zoukankan      html  css  js  c++  java
  • uoj328. 【UTR #3】量子破碎

    题意

    有一个长度为(2 ^ n),下标依次为(0, 1, ldots, 2 ^ n - 1)的数组,你要和交互库进行若干轮操作。
    每次操作开始时,数组里只有(a[x] = a[y] = frac{1}{sqrt 2} (x eq 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 imes 2)的实数矩阵(A),交互库会把数组(a)更新,具体来说,即:

    [egin{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的矩阵是

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

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

    [egin{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 eq 0)
    此时,调用一次query,会等概率返回(2 ^ {n - 1})个满足(a'_k eq 0)(k)中的一个。
    又因为当(a'_k eq 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();
    }
    
  • 相关阅读:
    第四周学习报告
    第三周学习报告
    第二周学习报告
    第一周学习报告
    大创首月学习计划
    20183122 综合实验《Python程序设计》实验报告
    20183122 实验三《Python程序设计》实验报告
    20183122 实验二《Python程序设计》实验报告
    数据存储和JSON,CSV
    python模块那点事
  • 原文地址:https://www.cnblogs.com/psimonw/p/11643885.html
Copyright © 2011-2022 走看看