有乙個長度為\(2 ^ n\),下標依次為\(0, 1, \ldots, 2 ^ n - 1\)的陣列,你要和互動庫進行若干輪操作。
每次操作開始時,陣列裡只有\(a[x] = a[y] = \frac (x \neq y)\),剩下的元素都是0。
你要和互動庫進行多次互動,求出\(x \oplus y\)的值(保證操作過程中\(x \oplus y\)不變)。
你可以進行兩種操作:
query
:
作一次詢問,互動庫會隨機返回乙個下標,返回\(x\)的概率是\(\frac ^ a[i] ^ 2}\),然後會開始新的一輪,互動庫會重新ran一對\(x, y\),保證\(x \oplus y\)不變的前提下,對陣列進行同上的賦值。
manipulate(a, i)
:
給出乙個\(2 \times 2\)的實數矩陣\(a\),互動庫會把陣列\(a\)更新,具體來說,即:
\[\begin
a'[x] = a[0][0] a[x] + a[1][0] a[x + 2 ^ i] \\
a'[x + 2 ^ i] = a[0][1] a[x] + a[1][1] a[x + 2 ^ i] \\
\end
\]要求給出的矩陣是酉矩陣,即\(a a ^t = i\)。此時可以證明\(\sum_ ^ a[i] ^ 2\)不變。
\(n \leq 16\)。
首先單方面感謝yhx大佬,這份題解主要參考了他的部落格。
這個manipulate
操作很像fwt_xor,而fwt_xor的矩陣是
\[\begin
1 & 1 \\
1 & -1 \\
\end
\]這個矩陣不是酉矩陣。但是只要變換一下,乘個縮放因子即可
\[\begin
\frac & \frac \\
\frac & -\frac \\
\end
\]此時,設原序列為\(\\),變換後序列為\(\\),根據結論,有
\[a'_k = (\frac) ^ \sum_ ^ n (-1) ^ a_i
\]則根據已知,得
\[a'_k = (\frac) ^ ((-1) ^ + (-1) ^ )
\]顯然,\( ^ 2 = 0\)或\( ^ 2 = \frac}\)。
注意到\(\sum ^ 2 = \sum ^ 2 = 1\),因此有\(2 ^ \)個\(k\)滿足\(a'_k = 0\)和\(2 ^ \)個\(k\)滿足\(a'_k \neq 0\)。
此時,呼叫一次query
,會等概率返回\(2 ^ \)個滿足\(a'_k \neq 0\)的\(k\)中的乙個。
又因為當\(a'_k \neq 0\)時,\((-1) ^ = (-1) ^ \),可以得到
\[|(x \oplus y) \cap k| \equiv 0 \pmod 2
\]注意到題目保證\(x \oplus y\)始終不變,那麼我們在得到乙個\(k\)後,\((x \oplus y) \cap k\)的二進位制中一定有偶數個1。
如果\(k\)是隨機返回的,我們期望每次排除一半的位置。
期望\(\mathcal o(n)\)輪後找到答案,所以總操作次數期望\(\mathcal o(n ^ 2)\)。
期望時間複雜度為\(\mathcal o(n 2 ^ n)\)。
#include "quantumbreak.h"
#include using namespace std;
const int n = 1 << 16;
const double s2 = 1 / sqrt(2.0);
double m[2][2] = , };
int query_xor(int n, int t)
for ( ; vis.count() > 1; )
for (int r = query(), i = 1; i <= s; ++i)
} }return vis._find_first();
}
UOJ 328 UTR 3 量子破碎
傳送門 學過 fwt 看到操作 2 不難可以聯想到 fwt 考慮一遍 oplus fwt 會把 a t 變成什麼 a t 1 1 a x 考慮這個東西 1 1 當 bitcount x t 和 bitcount y t 同奇偶時才有值 實際上就是 bitcount x oplus y t 為偶數 而...