Toys——约瑟夫环问题

Lark收藏了很多玩具。尽管她有很多玩具,但她每次只喜欢玩一个。她决定玩哪个玩具,把所有玩具放在她周围的一个圆圈里,编号为 0 到 T-1 。然后,她顺时针旋转,去除第K个玩具,直到剩下一个为止。这意味着她拿走的第一个玩具是有编号的K−1。如果在这个仪式中移动了任何玩具,Lark就会开始哭泣,然后按照原来的顺序重新排列玩具。
今天,Lark想让她的爸爸和她一起玩玩具。在Lark挑选的玩具中,她的父亲当然有一个最喜欢的玩具,当然也希望能选择那个特定的玩具。他应该把他最喜欢的玩具放在哪个位置,以确保这就是他们最终玩的玩具?

Input
输入是由2个整数组成 T和K,表示Lark拥有的玩具数量和在选择下一个要丢弃的玩具时跳跃长度。

Output
输出一个整数,父亲需要放置他最喜欢的玩具的位置,以供选择。Lark将在位置0 开始计数。

【数据范围】
1≤T≤10000000 ,1≤K≤1000000,K≤T

输入样例1:
5 2
输出样例1:
2

输入样例2:
25 18
输出样例2:
1


解析:

我们采用倒推,我们倒推出:最后剩下的这个数字,在最开始的数组中的位置。

剩下最后一个数字(简称“它”)的时候,总个数为 1,它的下标 pos=0。
那么它在上一轮也是安全的,总个数为 2,它的下标 pos=(0+m)%2; (解释:在上一轮中,它前面的数字(即下标为 m-1 的数字)被删走了;因此它的下标是 m;由于是环,因此需要 %2)
那么它在上上轮也是安全的,总个数为 3,它的下标 pos=(((0+m)%2)+m)%3;
那么它在上上上轮也是安全的,总个数为 4,它的下标 pos=((((0+m)%2)+m)%3+m)%4;
...
那么它在游戏开始的第一轮也是安全的,总个数为 n,它的下标就是最优位置,即父亲需要放置他最喜欢的玩具的位置。

也就是说如果从下向上反推的时候:假如它下一轮的下标为 pos,那么当前轮次的下标就是: (pos+m) 当前轮次的人数。


一、暴力(超时)

#include 
using namespace std;
#define int long long 
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef pair PII;
const int N=1e7+10;
int n,m;
bool p[N];
signed main()
{
    ios;
    cin>>n>>m;
    int cnt=n;
    int k=-1,falg=0;
    while (1)
    {
        k++;
        if (!p[k%n]) falg++;
        if (falg==m)
        {
            cnt--;
            p[k%n]=1;
            if (!cnt)
            {
                if (k%n) cout<

二、递归

#include 
using namespace std;
#define int long long 
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef pair PII;
const int N=1e7+10;
int find(int n,int k)
{
    if (n<=1)
    {
        return 0;
    }
    return (find(n-1,k)+k)%n;
}
int n,k;
signed main()
{
    ios;
    cin>>n>>k;
    cout<

三、递推(根据二)

#include 
using namespace std;
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define int long long
typedef pair PII;
const int N=1e7+10;
int find(int n,int k)
{
    int ans=0;
    for (int i=2;i<=n;i++) ans=(ans+k)%i;
    return ans;
}
int n,k;
signed main()
{
    ios;
    cin>>n>>k;
    cout<

你可能感兴趣的:(算法)