【luogu1052】 过河 [动态规划]

P1052 过河

把ppt上的内容搬上来QAQ

容易想到如下DP方法
  • f[x]表示跳到坐标x的位置上最少需要踩到的石子个数
  • f[x] = min( f[x-j] + stone[x] ), s <= j <= t
  • 但是,x高达10^9,难以计算
  • 但也容易发现,最多100个石子,所以很多时候两个石子距离隔得很远,这时后一石子坐标前的若干个连续的点都可达。
稍微证明一下:
当 s != t 时,存在 p 使得 s <= p < p+1 <= t 显然有 gcd(p, p+1) = 1
当Q >= p*(p-1)时,p*x + (p+1)*y = Q 一定有非负整数解 也即,当Q足够大时,可以仅通过走若干个p步和p+1步,从而走长度恰好为Q的距离
证明:当Q=p(p-1),令x=p-1,y=0;Q增加1,则x--,y++;x减到0后,y=p-1,此时Q=p^2-1,接着Q继续增加则令x=p,y=0;以此类推。
 
然后就不清楚离散除的那个数为什么是这么多QAQ
#include<bits/stdc++.h>
using namespace std;
#define Max(x,y) (x)>(y)?(x):(y)
#define Min(x,y) (x)>(y)?(y):(x)
#define ll long long
#define rg register
const int N=200+5,M=1e7+5,inf=0x3f3f3f3f,P=99999997;
int l,s,t,n,ans=inf,a[N],d[N],sto[M],f[M];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int main(){
//    freopen("in.txt","r",stdin);
    rd(l),rd(s),rd(t),rd(n);
    for(int i=1;i<=n;++i) rd(a[i]);
    sort(a+1,a+n+1);a[0]=0,a[n+1]=l;
    for(int i=1;i<=n;++i) d[i]=(a[i]-a[i-1])%3000;
    for(int i=1;i<=n;++i) a[i]=a[i-1]+d[i],sto[a[i]]=1;
    memset(f,inf,sizeof(f));
    f[0]=0,l=a[n];
    for(int i=1;i<=l+t;++i){
        for(int j=s;j<=t;++j)
            if(i-j>=0) f[i]=Min(f[i],f[i-j]);
        f[i]+=sto[i];
    }
//    for(int i=l;i<=l+t;++i) printf("%d ",f[i]);
    for(int i=l;i<l+t;++i) ans=Min(ans,f[i]);
    printf("%d",ans);
    return 0;
}
 
原文地址:https://www.cnblogs.com/lxyyyy/p/11234389.html