[故地重游][NOIP2019]格雷码

题目

洛谷5657

解说

去年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;
}

幸甚至哉,歌以咏志。

posted @ 2020-07-17 14:27  DarthVictor  阅读(311)  评论(3编辑  收藏  举报
莫挨老子!