Vijos P1002 过河 (NOIP增高组2005)

Vijos P1002 过河 (NOIP提高组2005)

链接:https://www.vijos.org/p/1002


解析

  若 p*x+(p+1)*y=Q(采用跳跃距离p和p+1时可以跳至任何位置Q),则在Q ≥ P*(P-1)时是一定有解的。
由于题目给出的一个区间是1≤S≤T≤10,于是当相邻的两个石子之间的距离不小于8*9=72时,则后面的距离都可以到达,我们就可以认为它们之间的距离就是72。如此一来,我们就将原题L的范围缩小为了100*72=7200,动态规划算法完全可以承受了。

但是当S=T时,上述等式是无法使用的,在这种情况下,只需要在所有石子中,统计出坐标是S倍数的石子个数就可以了。


注意

1.运用DP的时候,需要压缩

2.特殊解答S==T的时候


代码

#include <istream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define MIN(x,y) (x<y?x:y)
#define INF 1e7

int dp[100010];
int dd[100010];
int dis[105];

int main(){
    int L,S,T,M;
    int i,j;

    scanf("%d%d%d%d", &L,&S,&T,&M);
    for(i=1; i<=M; ++i)
        scanf("%d", &dis[i]);

    int ans = 0;
    if(S==T){
        for(i=1; i<M; ++i)
            if(dis[i]%S == 0)
                ++ans;
    }
    else{
        dis[0] = 0;
        sort(dis, dis+M+1);
        memset(dd, 0, sizeof(dd));

        for(i=1,j=0; i<=M; ++i){
            if((dis[i] - dis[i-1])>100)
                j += 100;
            else
                j += dis[i]-dis[i-1];
            dd[j] = 1;
        }

        int k = j+100;
        dd[0] = 0;
        for(i=1; i<=k; ++i){
            dp[i] = INF;
            for(j=S; j<=T; ++j){
                if(i<j) break;
                dp[i] = min(dp[i] , dp[i-j]+dd[i]);
            }
        }

        ans = dp[k];
    }
    printf("%d\n", ans);
    return 0;
}