• 洛谷 P5657 【格雷码】



    思路 :此题是由一个序列通过n次转换得来的,因此我们可以把这个序列还原回去,在还原的过程中得到问题的解。

    做法 :设第一个格雷码的编号是0,第2个是1……题目中所求的是编号为m(题目中的k)的n位格雷码,通过观察发现这个格雷码序列的前半段的首位都是0,而后半段都是1。所以我们可以通过判断当前m是在前半段还是在后半段来判断出n位编号为m的格雷码的首位是什么,同时我们也可以找出这个格雷码是属于哪个区间了。确定当前区间后,我们可以继续通过以下方法继续确定他所在的区间以及当前这个n位格雷码的编号为m的第i个数是多少,直到把这整个区间缩成一个数为止(用二分来实现)。但是我们需要注意,当确定当前区间后想要找下一位时,其中的顺序不一定是首位为0的在前,首位为1的在后(将上一次确定的区间里所有数的首位都去掉后),但我们依然可以发现一个规律,就是当当前的m在前半段时,下一位所确定的区间一定是0在前,1在后;反之则一定是1在前,0在后。注意如果此时的m在后半段,那么m要减去区间的一半

    观察样例 :

    2 3

     我们得到2位格雷码有四个 :

    00 01 11 10

    然后我们找编号为3的格雷码在后半段(编号从0开始的),因此确定第一位为1,输出1,将m - 序列的长度 / 2(因为数据太大,所以代码中是将长度一开始设定为2的n - 1次方了,然后减的直接就是序列的长度,但是意义上和 - 长度 / 2相等),此时的m为1;因为刚刚m在后半段,所以顺序为先1再0,因为此时的m在后半段,所以输出0

    代码

     1 #include <bits/stdc++.h>
     2 #define INF 0x3f3f3f3f
     3 #define int unsigned long long//unsigned long long了解一下 
     4 using namespace std;
     5 int n, m, l, f;
     6 signed main()
     7 {
     8     scanf("%llu %llu", &n, &m);
     9     l = pow(2, n - 1);//长度(数据原因,直接先/2了,所以只是2的n - 1次方)
    10     for(register int i = 0; l;)//i = 0代表0在前,1在后; 反之则为1。初始时是0在前1在后 
    11     {
    12         f = (m < l ? 0 : 1);//判断m在前半段还是后半段,前半段为0,反之为1(此时的l已经除过2了) 
    13         if(f)//后半段 
    14         {
    15             printf(i == 0 ? "1" : "0");//输出 
    16             i = 1;//改变 
    17             m -= l;//别忘了减 
    18         }
    19         else//前半段 
    20         {
    21             printf(i == 0 ? "0" : "1");//输出 
    22             i = 0;//改变 
    23         }
    24         l >>= 1;//二分 
    25     }
    26     return 0;
    27 }
  • 相关阅读:
    洛谷 P2048 [NOI2010]超级钢琴(优先队列,RMQ)
    洛谷P1074 靶形数独(跳舞链)
    洛谷P1337 [JSOI2004]平衡点 / 吊打XXX(模拟退火)
    洛谷P4003 无限之环(费用流)
    洛谷P3264 [JLOI2015]管道连接(斯坦纳树)
    洛谷P3190 [HNOI2007]神奇游乐园(插头dp)
    洛谷P3272 [SCOI2011]地板(插头dp)
    常用的端口配置
    Win7+Eclipse+Hadoop2.6.4开发环境搭建
    Windows10+eclipse+hadoop2.7.1环境配置+wordcount-折腾笔记
  • 原文地址:https://www.cnblogs.com/qqq1112/p/11964341.html
Copyright © 2020-2023  润新知