2018.5.24(Wannafly挑战赛15 --C出队---约瑟夫环)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值