嘟嘟噜
Description
由于众所周知的原因, 冈部一直欠真由理一串香蕉.
为了封上真由理的嘴, 冈部承诺只要真由理回答出这个问题, 就给她买一车的香蕉:
一开始有 (n) 个人围成一个圈, 从 (1) 开始顺时针报数, 报出 (m) 的人被机关处决. 然后下一
个人再从 (1) 开始报数, 直到只剩下一个人.
红莉栖: “这不就是约瑟夫问题吗...”
伦太郎: “助手你给我闭嘴!”
真由理虽然已经晕头转向了, 但听到有一车的香蕉, 两眼便放出了光芒.
“那个呢, 真由氏很想要一车子的香蕉呢. 如果可以帮帮我的话, 我可以把一些香蕉分给你哟, 诶
嘿嘿. 拜托你啦.”
Input Format
第一行一个整数 (T) , 表示数据组数.
接下来 (T) 行, 每行两个整数 (n) ,(m).
Output Format
对于每组数据, 输出一行一个整数, 表示幸存者的编号
Constraints
测试点编号 | n | m |
---|---|---|
(1) | (le 10^5) | (le 10^5) |
(2) | (le 10^6) | (le 10^5) |
(3) | (le 10^9) | (le 2) |
(4) | (le 10^9) | (le 2) |
(5) | (le 10^9) | (le 3) |
(6) | (le 10^9) | (le 3) |
(7) | (le 10^9) | (le 10^3) |
(8) | (le 10^9) | (le 10^4) |
(9) | (le 10^9) | (le 10^5) |
(10) | (le 10^9) | (le 10^5) |
对于(100\%)的数据,(1 le T le 20),(1 le n le 10^9),(1 le m le 10^5)
Solution
其实就是约瑟夫问题,有个数学结论,考试的时候wjyyy神仙打表打出来了,我(20pts)的平衡树暴力都打挂了。
结论:令(f_i)代表有(i)个人从头开始删最后一个人的编号,则有
[f_i=left{egin{aligned} 0 \,i=1 \ (f_{i-1}+m)\%i \,i<m \ frac{m imes (f_{i'}-i\%m)\% i'}{m-1} ige mend{aligned}
ight.
]
[i'=i-lfloorfrac{i}{m}
floor
]
解释一下,首先编号是从(0)开始的,我们每次删完一个数后,为了保证下次还是从头开始删,我们把删完后面的那个位置重新编号为(0),然后求解子问题。函数退回来就只要映射好编号就可以了,按照自己的理解就可以了。
Code:
#include <cstdio>
int n,m,T;
int dfs(int i)
{
int nt=i-i/m;
if(i>=m) return 1ll*((dfs(nt)-i%m)%nt+nt)%nt*m/(m-1);
return i==1?0:(dfs(i-1)+m)%i;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
printf("%d
",dfs(n)+1);
}
return 0;
}
2018.10.19