就是經典約瑟夫環問題的裸題
我一開始一直沒理解這個遞推是怎么來的,后來終於理解了
假設問題是從n個人編號分別為0...n-1,取第k個,
則第k個人編號為k-1的淘汰,剩下的編號為 0,1,2,3...k-2,k,k+1,k+2...
此時因為從剛剛淘汰那個人的下一個開始數起,因此重新編號
把k號設置為0,則
k 0
k+1 1
...
0 n-k
1 n-k+1
假設已經求得了n-1個人情況下的最終勝利者保存在f[n-1]中,則毫無疑問,該勝利者還原到原來的真正編號即為 (f[n-1]+k)%n (因為第二輪重新編號的時候,相當於把每個人的編號都減了k,因此重新+k即可恢復到原來編號)。由此,我們可以想象,當最終只剩下一個人的時候,該人即為勝利者,此時重新編號,因為只有一個人,所以此時f[1]=0
這樣f[2]=(f[1]+k)%2,這樣就可以求出最終勝利者在2個人的時候的情況下的編號,由遞推公式f[n]=(f[n-1]+k)%n,可遞推到最初編號序列中該勝利者的編號。
因此用這個方法,只需一遍On的掃描,即可求出最終答案
不過該題要求編號從1開始,只要把f[n]+1即可,同時,該題指定了第一個要刪除的人必須為編號為m的人,其實也不難,求出f[n]之后,把原本編號為0的位置移到跟m只相距k的位置即可實現第一次刪除的編號為m。所以最終 ans=(f[n]+1+m-k);
當然因為m-k可能為負數,導致整個ans為負,這樣其實最后+n即可解決。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int n,m,k; int main() { while (scanf("%d%d%d",&n,&k,&m)) { if (n+m+k==0) break; int s=0; for (int i=2;i<=n;i++) s=(s+k)%i; int ans; ans=(m-k+s+1)%n; if (ans<=0) ans+=n; printf("%d\n",ans); } return 0; }