uoj328 UTR 3 量子破碎

2022-05-23 21:12:10 字數 2060 閱讀 7772

有乙個長度為\(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 為偶數 而...