2019 CSP-S2 Day1T1题解

原题链接(Luogu)

// 就不打freopen了

格雷码(Code)
输入文件名:code.in
输出文件名:code.out
共 20 个测试点,每个测试点 5 分
每个测试点限时 1 秒,运行内存上限 256MB

题目描述

通常,人们习惯将所有 \(n\) 位二进制串按照字典序排列,例如所有 \(2\) 位二进制串按字典序从小到大排列为:\(00\)\(01\)\(10\)\(11\)
格雷码(Gray Code)是一种特殊的 \(n\) 位二进制串排列法,它要求相邻的两个二进制串间恰好有一位不同,特别地,第一个串与最后一个串也算作相邻。
所有 \(2\) 位二进制串按照格雷码排列的一个例子为:\(00\)\(01\)\(11\)\(10\)

\(n\) 位格雷码不止一种,下面给出其中一种格雷码的生成算法:
\(1\) 位格雷码由两个一位二进制串组成,顺序为:\(00\)\(11\)
\(n+1\) 位格雷码的前 \(2^n\) 个二进制串,可以由依此算法生成的 \(n\) 位格雷码(总共 \(2^n\)\(n\) 位二进制串)按顺序排列,再在每个串前加一个前缀 \(0\) 构成。
\(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\) 位格雷码为 \(0\)\(1\)

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

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

已知 \(2\) 位格雷码为:\(00\)\(01\)\(11\)\(10\)

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

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

输入格式

从文件 \(code.in\) 中读入数据。
仅一行两个整数 \(n,k\) ,意义见题目描述。

输出格式

输出到文件 \(code.out\) 中。
仅一行一个 \(n\) 位二进制串表示答案。

样例

样例 1 输入

1
2 3

样例 1 输出

1
10

样例 1 解释

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

样例 2 输入

1
3 5

样例 2 输出

1
111

样例 2 解释

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

数据范围

对于 \(50\%\) 的数据:\(n ≤ 10\)

对于 \(80\%\) 的数据:\(k ≤ 5 \times 10^6\)

对于 \(95\%\) 的数据:\(k ≤ 2 ^ {63}-1\)

对于 \(100\%\) 的数据:\(1 \le n \le 64\)\(0 \le k \lt 2^n\)

95' 代码


#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef unsigned long long llu;
int main(){
	freopen("code.in","r",stdin);freopen("code.out","w",stdout);
	int n ;
	llu k ;
	scanf("%d%llu",&n,&k);
	k += 1 ;
	llu now = pow(2,n);
	bool num = 0 ; 
//	printf("%llu %llu\n",now,k); 
	if(k > now / 2)printf("1");
	else printf("0");
	if(n > 1){ 
		
		for(int i = 2 ; i <= n ; i ++){
//			printf("\n\n---%d %llu %llu---\n\n",i,now,k);
			k %= now ;
			if(now > 4){
				if(k <= (now / 4) || k > ((3 * now) / 4))printf("0");
				else printf("1");
			}
			else {
				if(k <= 1 || k >= 4)printf("0");
				else printf("1");
			}	 
			now /= 2 ;
		}
	}
	
//	printf("%llu %llu %d",now, k , n );
	return 0 ;
} 
posted @ 2020-10-28 01:29  Last-Order  阅读(136)  评论(0编辑  收藏  举报