【luogu1052】 过河 [动态规划]
把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; }