https://www.nowcoder.com/acm/contest/112#question
C出队
https://www.nowcoder.com/acm/contest/112/C
这是关于“约瑟夫环”的系列问题
#include<iostream>
#include<cstdio>
using namespace std;
int main(int argc, char const *argv[])
{
long long n,q;
scanf("%lld%lld",&n,&q);//***不能用%I64d,会超时;***
while(q--)
{
long long x;
scanf("%lld",&x);
long long sum=n,ans=0,t;
while(!(x&1))//判断num的奇偶性用位运算表示;如果num为偶数,则num&1返回值为0,如果num为奇数,num&1返回值为1;
{
t=x>>1;
ans+=t;
x=sum-t;
sum-=t;
}
printf("%lld\n",ans+(x+1)/2);
}
return 0;
}
对于while()循环语句的理解:
假设n=6
1,2,3,4,5,6围成一圈,其编号为①②③④⑤⑥每次都是报1的出队;毋庸置疑,编号为奇数的出队,即第一轮后1,3,5已经出队,第二轮时,只剩下2,4,6三人,按照报数顺序,当5出队后,第一轮结束,下一轮的是从6开始报数的,第二轮的顺序为6,2,4,其编号更新为①②③,即6->①,2->②,4->③,同样,编号为奇数的出队,第二轮后6,4出队,到第三轮时,只剩下2,编号为①,同样,编号为奇数的出队,故经过三轮,这六个人全部出队;
本题的重点就是每经过一轮出队,都需更新一下第x个人的编号,如果是编号为奇数,则第x个人在此轮中出队,否则继续更新;
long long sum=n,ans=0,t;
while(!(x&1))//判断第x个人的编号是否为奇数,如果不是,循环继续进行,直到其为奇数为止;
{
t=x>>1;//t变量表示的是在x之前需要出队的人数;
ans+=t;//记录x之前出队的总人数;
x=sum-t;//跟新第x个人的编号
sum-=t;//更新总人数;
}
详细解释:
假设n=6,x=2;
1,2,3,4,5,6
第一轮出队,2的编号为②,偶数,满足循环条件,执行循环语句t=2/2;
第一轮中,2之前有一人出队,ans=1,更新队列为3,4,5,6,2;编号更新为
3->①,4->②,5->③,6->④,2->⑤,故第2人的编号更新为⑤,即x=sum-t语句,在准备第二轮出队前,判断一下第2人的编号是否为偶数,否,循环结束,输出ans+(x+1)/2;ans指的是第一轮出队中2人之前出队的总人数,(x+1)/2指的是在即将开始的第二轮出队中,第2人的编号为奇数,一定会在此轮中出队,在此轮中第2人出队的序号为(5+1)/2=3;
故第2人是第1+3=4个出队的;
关于(int argc, char const *argv[]),详情见大神博客
http://www.cnblogs.com/avril/archive/2010/03/22/1691477.html
https://blog.csdn.net/yang_chengfeng/article/details/49406443
有关约瑟夫环的问题,参考大神博客
http://www.cnblogs.com/daimingming/p/3242406.html
http://www.cnblogs.com/wuyoucao/p/4709293.html?ptvd
https://blog.csdn.net/eagleest/article/details/8091351
https://zhidao.baidu.com/question/120817085.html
视频
https://search.bilibili.com/all?keyword=%E7%BA%A6%E7%91%9F%E5%A4%AB%E7%8E%AF