在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整 数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点: 0 , 1 ,……, L (其中 L 是桥的长度)。坐标为 0 的点表示桥的起点,坐标为 L 的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是 S 到 T 之间的任意正整数(包括 S,T )。当青蛙跳到或跳过坐标为 L 的点时,就算青蛙已经跳出了独木桥。题目给出独木桥的长度 L ,青蛙跳跃的距离范围 S,T ,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。输入文件的第一行有一个正整数 L ( 1 <= L <= 10^9 ),表示独木桥的长度。第二行有三个正整数 S , T , M ,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中 1 <= S <= T <= 10 , 1 <= M <= 100 。第三行有 M 个不同的正整数分别表示这 M 个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。输出文件只包括一个整数,表示青蛙过河最少需要踩到的石子数。
【输入样例】 【输出样例】 对于30%的数据,L <= 10000;
10 2 对于全部的数据,L <= 10^9。
2 3 5
2 3 5 6 7
30分解(基础DP):
通过对题目的观察我们可以很快发现可以使用动态规划来解决这道题目,我们把每一个桥上的点踩过石子的次数视作前s至t个点踩过石子的次数,若这一个点上有石子则将这个值+1,选择这个点最少的石子次数,最终根据题意输出数轴上第l至l+t个点上最少的石子次数。
ans[i]=min(ans[i],ans[j]) i-t<=j<=i-s 第i个点没有石子 边界:ans[0]=0
ans[i]=min(ans[i],ans[j]+1) i-t<=j<=i-s 第i个点有石子
50分解(特殊数据):
在刚刚不优化DP的情况下我们可以发现一种特殊情况,即s=t,在这种情况下,我们只能选且必选数轴上为s倍数的点,因此只需要计算所有为s倍数点上石子数的和就能够直接得到答案。(注:在下一种做法中该特殊数据需要特判)
正解:状压DP
根据前面的基本动态规划,我们可以直接看出O(L)的令人绝望的时间复杂度和a[L]的巨大数组,于是我们需要对其进行比较大的优化。
回想一下刚开始的样例,我们可以发现,在第2个点之后每一个点都必定可以到达,所以我们可以尝试将中间部分大量的没有石子的空白区域跳过节省时间和空间消耗。
首先我们将s和t的关系分为三种情况:
①:t-s=1
在这种情况下,我们可以比较快速的得到在第t*s-t-s个是最后一个不可拼出的数,即第t*s-t-s+1及以后的点均必可跳到,我们可以选择将这一段到下一个石子处压缩为一步来减少时间消耗。
②:t-s>1
这种情况是一定会优于情况①的,因为我们完全可以仅取第s和s+1个跳跃点,所以这种情况可以省略。
③:s=t
当s=t时很明显是不可能取到s+1的,但由于这种情况易于解决所以只需要加个特判即可。
数学证明:
px+(p+1)y=gcd(p,p+1)是有整数解的,即可得:px+(p+1)y=s是一定有整数解的。
设px+(p+1)y=s的解为:x=x0+(p+1)t,y=y0−pt。令0<=x<=p(通过增减t个p+1来实现),s>p∗(p+1)−1,
则有:y=s−pxp+1>=s−p2p+1>p∗(p+1)−1−pxp+1>=0
即表示,当s>=p∗(p+1)时,px+(p+1)y=s有两个非负整数解,每次走p步或者p+1步,p∗(p+1)之后的地方均能够到达。
如果两个石子之间的距离大于p∗(p+1),那么就可以直接将他们之间的距离更改为p∗(p+1)。
综上,得到压缩路径的方法:若两个石子之间的距离>t∗(t−1),则将他们的距离更改为t∗(t−1)。
因为t<=10,因此我们可以直接将大于10*9的距离直接化为90.