[故地重游][NOIP2019]格雷码
题目
解说
去年NOIP省赛题,当时就学了1个月OI所以第一题就惨遭爆零,如今再回来刷一遍过了……
总体思路就是把格雷码当成十进制的数字进行处理,最后再转化回二进制。转化后的样子如下:
\(0 \ 1\)
\(0 \ 1 \ 3 \ 2\)
\(0 \ 1 \ 3 \ 2 \ 6 \ 7 \ 5 \ 4\)
\(\dots\)
假设最终结果为\(f(n,k)\)。
不难发现如果要求的数在该行的左半边:
即\(k<2^{n-1}\)
那么\(f(n,k)=f(n-1,k)\)
如果要求的数在该行的右半边:
即\(k>=2^{n-1}\)
那么\(f(n,k)=2^{n-1}+f(n,2^{n}-1-k)\)
这样的话我们就可以用递归来解决,最后的返回条件就是\(n=1\)时若\(k=0\)则返回\(0\),若\(k=1\)则返回\(1\)。
(以下代码中\(ll\)代表\(unsigned \ long \ long\))
ll dfs(int num,ll a){
if(num==1&&a==0) return 0;
if(num==1&&a==1) return 1;
if(a<=power(num-1)-1) return dfs(num-1,a);
return power(num-1)+dfs(num,power(num)-1-a);
}
但这时我们注意到一个问题:\(num=64\)时\(2^{64}\)会炸\(unsigned \ long \ long\)……
那我们特判一下不就行了。
ll dfs(int num,ll a){
if(num==1&&a==0) return 0;
if(num==1&&a==1) return 1;
if(a<=power(num-1)-1) return dfs(num-1,a);
if(num<64) return power(num-1)+dfs(num,power(num)-1-a);
else return power(num-1)+dfs(num,power(63)-1+power(63)-a);
}
最后再把数字转化为二进制即可。
代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;//记得开unsigned long long
int n;
ll k;
bool ans[70];
ll power(int x){//快速幂
ll ans=1,a=2;
while(x){
if(x&1) ans*=a;
x>>=1;
a*=a;
}
return ans;
}
ll dfs(int num,ll a){//递归
if(num==1&&a==0) return 0;
if(num==1&&a==1) return 1;
if(a<=power(num-1)-1) return dfs(num-1,a);
if(num<64) return power(num-1)+dfs(num,power(num)-1-a);
else return power(num-1)+dfs(num,power(63)+9223372036854775807-a);
}
void change(ll x){//转化为二进制
int cnt=0;
while(x){
ans[cnt]=x%2;
x/=2;
cnt++;
}
}
int main(){
cin>>n>>k;
change(dfs(n,k));
for(int i=n-1;i>=0;i--) cout<<ans[i];
return 0;
}
幸甚至哉,歌以咏志。
签名:
我将轻轻叹息,叙述这一切,
许多许多年以后:
林子里有两条路,我——
选择了行人稀少的那一条,
它改变了我的一生。