Atcoder AGC031C Differ By 1 Bit (构造、二进制)
Atcoder AGC031C Differ By 1 Bit (構(gòu)造、二進(jìn)制)
哎呀這個(gè)C怎么比B還水。。。。(我現(xiàn)在大概也就會(huì)做點(diǎn)這種水題了吧)
題目鏈接
https://atcoder.jp/contests/agc031/tasks/agc031_c
題目大意
符號(hào)約定: \(count(x)\)表示整數(shù)\(x\)在二進(jìn)制表示下\(1\)的個(gè)數(shù)。“二進(jìn)制表示下第\(x\)位”表示位權(quán)為\(2^x\)的位。數(shù)組下標(biāo)全部從0開始
給定\(N,A,B\), 求構(gòu)造一個(gè)\([0,2^N-1]\)的排列\(p\), 滿足\(p_0=A, p_{2^N-1}=B\), 對于任何\(i\in[1,2^N-1]\), \(count(p_i\ xor\ p_j)=1\).
\(1\le N\le 17\)
題解
注: 這道題“二進(jìn)制位相差\(1\)個(gè)”的這個(gè)條件,我們可以用圖形象地表示出來,就是一個(gè)\(n\)維立方體頂點(diǎn)和棱的幾何結(jié)構(gòu)。這樣畫出來也許有助于理解本題。
首先觀察到一些結(jié)論。
(1) 如果一個(gè)排列\(p\)是合法的,那么把\(p\)中的每個(gè)元素異或一個(gè)正整數(shù)\(x\)之后得到排列\(p'\),排列\(p'\)仍然是合法的。
太顯然,不證了。
據(jù)此,我們可以令\(B=B\ xor\ A\), 然后構(gòu)造一個(gè)\(p\)滿足\(p_0=0, p_{2^N-1}=B\), 最后把答案序列全部\(xor\ A\)
(2) 能構(gòu)造出以\(0\)開始以\(B\)結(jié)束的合法排列當(dāng)且僅當(dāng)\(count(B)\equiv 1(\mod 2)\)
證明: \(|count(p_i)-count(p_{i-1})|=1\), 故\(count(p_{2^N-1})\)為奇數(shù)。必要性得證。
充分性?我們可以直接按以下方案進(jìn)行構(gòu)造
假設(shè)我們要解決問題\((n,b)\) (表示大小為\(n\)起始點(diǎn)為\(0\)終止點(diǎn)為\(b\))
分類討論\(b\)二進(jìn)制表示下第\((n-1)\)位
若為\(1\), 則我們先在\([0,2^{n-1}-1]\)內(nèi)構(gòu)造一個(gè)起始點(diǎn)為\(0\)終止點(diǎn)為\(1\)的排列(遞歸調(diào)用問題\((n-1,1)\)),然后從\(1\)這個(gè)點(diǎn)一步跳到\(2^{n-1}+1\), 再構(gòu)造一個(gè)\([2^{n-1},2^n-1]\)的起始點(diǎn)為\(2^{n-1}+1\)終止點(diǎn)為\(b\)的排列。這一部分可以遞歸調(diào)用問題\((n-1,b\ xor\ (2^{n-1}+1))\)然后把生成的排列每個(gè)位置都異或\(2^{n-1}+1\)解決。
若為\(0\), 情況稍有復(fù)雜。我們依然是構(gòu)造兩個(gè)排列,第一個(gè)排列\(p_1\)由問題\((n-1,a)\)生成, 而我們希望在排列\(p_1\)中塞入另一個(gè)排列,而使得新排列仍然合法。考慮\(p_1[0]\)和\(p_1[1]\) (其中\(p_1[0]\)顯然為\(0\)), 構(gòu)造一個(gè)排列\(p_2\)值域?yàn)?span id="ozvdkddzhkzd" class="math inline">\([2^{n-1},2^n-1]\)且起始于\(2^{n-1}\)終止于\(p_1[1]\ xor\ 2^{n-1}\),這一部分可以通過調(diào)用問題\((n-1,p_1[1])\)然后給生成排列的每個(gè)元素都加上\(2^{n-1}\)完成。然后我們把\(p_2\)接在\(p_1[0]\)和\(p_1[1]\)之間,它就合法了。
時(shí)間復(fù)雜度\(T(n)=2T(n-1)+O(2^n)\), 解得\(T(n)=O(2^nn)\)
說了這么多,可能不太清楚。。后面我舉個(gè)例子:(僅展開模擬第一層遞歸)
例子1: 問題(4,13)的解決 判斷出為第一種情況(第3位為1) 首先構(gòu)造問題(3,1)的排列: 0 4 5 7 6 2 3 1 然后構(gòu)造問題(3,4)的排列: 0 2 3 1 5 7 6 4,其中4=13 xor 9, 9=2^3+1 問題(3,4)的排列每個(gè)數(shù)xor 9之后可得: 9 11 10 8 12 14 15 13 前后拼接即可得: 0 4 5 7 6 2 3 1 9 11 10 8 12 14 15 13就是答案例子2: 問題(4,7)的解決 判斷出為第二種情況(第3位為0) 首先構(gòu)造問題(3,7)的排列p1: 0 2 3 1 5 4 6 7, 發(fā)現(xiàn)p1[1]是2 然后構(gòu)造問題(3,2)的排列: 0 4 6 7 5 1 3 2, 然后每個(gè)數(shù)+8后可得8 12 14 15 13 9 11 10 然后把這個(gè)以8開頭以10結(jié)束的排列插在p1的0和2之間,得到0 8 12 14 15 13 9 11 10 2 3 1 5 4 6 7就是答案代碼
#include<cstdio> #include<cstdlib> #include<cstring> using namespace std;const int N = 17; int ans[(1<<N)+3]; int cnt[(1<<N)+3]; int tmp[(1<<N)+3]; int n,A,B;void solve(int x,int a,int ret[]) {if(x==0) {ret[0] = 0; return;}if(x==1) {ret[0] = 0; ret[1] = 1; return;}if(a&(1<<(x-1))){solve(x-1,1,ret);solve(x-1,a^((1<<(x-1))+1),ret+(1<<(x-1)));for(int i=(1<<(x-1)); i<(1<<x); i++) ret[i] = ret[i]^((1<<(x-1))+1);}else{solve(x-1,a,ret);solve(x-1,ret[1],ret+(1<<(x-1)));for(int i=(1<<(x-1)); i<(1<<x); i++) ret[i] = ret[i]^(1<<(x-1));tmp[0] = ret[0]; for(int i=0; i<(1<<(x-1)); i++) tmp[i+1] = ret[i+(1<<(x-1))];for(int i=((1<<(x-1))+1); i<(1<<x); i++) tmp[i] = ret[i-(1<<(x-1))];for(int i=0; i<(1<<x); i++) ret[i] = tmp[i];} }int main() {scanf("%d%d%d",&n,&A,&B); B^=A;for(int i=1; i<(1<<n); i++) cnt[i] = cnt[i>>1]+(i&1);if((cnt[B]&1)==0) {puts("NO"); return 0;}puts("YES");solve(n,B,ans);for(int i=0; i<(1<<n); i++) ans[i]^=A;for(int i=0; i<(1<<n); i++) printf("%d ",ans[i]);return 0; } 發(fā)表于 2019-03-22 21:53 suncongbo 閱讀(...) 評(píng)論(...) 編輯 收藏 刷新評(píng)論刷新頁面返回頂部總結(jié)
以上是生活随笔為你收集整理的Atcoder AGC031C Differ By 1 Bit (构造、二进制)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Atcoder AGC031B Reve
- 下一篇: UOJ #131 BZOJ 4199 l