1. 程式人生 > >hdu 3949 XOR (線性基)

hdu 3949 XOR (線性基)

amp ems .cn clas bit 需要 http c++ ear

鏈接: http://acm.hdu.edu.cn/showproblem.php?pid=3949

題意:

給出n個數,從中任意取幾個數字異或,求第k小的異或和

思路:

線性基求第k小異或和,因為題目中可以出現異或和為0的情況,但線性基裏是不會出現異或和為0的情況,所以我們需要多處理下,將數字全插入到線性基中,如果無法插入也就代表會出現異或和為0的情況,那麽求第k小就應該變成求線性基中第k-1小。

實現代碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int M = 1e6+10
; struct Linear_Basis{ ll b[63],nb[63],tot; bool flag = 0; void init(){ flag = 0; tot = 0; memset(b,-1,sizeof(b)); memset(nb,0,sizeof(nb)); } void Insert(ll x){ for(int i = 62;i >= 0;i --){ if(x&(1LL<<i)){
if(b[i] == -1){ b[i] = x; return ; } x ^= b[i]; } } flag = 1; return ; } ll Max(ll x){ ll ret = x; for(int i = 62;i >= 0;i --) ret = max(ret,ret^b[i]);
return ret; } ll Min(ll x){ ll ret = x; for(int i = 0;i <= 62;i ++) if(b[i]) ret ^= b[i]; return ret; } void rebuild(){ for(int i = 62;i >= 0;i --){ if(b[i] == -1) continue; for(int j = i-1;j >= 0;j --){ if(b[j] == -1) continue; if(b[i]&(1LL<<j)) b[i]^=b[j]; } } for(int i = 0;i <= 62;i ++) if(b[i]!=-1) nb[tot++] = b[i]; } ll K_Min(ll k){ ll res = 0; if(flag == 1) k --; if(k == 0) return 0; if(k >= (1LL<<tot)) return -1; for(int i = 62;i >= 0;i --) if(k&(1LL<<i)) res ^= nb[i]; return res; } }LB; int main() { int cas = 1,t,n,m; cin>>t; while(t--){ LB.init(); cin>>n; ll x; for(int i = 1;i <= n;i ++){ cin>>x; LB.Insert(x); } LB.rebuild(); printf("Case #%d:\n",cas++); scanf("%d",&m); while(m--){ ll k; scanf("%lld",&k); printf("%lld\n",LB.K_Min(k)); } } return 0; }

hdu 3949 XOR (線性基)