[故地重遊][NOIP2019]格雷碼
阿新 • • 發佈:2020-07-17
題目
解說
去年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\)
那我們特判一下不就行了。
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;
}
幸甚至哉,歌以詠志。