NEUQOJ 题目1496 田鼠看热闹(Ⅱ)(线段树,约瑟夫)

本文探讨了一种名为‘幸运小子’的游戏,游戏中玩家通过顺时针数数的方式淘汰,最终留下一名胜者。通过输入玩家数量n和数数次数m,我们能计算出最终胜者的初始位置及出局顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1496: 田鼠看热闹(Ⅱ)

时间限制: 2 Sec   内存限制: 128 MB
提交: 58   解决: 7
[ 提交][ 状态][ 讨论版]

题目描述

田鼠在集市中继续游荡着,突然又被人群吸引住了,他挤进人群中一看,原来他们在玩一个叫做“幸运小子”的游戏,游戏初始如下

1. 游戏有n个玩家,编号从1-n,并且这n个玩家围成一个环形

2. 由主持人随机说一个数字m

3. 每次从玩家1顺时针开始数m个数(包括玩家1),数到第m个人的编号是k,则k玩家出局,由此时在玩家k下一位的玩家继续开始下一轮游戏,直到剩下一个人为止,则这个人可以拿走奖品

田鼠一看,我去,这不就是约瑟夫问题么?赶紧找到正确的位置加入,开心的拿到了奖品,,可是这时候主持人大喊:“桥豆麻袋!(稍等一下)这位先生,你要拿走奖品还需要回答一个问题!”田鼠心虚了:“什么问题!?”主持人说:“请问,刚才的出局顺序是什么!”田鼠懵逼了,只好请你来救救他。

输入

多组数据输入,每一组输入数据包含两个数字 n(1<=n<=10^6)m(1<=m<=10^9)

输出

对于每组输入,先输出一个正整数,表示田鼠一开始加入的编号,并且这个编号是最后的存留编号,之后换行,然后输出n-1个数,顺序输出出队的玩家的编号,两个数之间用空格隔开,具体看样例。

样例输入

7 3

样例输出

4
3 6 2 7 5 1

提示


n=7,m=3的时候,游戏从玩家1开始,出局顺序为  3->6->2->7->5->1  最后编号4胜利,这也是田鼠初始站的位置

来源

ac代码

#include<stdio.h>
#include<string.h>
int node[1000010<<2];
int ans=0;
void pushup(int tr)
{
    node[tr]=node[tr<<1|1]+node[tr<<1];
}
void build(int l,int r,int tr)
{
    node[tr]=r-l+1;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(l,mid,tr<<1);
    build(mid+1,r,tr<<1|1);
}
int getsum(int L,int R,int l,int r,int tr)
{
    if(L<=l&&R>=r)
    {
        return node[tr];
    }
    int mid=(l+r)>>1;
    int ans=0;
    if(L<=mid)
        ans+=getsum(L,R,l,mid,tr<<1);
    if(R>mid)
        ans+=getsum(L,R,mid+1,r,tr<<1|1);
    return ans;
}
void remove(int pos,int l,int r,int tr)
{
    if(l==r)
    {
        node[tr]=0;
        ans=l;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=node[tr<<1])
        remove(pos,l,mid,tr<<1);
    else
        remove(pos-node[tr<<1],mid+1,r,tr<<1|1);
    pushup(tr);
}
int res[1000100];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int i,j,k=0;
        ans=0;
        build(1,n,1);
        for(i=0;i<n;i++)
        {
            if(ans==0)
                k=m%node[1];
            else
            {
                int ssum=getsum(1,ans,1,n,1);
                k=(ssum+m)%node[1];
            }
            if(k==0)
                k=node[1];
            remove(k,1,n,1);
            res[i]=ans;
        }
        printf("%d\n",res[n-1]);
        for(i=0;i<n-1;i++)
        {
            if(i)
                printf(" %d",res[i]);
            else
                printf("%d",res[i]);
        }
        printf("\n");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值