uoj328. 【UTR #3】量子破碎

题意

有一个长度为\(2 ^ n\),下标依次为\(0, 1, \ldots, 2 ^ n - 1\)的数组,你要和交互库进行若干轮操作。
每次操作开始时,数组里只有\(a[x] = a[y] = \frac{1}{\sqrt 2} (x \neq y)\),剩下的元素都是0。
你要和交互库进行多次交互,求出\(x \oplus y\)的值(保证操作过程中\(x \oplus y\)不变)。
你可以进行两种操作:
query:
作一次询问,交互库会随机返回一个下标,返回\(x\)的概率是\(\frac{a[x] ^ 2}{\sum_{i = 0} ^ {n - 1} a[i] ^ 2}\),然后会开始新的一轮,交互库会重新ran一对\(x, y\),保证\(x \oplus y\)不变的前提下,对数组进行同上的赋值。
manipulate(A, i):
给出一个\(2 \times 2\)的实数矩阵\(A\),交互库会把数组\(a\)更新,具体来说,即:

\[\begin{cases} 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{cases} \]

要求给出的矩阵是酉矩阵,即\(A A ^T = I\)。此时可以证明\(\sum_{i = 0} ^ {n - 1} a[i] ^ 2\)不变。
\(n \leq 16\)

题解

首先单方面感谢yhx大佬,这份题解主要参考了他的博客。
这个manipulate操作很像fwt_xor,而fwt_xor的矩阵是

\[\begin{bmatrix} 1 & 1 \\ 1 & -1 \\ \end{bmatrix} \]

这个矩阵不是酉矩阵。但是只要变换一下,乘个缩放因子即可

\[\begin{bmatrix} \frac{1}{\sqrt 2} & \frac{1}{\sqrt 2} \\ \frac{1}{\sqrt 2} & -\frac{1}{\sqrt 2} \\ \end{bmatrix} \]

此时,设原序列为\(\{a_i\}\),变换后序列为\(\{a'_k\}\),根据结论,有

\[a'_k = (\frac{1}{\sqrt 2}) ^ {n} \sum_{i = 0} ^ n (-1) ^ {|i \cap k|} a_i \]

则根据已知,得

\[a'_k = (\frac{1}{\sqrt 2}) ^ {n + 1} ((-1) ^ {|x \cap k|} + (-1) ^ {|y \cap k|}) \]

显然,\({a'_k} ^ 2 = 0\)\({a'_k} ^ 2 = \frac{1}{2 ^ {n - 1}}\)
注意到\(\sum {a'_k} ^ 2 = \sum {a_k} ^ 2 = 1\),因此有\(2 ^ {n - 1}\)\(k\)满足\(a'_k = 0\)\(2 ^ {n - 1}\)\(k\)满足\(a'_k \neq 0\)
此时,调用一次query,会等概率返回\(2 ^ {n - 1}\)个满足\(a'_k \neq 0\)\(k\)中的一个。
又因为当\(a'_k \neq 0\)时,\((-1) ^ {|x \cap k|} = (-1) ^ {|y \cap k|}\),可以得到

\[|(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 <bits/stdc++.h>
using namespace std;
const int N = 1 << 16;
const double s2 = 1 / sqrt(2.0);
double M[2][2] = {{s2, s2}, {s2, -s2}};
int query_xor(int n, int t) {
	int S = (1 << n) - 1; bitset <N> vis;
	for (int i = 1; i <= S; ++i) {
		vis.set(i);
	}
	for ( ; vis.count() > 1; ) {
		for (int i = 0; i < n; ++i) {
			manipulate(M, i);
		}
		for (int r = query(), i = 1; i <= S; ++i) {
			if (__builtin_parity(i & r)) {
				vis.reset(i);
			}
		}
	}
	return vis._Find_first();
}
posted @ 2019-10-09 20:11  psimonw  阅读(204)  评论(0编辑  收藏  举报