您的位置:首页 > 其它

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

2015-12-01 20:56 459 查看


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=node[tr<<1|1]+node[tr<<1];
}
void build(int l,int r,int tr)
{
node=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;
}
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=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");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: