caioj1522: [NOIP提高组2005]过河

状态压缩的经典题。

按照一般做法,DP一维时间O(n),显然跑不过。考虑到石子较少,实际上有很长一段是一定可以跳到的,设两个石头分别在i点和j点,跳跃的路程为S到T。那么从i点可以跳到i+S到i+T。从j-T到j-S可以跳到J。显然当i和j相隔非常非常远时,从i到i+T中必然可以经过若干次跳跃,然后跳到j-T到j的任意一段。

然后状压,可以发现距离大于90(假设s和t不同,s(9)和t(10)的最小公倍数)一定可以到达,这样我们把石头之间的距离%90节省时间。

然后特判一下s==t的情况,就可以AC。但有一个问题,我将mod变成100,不特判s==t的情况,这样会WA,这个我无法理解。

数据:10000
7 7 100
1111 1118 1114 1117 3010 7508 1119 1105 899 1112 9667 3238 1108 5178 4627 2116 2089 9184 1115 8887 3565 3560 3559 3562 2410 3564 3571 565 3561 3566 3573 7432 9485 4484 7258 4555 8812 1291 3567 3221 5252 5253 5244 797 5251 7885 5245 9340 5255 6537 7737 5243 9316 5246 6694 6773 5247 6031 5256 5249 5484 5482 7513 5485 5479 5481 5480 5489 381 2572 9255 7624 5821 8606 7829 5488 442 5490 5492 8098 483 482 481 478 469 474 4054 472 471 4407 479 7006 475 470 3147 6933 9097 7781 473 2221
应该输出10但是改了输出13.

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int se[110],a[1100000],f[1100000];
int main()
{
    int L,s,t,n;
    scanf("%d%d%d%d",&L,&s,&t,&n);
    for(int i=1;i<=n;i++)scanf("%d",&se[i]);
    sort(se+1,se+n+1);
    if(s==t)
    {
        int ans=0;
        for(int i=1;i<=n;i++)
            if(se[i]%s==0)ans++;
        printf("%d
",ans);
        return 0;
    }
    for(int i=1;i<=n;i++)se[i]=se[i-1]+(se[i]-se[i-1])%90;
    L=(L-se[n])%90+se[n];
    for(int i=1;i<=n;i++)a[se[i]]=1;
    
    memset(f,63,sizeof(f));f[0]=0;
    for(int i=s;i<=L+t;i++)
        for(int j=s;j<=t;j++)
            if(i>=j)
                f[i]=min(f[i],f[i-j]+a[i]);
                
    int ans=999999999;
    for(int i=L;i<L+t;i++)ans=min(ans,f[i]);
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/AKCqhzdy/p/7616899.html