本文共 3304 字,大约阅读时间需要 11 分钟。
题目描述
在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点: (其中 是桥的长度)。坐标为 的点表示桥的起点,坐标为 的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是 到 之间的任意正整数(包括 )。当青蛙跳到或跳过坐标为 的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度 ,青蛙跳跃的距离范围 ,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
输入输出格式
输入格式:
第一行有 个正整数 ,表示独木桥的长度。
第二行有 个正整数 ,分别表示青蛙一次跳跃的最小距离,最大距离及桥上石子的个数,其中 , 。
第三行有 个不同的正整数分别表示这 个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。
输出格式:
一个整数,表示青蛙过河最少需要踩到的石子数。
输入输出样例
输入样例#1:
102 3 52 3 5 6 7
输出样例#1:
2
说明
对于30%的数据, ;
对于全部的数据, 。
2005提高组第二题
思路
如果不考虑数据范围的话,可以很快得出递推关系式: ( 为 点的石头数 表示到达 点踩到的最少石头数)
然鹅看了数据范围后,时间和空间都是过不去的。所以需要选择别的方法:
当 的时候,可以很容易得到:所有在 倍数位置上的点,都会走到,所以对该种情况进行特判
我们可以发现石子在桥上放置的是非常稀疏的,而且当点的位置超过一定范围,点都是可以跳到的。所以可以将石子所在的位置压缩到这个范围里去。将压缩后位置储存起来作为新的石头的位置,按照这个位置进行dp即可
假设每次走 或者 步.我们知道 .
由扩展欧几里得可知,对于二元一次方程组: 是有整数解的,即可得: 是一定有整数解的。设 的解为: 。令 (通过增减 个 来实现), ,则有: 即表示,当 时, 有两个非负整数解,每次走 步或者 步, 之后的地方均能够到达。如果两个石子之间的距离大于 ,那么就可以直接将他们之间的距离更改为 。综上,得到压缩路径的方法:若两个石子之间的距离大于 ,则将他们的距离更改为 。因 ,因此我们可以直接将大于 的距离直接化为 .
关于路径压缩常数的选择,证明过程详见:
AC代码
/************************************************************************* > Author: WZY > School: HPU > Created Time: 2019-02-03 15:55:49 ************************************************************************/#include#define ll long long#define ull unsigned long long#define ms(a,b) memset(a,b,sizeof(a))#define INF 0x7f7f7f7fconst int maxn=1e6+10;const int mod=1e9+7;using namespace std;int a[maxn];int dp[maxn];int vis[maxn];int main(int argc, char const *argv[]){ ios::sync_with_stdio(false); cin.tie(0); int L; int ans=0; int s,t,m; cin>>L; cin>>s>>t>>m; for(int i=1;i<=m;i++) cin>>a[i]; if(s==t) { for(int i=1;i<=m;i++) { if(a[i]%s==0) ans++; } cout< < =0;i--) { dp[i]=INF; for(int j=s;j<=t;j++) dp[i]=min(dp[i],dp[i+j]+vis[i]); } cout< <
转载地址:https://www.cnblogs.com/Friends-A/p/11054978.html 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!