如果(L)小一点的话方程就很显然了,是(f[i]=min_{j=S}^{j<=T}{f[i-j]+stone[j]})
然后(L)非常的大,所以我们就可以把两个石子中间的部分可以缩了。
如NOIP2017D1T1一样,发现石子后T×(T-1)个才有用。
所以就可以写了。
代码如下
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=20005;
int f[N],dis[N],L,S,T,M,a[N],ans,sum;
bool stone[N];
int main() {
cin>>L>>S>>T>>M;
if(S==T) {for(int i=1;i<=M;i++) scanf("%d",&a[i]),ans+=(a[i]%S)==0;cout<<ans<<endl;return 0;}
for(int i=1;i<=M;i++) scanf("%d",&a[i]);
sort(a+1,a+1+M);
for(int i=1;i<=M;i++) dis[i]=min(a[i]-a[i-1],T*(T-1)),sum+=dis[i],stone[sum]=1;
dis[M+1]=min(L-a[M],T*(T-1));sum+=dis[M+1];
stone[dis[M+1]]=1;
memset(f,0x3f,sizeof f);
f[0]=0;
ans=0x3f3f3f3f;
for(int i=1;i<=sum+T;i++)
for(int j=S;j<=T;j++) if(i>=j)f[i]=min(f[i],f[i-j]+stone[i]);
for(int i=sum;i<=sum+T;i++) ans=min(ans,f[i]);
cout<<ans<<endl;
return 0;
}