複習dp(迪皮)的時候刷到了一道簡單路徑壓縮的題目(一點不會qwq)數組
題目描述連接。spa
正解:code
首先呢,咱們看到題目,天然而然的會想到這種思路:blog
設狀態變量dp[i]表示從第一個格子開始通過一些跳躍跳到第i個格子上所踩到的最小石子數目。get
那麼,根據每一次跳s~t個格子,咱們能夠得出dp[i]能夠從dp[i-t]到dp[i-s]轉移過來,要綜合考慮的話呢,就要在全部以前的狀況中取一個石子數最小的在加上當前位置是否有石子數,就是dp[i]的值。string
因而呢,有了總體思路,咱們開始敲起了代碼。it
瀏覽數組範圍時發現了這樣一個東西:io
awslast
這空間時間都會炸吧。。。class
因而乎,咱們上述的簡單套路就被ban掉了。
開始思考:
咱們發如今這種數據下,石子間的間隔變得很是的大。
能不能壓縮一下那些多餘的路徑,可是卻對答案沒有影響呢?
首先,摘取洛谷題解中一位dalao的作法:
我直接沒看,被ex到了。
本身思考:
看了看數據範圍:
觀察dp式子dp[i]=max(dp[i-t]~dp[i-s])+flag[i];flag[i]表示第i個位置有沒有石子。
當一段區間不存在石子時,flag就無用了。
因而說白了,就是個統計最大值的過程一旦統計完dp[i]到dp[i-t]的最大值,其後面flag等於0的狀況直接就能夠跳過了。
不難想出,統計dp[i]到dp[i-t]這個區間的最大值一共須要lcm(s,t)次。
感性理解。。。
因而咱們得出了最短壓縮長度90.。?(90=9*10,10,10的狀況直接特判就好了)
那麼,把多餘90的距離都壓縮成90必定能保證結果不變。
上代碼:
#include<cstdio> #include<cstring> #include<algorithm> #define maxn 214748364 using namespace std; int read() { int ans=0; char ch=getchar(),last=' '; while(ch>'9'||ch<'0')last=ch,ch=getchar(); while(ch>='0'&&ch<='9')ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar(); return last=='-'?-ans:ans; } int min(int a,int b){return a<b?a:b;} inline bool cmp(int a,int b) {return a<b;} int l,s,t,m,sz[20003],ans,dis[20003],sum,flag[20001],dp[20001]; int main(){ l=read(); s=read(),t=read(),m=read(); if(s==t) { int bol; for(int i=1;i<=m;i++) { bol=read();ans+=((bol%s)==0); } printf("%d\n",ans);return 0; } for(int i=1;i<=m;i++) sz[i]=read(); sort(sz+1,sz+1+m,cmp); for(int i=1;i<=m;i++) dis[i]=min(sz[i]-sz[i-1],90);//dis[i]表示第i個石子到第i-1個石子的距離差 dis[m+1]=min(l-sz[m],100); for(int i=1;i<=m;i++) sum+=dis[i],flag[sum]=1; sum+=dis[m+1]; for(int i=1;i<=sum+9;i++) { dp[i]=maxn; for(int j=s;j<=t;j++) { if(i>=j)dp[i]=min(dp[i],dp[i-j]+flag[i]); } } int minn=maxn; for(int i=sum;i<=sum+9;i++) { minn=min(minn,dp[i]); } printf("%d",minn); return 0; }
完結/
也就是說,對於s=t=10的極端狀況,只要看100的倍數上有沒有石子統計一下就好了。
對於次大的狀況s=9,t=10,時,只要把s