在河上有一座獨木橋,一隻青蛙想沿着獨木橋從河的一側跳到另外一側。在橋上有一些石子,青蛙很討厭踩在這些石子上。因爲橋的長度和青蛙一次跳過的距離都是正整數,咱們能夠把獨木橋上青蛙可能到達的點當作數軸上的一串整點:\(0,1,…,L\)(其中\(L\)是橋的長度)。座標爲\(0\)的點表示橋的起點,座標爲\(L\)的點表示橋的終點。青蛙從橋的起點開始,不停的向終點方向跳躍。一次跳躍的距離是\(S\)到\(T\)之間的任意正整數(包括\(S,T\))。當青蛙跳到或跳過座標爲\(L\)的點時,就算青蛙已經跳出了獨木橋。ios
題目給出獨木橋的長度\(L\),青蛙跳躍的距離範圍\(S,T\),橋上石子的位置。你的任務是肯定青蛙要想過河,最少須要踩到的石子數。git
輸入格式:優化
第一行有\(1\)個正整數\(L(1 \le L \le 10^9)\),表示獨木橋的長度。spa
第二行有\(3\)個正整數\(S,T,M\),分別表示青蛙一次跳躍的最小距離,最大距離及橋上石子的個數,其中\(1 \le S \le T \le 10\),\(1 \le M \le 100\)。code
第三行有\(M\)個不一樣的正整數分別表示這\(M\)個石子在數軸上的位置(數據保證橋的起點和終點處沒有石子)。全部相鄰的整數之間用一個空格隔開。get
輸出格式:string
一個整數,表示青蛙過河最少須要踩到的石子數。it
輸入樣例#1:io
10 2 3 5 2 3 5 6 7
輸出樣例#1:class
2
對於\(30\%\)的數據,\(L \le 10000\);
對於所有的數據,\(L \le 10^9\)。
思路:不加優化的話會重複計算好多的多餘的東西。因此咱們能夠把這樣一段段沒用的東西減掉,怎麼減呢,這就是狀壓的另外一種實現。由於\(s\)和\(t\)都小於等於\(10\),因此求得\(1-10\)的最小公倍數是\(2520\),而當兩個點相距\(2520\)時,減掉也不會有影響。這裏有幾種具體的實現方法,但好像只有我下面呈現的這種比較好寫。注意輸入數據不必定有序,因此要先打一個快排。
代碼:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define mod 2520 #define maxn 400001 using namespace std; inline int qread() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f; } int m,s,t,l,ans,a[101],sz[101],vis[maxn],f[maxn]; int main() { l=qread(),s=qread(),t=qread(),m=qread(); for(int i=1;i<=m;++i) a[i]=qread(); sort(a+1,a+1+m); for(int i=1;i<=m;++i) sz[i]=(a[i]-a[i-1])%2520; for(int i=1;i<=m;++i) { a[i]=a[i-1]+sz[i]; vis[a[i]]=1; } l=a[m]; ans=m; for(int i=0;i<=l+t;++i) f[i]=m; f[0]=0; 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]+=vis[i]; } } for(int i=l;i<l+t;++i) ans=min(ans,f[i]); cout<<ans<<'\n'; return 0; }