• NOIP2019 格雷码 [提高组]


    题目:格雷码

    网址:https://www.luogu.com.cn/problem/P5657

    通常,人们习惯将所有(n)位二进制串按照字典序排列,例如所有(2)位二进制串按字典序从小到大排列为:(00,01,10,11)

    格雷码(Gray Code)是一种特殊的(n)位二进制串排列法,它要求相邻的两个二进制串间恰好有一位不同,特别地,第一个串与最后一个串也算作相邻。

    所有(2)位二进制串按格雷码排列的一个例子为:(00,01,11,10)

    (n)位格雷码不止一种,下面给出其中一种格雷码的生成算法:

    1. (1)位格雷码由两个(1)位二进制串组成,顺序为:(0,1)

    2. (n+1)位格雷码的前(2^n)个二进制串,可以由依此算法生成的(n)位格雷码(总共(2^n)(n)位二进制串)按顺序排列,再在每个串前加一个前缀(0)构成。

    3. (n+1) 位格雷码的后(2^n)个二进制串,可以由依此算法生成的(n)位格雷码(总共(2^n)(n)位二进制串)按逆序排列,再在每个串前加一个前缀(1)构成。

    综上,(n+1)位格雷码,由(n)位格雷码的(2^n)个二进制串按顺序排列再加前缀(0),和按逆序排列再加前缀(1)构成,共(2^{n+1})个二进制串。另外,对于(n)位格雷码中的(2^n)个二进制串,我们按上述算法得到的排列顺序将它们从(0∼2^n−1)编号。

    按该算法,(2)位格雷码可以这样推出:

    1. 已知(1)位格雷码为 (0,1)

    2. 前两个格雷码为 (00,01)。后两个格雷码为(11,10)。合并得到 (00,01,11,10),编号依次为 (0 ~ 3)

    同理,(3) 位格雷码可以这样推出:

    1. 已知(2)位格雷码为:(00,01,11,10)

    2. 前四个格雷码为:(000,001,011,010)。后四个格雷码为:(110,111,101,100)。合并得到:(000,001,011,010,110,111,101,100),编号依次为 (0 ~ 7)

    现在给出 (n,k),请你求出按上述算法生成的(n)位格雷码中的(k)号二进制串。

    输入格式

    仅一行两个整数 (n,k),意义见题目描述。

    输出格式

    仅一行一个(n)位二进制串表示答案。

    输入输出样例

    输入

    2 3
    

    输出

    10
    

    输入 #2

    3 5
    

    输出 #2

    111
    

    输入 #3

    44 1145141919810
    

    输出 #3

    00011000111111010000001001001000000001100011
    

    说明/提示

    【样例(1)解释】

    (2) 位格雷码为:(00,01,11,10),编号从(0∼3),因此(3)号串是(10)

    【样例(2)解释】

    (3)位格雷码为:(000,001,011,010,110,111,101,100),编号从(0∼7),因此(5)号串是(111)

    【数据范围】

    对于(50%)的数据:(0≤n≤10)
    对于(80%)的数据:(k≤5×10^6)
    对于(95%)的数据:(k≤2^{63})
    对于(100%)的数据:(1≤n≤64,0≤k<2^n)


    如果模拟,那么只能过(50)分。

    首先,确定第(k)个数的位置在哪里。若(k<2^n),该数在序列前半部分;反之,则在右半部分。
    该数的第(n)位就是如此确定下来的:若在前半部分,第(n)位数上为(0);若为后半部分,第(n)位数上为(1)

    我们继续。

    若该数位于前半部分,那么(n-1)位即可以按上述规律确定;如果不幸在后面了,(n-1)位规律是相反的。

    分治!

    换句话说,确定第(i+2)位数之后,该数的位置仅影响的是第(i+1)位的确定,但跟第(i)位毫无关联。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define ull unsigned long long
    using namespace std;
    const int maxn = 64 + 5;
    ull n, k, p[maxn];
    int main()
    {
    	cin >> n >> k;
    	p[0] = 1;
    	for(int i = 1; i <= n; ++ i) p[i] = p[i - 1] << 1ll;
    	int cur = 0;
    	for(int i = n; i > 0; -- i)
    	{
    		if(!cur)
    		{
    			if(k < p[i - 1]) 
    			{
    				putchar('0');
    				cur = 0;
    			}
    			else 
    			{
    				putchar('1');
    				cur = 1;
    			}
    		}
    		else
    		{
    			if(k < p[i - 1]) 
    			{
    				putchar('1');
    				cur = 0;
    			}
    			else 
    			{
    				putchar('0');
    				cur = 1;
    			}
    		}
    		k %= p[i - 1];
    	}
    	return 0;
    }
    
  • 相关阅读:
    JQuery制作网页——第五章 初识 jQuery
    JQuery制作网页—— 第四章JavaScript对象及初识面向对象
    JQuery制作网页—— 第三章 JavaScript操作DOM对象
    JQuery制作网页—— 第二章 JavaScript操作BOM对象
    JQuery制作网页—— 第一章 JavaScript基础
    JAVA / MySql 编程——第八章 DAO 模式
    JAVA / MySql 编程——第七章 JDBC
    JAVA / MySql 编程——第六章 Mysql 创建账户的相关命令
    JAVA / MySql 编程——第五章 事务、视图、索引、备份和恢复
    JAVA / MySql 编程—— 第四章 高级查询(二)
  • 原文地址:https://www.cnblogs.com/zach20040914/p/13384736.html
Copyright © 2020-2023  润新知