2019 CSP-S2 Day1T1题解
原题链接(Luogu)
// 就不打freopen了
题目描述
通常,人们习惯将所有 \(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 ;
}