1. 程式人生 > >【線性基】HDU3949[XOR]題解

【線性基】HDU3949[XOR]題解

題目概述

給出 n 個數,求選出的非空集合中異或和第 k 小的異或和(異或和相同算一次),沒有 k 個輸出 1

解題報告

如果構造線性基時將矩陣消成對角矩陣,得到的線性基就有一個很棒的性質:最高位為 i 的數至多隻有一個,且其他數第 i 位為 0 (即使得到的線性基無法表示為對角矩陣,只要按照消成對角矩陣的方法去構造,也滿足這個性質)。

因為最高位為 i 的數至多隻有一個,所以挑出矩陣中的非零項 {Bm}i=0m1Bi(kand2i) 就是答案。

解題報告

#include<cstdio>
#include<cstring>
typedef long long LL; using namespace std; const int Log=60; int te,n,Q;LL M[Log],B[Log]; inline void Insert(LL x){ for (int j=Log;~j;j--) if (x>>j&1) if (M[j]) x^=M[j]; else{ M[j]=x;for (int k=0;k<j;k++) if (M[j]>>k&1) M[j]^=M[k]; for
(int k=j+1;k<Log;k++) if (M[k]>>j&1) M[k]^=M[j];break; } } int main(){ freopen("program.in","r",stdin); freopen("program.out","w",stdout); for (int i=(scanf("%d",&te),1);i<=te;i++){ printf("Case #%d:\n",i);scanf("%d",&n);memset(M,0,sizeof(M));B[0
]=0; for (int i=1;i<=n;i++) {LL x;scanf("%lld",&x);Insert(x);} for (int i=0;i<Log;i++) if (M[i]) B[++B[0]]=M[i]; for (scanf("%d",&Q);Q;Q--){ LL x,ans=0;int pos=0;scanf("%lld",&x);x-=B[0]<n; while (x) {pos++;if (x&1) ans^=B[pos];x>>=1;} if (B[0]<pos) puts("-1"); else printf("%lld\n",ans); } } return 0; }