链接: 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: ",cas++); scanf("%d",&m); while(m--){ ll k; scanf("%lld",&k); printf("%lld ",LB.K_Min(k)); } } return 0; }