嘟嘟噜 解题报告

嘟嘟噜

Description

由于众所周知的原因, 冈部一直欠真由理一串香蕉.
为了封上真由理的嘴, 冈部承诺只要真由理回答出这个问题, 就给她买一车的香蕉:
一开始有 \(n\) 个人围成一个圈, 从 \(1\) 开始顺时针报数, 报出 \(m\) 的人被机关处决. 然后下一
个人再从 \(1\) 开始报数, 直到只剩下一个人.
红莉栖: “这不就是约瑟夫问题吗...”
伦太郎: “助手你给我闭嘴!”
真由理虽然已经晕头转向了, 但听到有一车的香蕉, 两眼便放出了光芒.
“那个呢, 真由氏很想要一车子的香蕉呢. 如果可以帮帮我的话, 我可以把一些香蕉分给你哟, 诶
嘿嘿. 拜托你啦.”

Input Format

第一行一个整数 \(T\) , 表示数据组数.
接下来 \(T\) 行, 每行两个整数 \(n\) ,\(m\).

Output Format

对于每组数据, 输出一行一个整数, 表示幸存者的编号

Constraints

测试点编号nm
\(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\{\begin{aligned} 0 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \,i=1 \\ (f_{i-1}+m)\%i \ \ \ \ \ \ \ \ \ \ \,i<m \\ \frac{m \times (f_{i'}-i\%m)\% i'}{m-1} \ i\ge m\end{aligned}\right.\]

\[i'=i-\lfloor\frac{i}{m} \rfloor\]

解释一下,首先编号是从\(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\n",dfs(n)+1);
    }
    return 0;
}

2018.10.19

转载于:https://www.cnblogs.com/butterflydew/p/9816337.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值