zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    牛客网 二叉树的镜像 JAVA
    牛客网 反转链表 JAVA
    牛客网 调整数组顺序使奇数位于偶数前面 JAVA
    Integer to Roman LeetCode Java
    Valid Number leetcode java
    Longest Common Prefix
    Wildcard Matching leetcode java
    Regular Expression Matching
    Longest Palindromic Substring
    Add Binary LeetCode Java
  • 原文地址:https://www.cnblogs.com/zach20040914/p/13384736.html
Copyright © 2011-2022 走看看