#include<iostream> #include<cmath> using namespace std; int main() { int n,sum=0,j,i,k,lpl,a[100000],b[100000]; cin>>n; a[1]=1,b[1]=1; for(int i=2;i<=n;i++) { a[i]=(a[i-1]+1)%i+1; if(a[i]==i)b[i]=i; else b[i]=b[a[i]]; } cout<<b[n]+n; }
又是一道遞推 代碼如上;
試題描述:
你一定聽說過經典“約瑟夫”問題吧?現在來組織一個皆大歡喜的新游戲:假設 n 個人站成一圈,從第 1 人開始交替的去掉游戲者,但只是暫時去掉(例如,首先去掉 2),直到最后剩下唯一的幸存者為止。幸存者選出后,所有比幸存者號碼高的人每人將得到 1 塊錢,並且永久性地離開,其余剩下的人將重復以上過程,比幸存者號碼高的人每人將得到 1 塊錢后離開。一旦經過這樣的過程后,人數不再減少,最后剩下的那些人將得到 2 塊錢。請計算一下組織者一共要付出多少錢?
例如,第一輪有 5 人,幸存者是 3,所以 4、5 得到 1 塊錢后離開,下一輪幸存者仍然是 3,因此沒有人離開,所以每人得到 2 塊錢,總共要付出 2+2*3=8 塊錢。
輸入:
一行一個整數 n。
輸出:
一行一個整數,不超過65535,表示總共要付出多少錢。
輸入實例:
10
輸出實例:
13
首先,每個人都會得到1塊錢,只有最后的那些幸存者多得到了1塊錢。所以只要求出最后會幸存的人即可。
假設經過m次出圈操作后還剩final(m)個人,此時的人數已經不可以再減少了,則問題的解應該為final(m)+n.可是如何求final(m)呢?
當第i次的final(i)=i時,人數就不會再減少了,此時的i即為m,否則,就需要對剩下的final(i)個人再進行報數出圈操作;
會有兩種情況:1 設jose(i)為幸存者的編號,設報道K的人出去,則jose(i-1)可以理解為第一輪第一次報數,k出去后的狀態,k出去后會從k+1繼續報數,此時圈中有i-1個人,從k+1開始報數,編號jose(i)為:k+1,K+2......i,1,2.....,k-1;
2 可以人為地把這個圈逆時針轉k個單位,此時報數的編號jose(i-1):1,2.....,i-k,i-k+1,i-k+2....,i-1;
從上面兩種情況可以發現除了i和i-k以外,其他所有數據都滿足規律:jose(i)=(jose(i-1)+k)mod i。對這個式子稍微調整一下,變成的公式都滿足了:jose(i)=(jose(i-1)+1)mod i+1;
至此這個問題的遞推公式就出來了,邊界條件為jose(1)=1.然后,順推求出每個jose(i),直到某一次jose(i)=i,則final(i)=i,否則final(i)=final(jose(i)).
所以就是這樣了!!!
