HDU - 3949 XOR —— 線性基
阿新 • • 發佈:2018-11-12
題意:
詢問給定的數列裡第k大的異或和
思路:
線性基
將所有數插入線性基之後,所有62個數有的是0,其他數最高位1的位置不相同
用類似高斯消元的方法將線性基變為每個數只有最高位1,這樣就可以方便的求出第k大的異或
最大的異或值一定是這些裡面所有數的異或(全部能為1的位置都是1),第二大的異或值一定是最大的去掉最後一個1,依此類推(其實結果就是k的二進位制裡的1的下標對應的數的異或)
還有問題是0能不能被異或出來的,當高斯消元之後得到的數的個數和原來的n不相等時,0可以被異或出來,否則可以。
其實蠻好理解的,數量不相等說明有數線上性基的插入過程中被取消掉了,即它可以被其他數的異或得到,這時就會出現異或0
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <cstring> #include <algorithm> using namespace std; #define ll long long #define max_ 200100 #define mod 1000000007 #define inf 0x3f3f3f3f int n,q; int casnum=1; ll p[70]; void insert(ll n) { for(int i=62;i>=0;i--) { if((n>>i)&1) { if(p[i]) n=n^p[i]; else { p[i]=n; break; } } } } int main(int argc, char const *argv[]) { int t; scanf("%d",&t); while(t--) { printf("Case #%d:\n",casnum++); memset(p,0,sizeof p); scanf("%d",&n); for(int i=1;i<=n;i++) { ll x; scanf("%lld",&x); insert(x); } for(int i=62;i>=0;i--) { if(p[i]) { for(int j=i+1;j<=62;j++) { if((p[j]>>i)&1) { p[j]=p[j]^p[i]; } } } } int l=0; for(int i=0;i<=62;i++) { if(p[i]) { p[l++]=p[i]; } } scanf("%d",&q); while(q--) { ll x; ll ans=0; scanf("%lld",&x); if(l!=n) x--; if(x==0) { printf("0\n"); continue; } if(x>=(1LL<<l)) { printf("-1\n"); continue; } for(int i=62;i>=0;i--) { if((x>>i)&1) { ans=ans^p[i]; } } printf("%lld\n",ans); } } return 0; }