【解题报告】洛谷P5657 格雷码
题目链接
https://www.luogu.com.cn/problem/P5657
思路
我们大眼观察数据
然后发现, n 位格雷码实际上是由 n−1 位格雷码转化而来
找规律知道,除去第一位之外,前一半和后一半的数值实际上是中心对称的,所以我们打出了如下的暴力
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include <iostream> #include <cstdio> #include <algorithm> #include <string> using namespace std; unsigned long long n,k; void dfs(unsigned long long n,unsigned long long k) { if(n==0) return ; long long x=(1<<(n-1)); if(k==0) { for(long long i=1;i<=n;i++) cout<<"0"; return ; } if(k+1>x) { long long next=2*x-k-1; cout<<"1"; dfs(n-1,next); } else { long long next=k; cout<<"0"; dfs(n-1,next); } } int main() { cin>>n>>k; dfs(n,k); cout<<endl;
return 0; }
|
这份代码可以得到60pts的高分
所以我们继续研究
分别把自己能手算出来的每个格雷码和 k 进行对比发现
当 k≥2 的时候,第 k 个格雷码的第 1 位是 k−2 的第二位去翻的结果,否则格雷码的第一位是 0
实际上还有更方便的方法
考虑答案的每一位,发现格雷码第 i 位是 k xor ⌊2k⌋ 的第 i 位
然后。。。就过了?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cstring> using namespace std; int n; unsigned long long k; int main() { cin>>n>>k; k^=k>>1; while(~--n) cout<<(k>>n&1); return 0; }
|