這是一道通訊題。測試
給你 \(8\) 個 \(32\) 位整數。加密端要把這些數加密成至少 \(1000\) 個 \(32\) 位整數,交互庫會把這些整數隨機打亂後發給解密端,解密端最多能得到其中 \(lim\) 個的值,解密端要按順序給出這 \(8\) 個整數。加密
交互庫會測試 \(100\) 次。spa
對於 \(lim\geq 50\) 的測試點,要求 \(100\%\) 的正確率。code
對於 \(lim\geq 20\) 的測試點,要求 \(90\%\) 的正確率。get
對於 \(lim\geq 17\) 的測試點,要求 \(50\%\) 的正確率。it
先把這些數拆成 \(16\) 個 \(16\) 位整數。class
而後每次隨機選一些數異或到一塊兒,前 \(16\) 位爲這些數的異或值,後 \(16\) 位爲選了那些數。im
解密端隨機 \(lim\) 個數,求出這些數能不能解出原來的 \(16\) 個數。通信
若是 \(lim\times 16\) 的矩陣滿秩就能求出。static
\(17\times 16\) 的矩陣滿秩的機率約爲 \(58\%\)。
\(20\times 16\) 的矩陣滿秩的機率約爲 \(94\%\)。
\(50\times 16\) 的矩陣滿秩的機率約爲 \(100\%\)。
仍是先把這些數拆成 \(16\) 個 \(16\) 位整數,記爲 \(a_0,a_1,\ldots,a_{15}\)。
記 \(f(x)=\sum_{i=0}^{15}a_ix^i\)。
取一個合適大小的整數 \(p\)。
對於 \(0\leq i<1000\),返回 \(i+(f(i)\bmod p)\times 1000\)。
解密端隨便選 \(16\) 個數就能插值插出 \(a_0,a_1,\ldots,a_{15}\)。
正確率爲 \(100\%\)。
#include<vector> #include<algorithm> using namespace std; vector<int>encode(vector<int>arr,int lim) { static unsigned a[100]; for(int i=0;i<16;i++) a[i]=0; for(int i=0;i<8;i++) { unsigned v=arr[i]; a[i*2]=v&((1<<16)-1); a[i*2+1]=v>>16; } for(int i=0;i<16;i++) a[i]|=1<<(i+16); vector<int>vec; for(int i=0;i<1<<16;i++) { unsigned s=0; for(int j=0;j<16;j++) if((i>>j)&1) s^=a[j]; vec.push_back(s); } return vec; } static unsigned seed=1932532; static unsigned get() { seed^=seed<<13; seed^=seed>>17; seed^=seed<<5; return seed; } vector<int>decode(int(*const arr)(int),int n,int lim){ static unsigned a[100],b[1000000],c[1000000]; for(int i=0;i<1<<16;i++) c[i]=i; for(int i=0;i<1<<16;i++) { int y=get()%(i+1); if(y!=i) swap(c[i],c[y]); } for(int i=0;i<lim;i++) b[i]=arr(c[i]); vector<int>vec; for(int i=0;i<16;i++) { int x=lim; for(int j=i;j<lim;j++) if(b[j]&(1<<(16+i))) { x=j; break; } if(x>=lim) { for(int i=0;i<8;i++) vec.push_back(0); return vec; } if(x!=i) swap(b[x],b[i]); for(int j=0;j<lim;j++) if(j!=i&&(b[j]&(1<<(16+i)))) b[j]^=b[i]; } for(int i=0;i<16;i++) b[i]&=(1<<16)-1; for(int i=0;i<8;i++) vec.push_back((b[i*2+1]<<16)|b[i*2]); return vec; }
#include<vector> #include<algorithm> using namespace std; typedef long long ll; static const ll p=100003; vector<int>encode(vector<int>arr,int lim) { static unsigned a[100]; for(int i=0;i<16;i++) a[i]=0; for(int i=0;i<8;i++) { unsigned v=arr[i]; a[i*2]=v&((1<<16)-1); a[i*2+1]=v>>16; } vector<int> vec; for(int i=0;i<1000;i++) { ll s=0; for(int j=15;j>=0;j--) s=(s*i+a[j])%p; vec.push_back(i+s*1000); } return vec; } static ll fp(ll a,ll b) { ll s=1; for(;b;b>>=1,a=a*a%p) if(b&1) s=s*a%p; return s; } vector<int>decode(int(*const arr)(int),int n,int lim){ static unsigned a[100],b[100]; static ll x[1000],y[1000],ans[1000],e[1000]; for(int i=0;i<16;i++) { b[i]=arr(i); x[i]=b[i]%1000; y[i]=b[i]/1000; } for(int i=0;i<16;i++) ans[i]=0; for(int i=0;i<16;i++) { for(int j=0;j<16;j++) e[j]=0; e[0]=1; for(int j=0;j<16;j++) if(j!=i) { for(int k=15;k>=0;k--) { e[k+1]=(e[k+1]+e[k])%p; e[k]=-e[k]*x[j]%p; } } ll s=y[i]; for(int j=0;j<16;j++) if(j!=i) s=s*fp(x[i]-x[j],p-2)%p; for(int j=0;j<16;j++) { e[j]=e[j]*s%p; ans[j]=(ans[j]+e[j])%p; } } for(int i=0;i<16;i++) a[i]=(ans[i]+p)%p; vector<int>vec; for(int i=0;i<8;i++) vec.push_back((a[i*2+1]<<16)|a[i*2]); return vec; }