hdu3949 XOR(線性基【第k大)
阿新 • • 發佈:2019-01-11
分析:
求第k大:把k二進位制拆分,如果k的第i位上是1,ans^=b[i]
這是什麼道理呢?
異或消元最後得到的是一組基
給出n個數能夠異或出來的值,都是這些基線性組合形成的數
方便起見,我們把矩陣消成對角線型(比較好理解)
這樣1只會出現在對角線上
:對角線上有多少個1
顯然我們能得到個不同的異或值(包括0)
然而存在一個問題:0是否真的可行
我們需要特殊處理一下0:
如果,就說明每個數字都有會貢獻1個1,那麼就絕對不可能取到0
if (cnt==n) x++; //0不可以達到
在最後統計答案的時候,我們預設0可以達到
所以只有x>now的時候才統計
這樣最後的x應該是等於1,這個1就是給0留的位置
for (int i=63;i>=0;--i) {
if(b[i]) {
ll now=(1LL<<(tmp-1));
if(x>now) x-=now,ans^=b[i];
tmp--;
}
}
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=10005 ;
int n,m,K;
ll a[N],b[100];
void cal() {
for (int i=1;i<=n;i++)
for (int j=63;j>=0;j--)
if (a[i]>>j&1) {
if (b[j]) a[i]^=b[j];
else {
b[j]=a[i];
for (int k=j-1;k>=0;k--)
if (b[k]&&(b[j]>>k&1)) b[j]^=b[k];
for (int k=j+1;k<=63;k++)
if (b[k]>>j&1) b[k]^=b[j];
break;
}
}
}
int main()
{
int T;
scanf("%d",&T);
for (int cas=1;cas<=T;cas++) {
memset(b,0,sizeof(b));
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
cal();
int cnt=0;
for (int i=0;i<=63;i++) if (b[i]) cnt++; //一共能組成(1<<cnt)個不同的數
scanf("%d",&m);
printf("Case #%d:\n",cas);
for (int i=1;i<=m;i++) {
ll x;
scanf("%lld",&x);
if (cnt==n) x++; //0不可以達到
if (x>(1LL<<cnt)) {printf("-1\n");continue;}
ll ans=0;
int tmp=cnt;
for (int i=63;i>=0;--i) {
if(b[i]) {
ll now=(1LL<<(tmp-1));
if(x>now) x-=now,ans^=b[i]; //x>now (0也要算上)
tmp--;
}
}
printf("%lld\n",ans);
}
}
return 0;
}