嘟嘟噜 解题报告

嘟嘟噜

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

原文地址:https://www.cnblogs.com/butterflydew/p/9816337.html