解题思路
注意到若 \(A_i=1\) 那么 \(A_i\) 一定没有被损坏。我们尝试通过把信息编码进 \(1\) 的位置。
显然无法朴素地对 \(X\) 拆位。考虑对每个位置设置一个 \([0,2^{60})\) 的权值 \(w_i\)。然后找到一种方案使得 \(X\) 等于所有 \(1\) 的位置设置的权值的异或和,即
\X=\\bigoplus_{i\\in T}w_i \\
其中 \(T=\{i|S_i=1\}\)。
我们可以通过设置固定随机种子的技巧让双方事先约定好 \(\{w_i\}_{i=0}^{N-1}\)。然后直接异或线性基解决即可。
可以证明,这种方式的成功率足够大。
恰有 \(110\) 个可用位置,每个权值视为一个 \(60\) 维布尔向量,即
\w_i\\in\\mathbb Z_2\^{60} \\
且向量的取值互相独立。
任意向量 \(x\) 和 \(y\) 的点积为 \(0\) 的概率为 \(\frac{1}{2}\)。这里点积定义为 \(\operatorname{popcount}(x \operatorname{and} y) \bmod 2\)。
因此存在一个 \(x\) 使其和所有 \(w_i\) 的点积都为 \(0\) 的概率不超过
\2\^{60}\\times 2\^{-110}=2\^{-50} \\
即这 \(110\) 个向量恰能张成整个 \(\mathbb Z_2^{60}\) 空间的概率至少为
\1-2\^{-50} \\
共 \(1000\) 组测试,总成功概率不低于
\(1-2\^{-50})\^{1000}\\approx 1-10\^{-12} \\
Code
Anna.cpp
cpp
#include "Annalib.h"
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i(a);i<b;++i)
#define per(i,a,b) for(int i(a);i>b;--i)
#define rept(i,a,b) for(int i(a);i<=b;++i)
#define pert(i,a,b) for(int i(a);i>=b;--i)
using namespace std;
namespace{
constexpr int SEED=0,N=150,M=60;
ll a[N],b[M];
bitset<N> msk[M];
// b[i]:线性基中最高位是i的数,没有则为0
// msk[i]:线性基中最高位是i的数是哪些a的元素异或起来得到的
bool f[N],flag;
void init(){
if(!flag){
mt19937 gen(SEED);
uniform_int_distribution<ll> dist(0,(1ll<<60)-1);
rep(i,0,N) a[i]=dist(gen);
flag=true;
}
fill(f,f+N,false);
fill(b,b+M,0);
rep(i,0,M) msk[i].reset();
}
}
void Anna(int n,ll x,int k,int p[]){
init();
rep(i,0,k) f[p[i]]=true;
rep(i,0,n) if(!f[i]){
// 将a[i]插入线性基
ll tb=a[i];
bitset<N> tmsk;
tmsk.set(i);
pert(j,M-1,0) if(tb>>j&1){
if(b[j]){
tb^=b[j];
tmsk^=msk[j];
}else{
b[j]=tb;
msk[j]=tmsk;
break;
}
}
}
// 判断x能否被线性基中的数表示
bitset<N> xmsk;
pert(j,M-1,0) if(x>>j&1){
x^=b[j];
xmsk^=msk[j];
}
rep(i,0,n) Set(i,xmsk[i]);
}
Bruno.cpp
cpp
#include "Brunolib.h"
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i(a);i<b;++i)
#define per(i,a,b) for(int i(a);i>b;--i)
#define rept(i,a,b) for(int i(a);i<=b;++i)
#define pert(i,a,b) for(int i(a);i>=b;--i)
using namespace std;
namespace{
constexpr int SEED=0,N=150,M=60;
ll a[N];
bool flag;
void init(){
if(!flag){
mt19937 gen(SEED);
uniform_int_distribution<ll> dist(0,(1ll<<60)-1);
rep(i,0,N) a[i]=dist(gen);
flag=true;
}
}
}
ll Bruno(int n,int f[]){
init();
ll ans=0;
rep(i,0,n) if(f[i]) ans^=a[i];
return ans;
}