[LUOGU] 1052 过河

如果\(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;
}
posted @ 2018-10-22 10:57  SWHsz  阅读(106)  评论(0编辑  收藏  举报