題目
爲了銘記歷史,國王準備在閱兵的間隙玩約瑟夫遊戲。它召來了 n(1\le n\le 5000)n(1≤n≤5000) 個士兵,逆時針圍成一個圈,依次標號 1, 2, 3 … n1,2,3…n。
第一輪第一個人從 11 開始報數,報到 11 就停止且報到 11 的這個人出局。
第二輪從上一輪出局的人的下一個人開始從 11 報數,報到 22 就停止且報到 22 的這個人出局。
第三輪從上一輪出局的人的下一個人開始從 11 報數,報到 33 就停止且報到 33 的這個人出局。
第 n - 1n−1 輪從上一輪出局的人的下一個人開始從 11 報數,報到 n - 1n−1 就停止且報到 n - 1n−1 的這個人出局。
最後剩餘的人是倖存者,請問這個人的標號是多少?
思路
設dp[i][j] 爲i個人 第一個人從j開始報號 的結果。
那麼dp[i][j] = (dp[i - 1][j + 1] + j) % i
因爲在dp[i][j] 下先刪除一個人第j個, 然後接着要刪除第(j+1)個所以是dp[i - 1][j + 1]. 而且本來開始的位置是0 現在變成了j所以要 +j.
代碼
#include <iostream>
#include <cstring>
#include <stdio.h>
using namespace std;
int T;
const int MAXN = 5010;
long long dp[MAXN];
int main() {
scanf("%d",&T);
for(int j = 5000;j >= 1;j --) {
for(int i = 5000;i >= 1;i --) {
dp[i] = (dp[i - 1] + j) % i; //使用類揹包手法優化
}
}
while (T --) {
int n;
scanf("%d",&n);
printf("%I64d\n",dp[n] + 1);
}
}