time limit: 3000 ms memory limit: 256 mb
description
it = inverse transform
兩個長度為 \(2^n\) 的序列 \(a,b\). ( 下標從 0 到 \(2n−1\) )
滿足 \(0≤a_i≤10^9\) , 且 \(b\) 由 \(a\) 變換而來, 變換如下:
\[b_i=\sum\limits_f((i∨j)⊕i) a_j
\]其中 \(∨\) 表示按位或, \(⊕\) 表示按位異或. \(的二進位制中的個數為偶數f(x)=[x的二進位制中1的個數為偶數]\)
(其中 [expression] 當 expression為真時為 1, 否則為 0)
現在, \(a\) 序列被玩丟了...
請你通過 \(b\) 序列還原出 \(a\) 序列
input
第一行乙個數 \(t\) 表示測試資料組數
接下來對於每組資料 :
第一行乙個整數 \(n\)
第二行 \(2^n\) 個整數, 表示序列 \(b\)
output
輸出包括 \(t\)行
每行 \(n\) 個整數, 表示序列 \(a\)
sample input
401
11 3
25 3 4 10
3101 91 92 104 93 105 108 190
sample output
1
1 21 2 3 4
31 24 26 23 27 23 24 12
hint對於10% 的資料 \(n≤5\)
對於另外10% 的資料\(n≤10\)
對於100% 的資料 : \(t≤5,1≤n≤20\)
資料保證 \(b\) 序列 能 唯一地對應乙個 \(a\) 序列
且保證對應的 \(a\) 序列滿足 \(0≤a_i≤10^9\)
(注意: 但不保證讀入的 \(b\) 序列滿足 \(0≤b_i≤10^9\) )
solution
這個直接大力高斯消元就好了,注意是。。不保證\(b\)是int所以要用long long。。
(另外10%不會qwq)
首先觀察一下那個詭異的變換\((i∨j)⊕i\)(記作\(change(x,y)\)好了)我們考慮一下把不同的\(0\)和\(1\)組合帶進去會得到什麼:
\[\begin
change(0,1)=1\ \ \ \ \ \ \ \ \ \ \ \ change(1,1)=0\\
change(0,0)=0\ \ \ \ \ \ \ \ \ \ \ \ change(1,0)=0\\
\end
\]會發現帶進去的除了\((0,1)\)以外其他全部都是\(0\)
然後我們再看一下那個詭異的\(f\)函式,會發現我們需要考慮的只是\(change\)後的\(1\)的個數的奇偶性
然後因為這個東西每位的運算是獨立的,再加上是二進位制,可以考慮分治來解決這個問題
\(b\)推\(a\)比較煩,那麼就先看\(a\)推\(b\)
考慮每次將這個數列分成兩半,對於\([l,mid]\)中的\(b_i\),我們只求\(b_i=\sum\limits_^f(change(i,j))a[j]\)
同理\([mid+1,r]\)中的\(b_i=\sum\limits_^f(change(i,j))a[j]\)
換句話來說,就是對於分成的每乙個區間,我們只求這個區間內對答案的貢獻,按照這樣的方式,分到最後區間長度為\(1\)時,我們可以得到\(b_i=a_i\),然後再將這些分開的區間一層一層地合併,同時統計跨區間的貢獻,最後得到完整的\(b\)陣列(有點像。。線段樹的pushup一樣?)
那麼現在考慮怎麼統計跨區間的貢獻
我們考慮將\([l,mid]\)和\([mid+1,r]\)合併成\([l,r]\)的情況,考慮這樣劃分出來的區間的性質,必定是\([2^n,2^m-1]\)這樣的形式,記\([l,mid]\)的區間長度為\(2^k\),\([l,mid]\)和\([mid+1,r]\)還滿足這兩個區間對應的下標寫成二進位制後,後\(k\)位是一樣的,只有第\(k+1\)位不同,舉\([0,1]\)和\([2,3]\)為例子,兩個區間對應的下標寫成二進位制後分別是\(00,01\)和\(10,11\),對應起來只有第\(2\)位是不同的,而且左邊的一組這位全是\(0\),右邊的一組這位全是\(1\)
清楚了這樣的性質之後,再考慮合併區間就方便多了
為了方便我們將\([l,mid]\)記作\(bx\)(下標從\(l\)到\(mid\) ),\([mid+1,r]\)記作\(by\)(下標從\(mid+1\)到\(r\) ),這兩個區間合併後在大區間記作\(b\)(下標從\(l\)到\(r\) ),\(b\)由\(b'x\)和\(b'y\)兩個部分組成,其中\(b'x\)的下標從\(l\)到\(mid\),\(b'y\)的下標從\(mid+1\)到\(r\)
首先考慮\(b'y[i]\)是怎麼得到的,首先肯定是\(by[i]\)加上\(\sum\limits_^f(change(i,j))a[j]\)得到的,而由於\(bx\)和\(by\)的下標滿足上面的性質,所以我們只用考慮不同的那一位對\(1\)的個數的奇偶性的影響
而因為我們的\(change\)只有帶入\((0,1)\)後得到的是\(1\),也就是說只有兩個數不同的那一位分別為\(0\)和\(1\)的時候才會對奇偶性有影響,所以我們可以發現,當\(i \in [mid+1,r]\)時,\(\sum\limits_^f(change(i,j))a[j]=bx[i-mid]\)(因為這樣不同的兩位帶進去是\((1,0)\),得出來是\(0\),不會對奇偶性造成影響,而除去不同的那一位,\(i\)和\(i-mid\)的其他位是一樣的,貢獻相同),所以我們可以知道:
\[b'y[i]=by[i]+bx[i-mid]
\]同理,考慮\(b'x[i]\)是怎麼得到的,肯定也是\(bx[i]\)加上\(\sum\limits_^f(change(i,j))a[j]\)得到的,從同樣的角度來分析,會發現\(b'x[i]\)在計算的時候,我們帶進去考慮的不同的那位是\((0,1)\),得出來是\(1\),會影響奇偶性,所以那一大段sigma應該是等於計算\(by[i+ mid]\)中\(f\)值為\(0\)的\(a[j]\)的和,我們記\(\sum\limits_^a[i]=sum\),那麼:
\[b'x[i]=bx[i]+sum-by[i+mid]
\]於是乎順推的問題就很愉快滴解決了(感覺有點像fft?)
但是現在的問題是知道\(b\)來求\(a\)啊,也就是我們要從\(b'x\)和\(b'y\)推回\(bx\)和\(by\) ,所以我們把上面的兩條式子稍微變一下:
\[\begin
bx[i]&=\frac\\
by[i]&=b'y[i]-bx[i-mid]
\end
\]看起來不錯,但是那個\(sum\)怎麼辦?
我們再考慮一下\(by[r]\)(也就是\(by\)部分的最後一位)的值是哪些\(a\)貢獻過來的,因為\(r\)是\(2^k-1\)的形式,所以寫成二進位制之後(不看前導零)都是\(1\),也就是從下面的更小的區間合併上來時,怎麼算\(1\)的個數的奇偶性都不會有變化,也就是說\([l,r]\)這個區間內的所有\(a\)都是對其有貢獻的,即\(by[r]=\sum\limits_^a[i]\),而\(bx[mid]\)(也就是\(bx\)部分的最後一位)則是除了從右邊數第\(k\)位是\(0\)外,其他位和\(r\)相同,稍微思考一下其推上來的過程可以發現\(bx[mid]=\sum\limits_^a[i]\)
那麼我們的\(sum=by[r]-bx[mid]\)就好了
然後就一路推下去長度從\(n\)推到\(1\)就可以將\(a\)完整還原出來啦
**大概長這個樣子,十分簡短
(題外話:聽說這個其實跟fwt很像?然後寫起來的迴圈跟fft長得一樣樣的除了最外層逆過來列舉了)
#include#include#include#define ll long long
using namespace std;
const int maxn=(1<<20)+10;
ll a[maxn];
int n,m,t;
int main()
}} for (int i=0;i
printf("%lld ",a[i]);
printf("\n");
}}
Google Home其實是個錯誤
從google i o大會來看,google步微軟後塵的可能性在增加而不是減少。當年微軟如果不是圍繞著windows做網際網路,也許就沒有現在的google。而google如果仍然持續按照搜尋等工具的成功思路來運作ai,那它就很可能像微軟錯失網際網路那樣錯失ai。當年微軟並並非沒有投入資源做網際網路...
快樂其實是一種習慣
到處都不景氣,你的工作心情是否也染上了些許低迷呢?一大早,我跳上一部計程車,要去深圳郊區一企業做內訓。因正好是尖峰時刻,沒多久車子就卡在車陣中,此時前座的司機先生開始不耐地嘆起氣來。隨口和他聊了起來 最近生意好嗎?後照鏡的臉垮了下來,聲音臭臭的 有什麼好?到處都不景氣,你想我們計程車生意會好嗎?每天...
Python學習 01(其實是Linus基礎)
1.1作業系統的作用 1.直接操作計算機硬體 用來管理硬體裝置 2.把操作硬體的 封裝成乙個又乙個的系統呼叫,供其他程式設計師來通過這些系統呼叫來間接操作計算機硬體 聽歌例項 將歌曲檔案從硬碟載入到記憶體中 使用音效卡對音訊資料進行解碼 將解碼後對資料傳送到音響 home 系統預設的使用者家目錄,新...