N个人坐成一个圆环(编号为1 - N),从第1个人开始报数,数到 的人出列,后面的人重新从1开始报数。问最后剩下的人的编号。
例如:N = 3,M = 2。2号先出列,然后是1号,最后剩下的是3号。
考虑先将第一个人处决, 然后去掉得到下表格第二行,
从 开始重新编号, 得到下表格第三行, 设 长度为 的环最后出去的人的编号 .
… | … | ||||
---|---|---|---|---|---|
… | … | ||||
… | … |
推出递推式: .
直接计算 时间复杂度为 , 不能通过此题, 考虑加速转移过程,
注意到转移只受到 模数 的影响, 可以在 模数 这里 “动手脚”,
设当前状态为 , 则可以直接转移到 , 其中 .
这里是从 到 标号, 因此输出答案时要加 .
#include<bits/stdc++.h>
#define reg register
typedef long long ll;
const int maxn = 1e6 + 5;
int M;
ll N;
void Work(){
scanf("%lld%d", &N, &M);
ll cur = 0;
for(reg ll i = 2; i <= N; i ++){
if(cur + M >= i) cur += M, cur %= i;
else{
ll k = std::min(N-i+1, (i-cur)/M);
cur += k*M, i += k - 1;
}
}
printf("%lld
", cur+1);
}
int main(){
int T; scanf("%d", &T);
while(T --) Work();
return 0;
}