[題解]luogu_P1052 過河

來源:題解


 

不發題面

因為 l 範圍太大,而石子數卻很少,步數也僅僅在1~10之間,

也就是說兩個石子之間很有可能間隔很大的距離,不管怎麼跳都能跳過去,那麼中間那些怎麼樣都能跳過去的區間和沒有等價,

所以讀入后就更新一遍pos和vis數組,範圍就可以縮到比較小,

至於具體多大的區間可以刪掉,可以取1~10的最小公倍數2520,(小凱的疑惑)71,(t * t-1)90,甚至可以 %t 再 +t,好像都可以

大概是一個離散化的方法吧

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int l,s,t,m,ans;
int p[101],d[101],v[300001];
int f[300001];
int main()
{
    scanf("%d%d%d%d",&l,&s,&t,&m);
    for(int i=1;i<=m;i++){
        scanf("%d",&p[i]);
    }
    if(s==t){
        for(int i=1;i<=m;i++)if(p[i]%t==0)ans++;
        printf("%d",ans);return 0;
    }
    sort(p+1,p+1+m);
    for(int i=1;i<=m;i++){
        d[i]=(p[i]-p[i-1])%2520;//只要兩個石子之間超過1~10的lcm,這一段就相當於沒有,怎麼樣都可以跳過去 
    }
    for(int i=1;i<=m;i++){//更新p[i]和v[i] 
        p[i]=p[i-1]+d[i];
        v[p[i]]=1;
    }
    int l=p[m];
    memset(f,0x3f,sizeof(f));
    f[0]=0;
    for(int i=1;i<=l+t;i++)//這裡l+t是因為有可能跳過,預留出跳過頭的範圍,在在區間內找最小值 
    for(int j=s;j<=t;j++){
        if(i-j>=0)
        f[i]=min(f[i],f[i-j]+v[i]);
    }
    int ans=m;
    for(int i=l;i<l+t;i++)ans=min(ans,f[i]);
    printf("%d",ans);
}

 

posted @ 2019-03-15 21:14  羊肉汤泡煎饼  阅读(126)  评论(0编辑  收藏  举报