分析:其实很容易想到的就是设f[i]表示跳到坐标为i的位置时所踩到的最少石子数,那么显然有
f[i]=min(f[i-T~i-S])+vis[i],其中vis[i]标记坐标为i的位置是否有石子,但是当我们读完数据范围后发现这样是不行的,因为数据范围是1e9,显然会超时,但是发现石子数量不是很多,所以这个时候我们就需要从石子之间的距离这个角度来对本道题目来进行优化了。
假设我们每次可以走s~t步,如果s==t,那么我们只有一种走的方式,那么这样答案就很容易求出来,现在我们来分析一下s!=t的情况,那么我们每步可以走s步也可以走s+1,步,那么对于任意的w>=(s+1)*s,我们都可以通过每次走s或s+1步来到达,这个是由裴蜀定理推论得到的。
先来说一下裴蜀定理:对于任意的x和y都能够找到a和b使得a*x+b*y=gcd(x,y)成立
那么一定有k*a*x+k*b*y=k*gcd(x,y)成立
由于s和s+1互质(任意相邻两个数均互质),一定有a*s+b*(s+1)=w(w>=s*(s+1))成立,现在的问题就是我们能不能找到正整数解满足这个等式我们假设0<=a<=s,那么b=(w-a*s)/(s+1)>=0,所以一定存在正整数a和b满足上面方程,那也就是说任意大于s*(s+1)的数均可以由s和s+1来得到,那么当两个石子之间的距离大于s*(s+1)时,我们就可以把他们之间的距离变为s*(s+1),这样就可以按照一开始分析的思路来解决这道题目了。需要注意的就是当s等于t时我们无法走s+1步,这一种情况需要特判。
下面是代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=1e7+10;
int f[N],a[N],b[N];
bool vis[N];
int main()
{
int L;
cin>>L;
int s,t,m;
cin>>s>>t>>m;
for(int i=1;i<=m;i++)
scanf("%d",&a[i]);
sort(a+1,a+m+1);
if(s==t)//特判s=t的情况
{
int cnt=0;
for(int i=1;i<=m;i++)
if(a[i]%s==0) cnt++;
printf("%d",cnt);
return 0;
}
for(int i=1;i<=m;i++)
{
if(a[i]-a[i-1]>s*(s+1)) b[i]=b[i-1]+s*(s+1);
else b[i]=b[i-1]+a[i]-a[i-1];
vis[b[i]]=true;
}
memset(f,0x3f,sizeof f);
f[0]=0;
int ans=0x3f3f3f3f;
L=b[m]+10;//最后一步跳的距离不肯能超过10
for(int i=s;i<=L;i++)
for(int j=s;j<=min(t,i);j++)
f[i]=min(f[i],f[i-j]+vis[i]);
for(int i=b[m];i<=L;i++)
ans=min(ans,f[i]);
printf("%d",ans);
return 0;
}