洛谷P1052 过河(NOIp2005)

DP

题目传送门

DP应该比较好想,主要是怎么压缩距离。

因为L有1e9,而s和t只有10,因此我们可以考虑在s和t上做文章。压缩距离需要保证不管怎么跳,最终状态都是等价的。

lcm=LCM(s,s+1,,t) ,则对于所有间隔>lcm的石子,把距离%lcm+lcm。因为不论怎么跳,总会跳到lcm这个点。而两个石子之间不会有石子,因此可以把lcm这块给省掉去。然后直接做DP就可以啦!

代码:

#include
#include
#include
#define MAXN 1000000
using namespace std;
int s,t,l,n,lcm;
int f[MAXN+5],a[MAXN+5],st[MAXN+5];
int gcd(int a,int b){
    if (!b) return a;
    return gcd(b,a%b);
}
int main(){
    scanf("%d%d%d%d",&l,&s,&t,&n);
    lcm=1;
    for (int i=s;i<=t;i++) lcm=lcm*i/gcd(lcm,i);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    int k=0;
    for (int i=1;i<=n;i++){
        int m=a[i]-a[i-1];//压缩距离
        if (m>lcm) m=m%lcm+lcm;
        st[k+m]=1; k+=m;
    }
    memset(f,0x3f,sizeof(f)); f[0]=0;
    for(int i=s;i<=k+t;i++){//DP
        for (int j=s;j<=t;j++)
            f[i]=min(f[i-j],f[i]);
        f[i]+=st[i];//st[i]表示这里是否有石头
    }
    int ans=1e8;
    for (int i=k;i<=k+t;i++)//因为有可能跳出,因此最后需要统计到k+t
        ans=min(ans,f[i]);
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(DP---一般DP,洛谷,蒟蒻zxl的Blog专栏)