题意:n个数,q个询问,问这n个数的子集异或和中,第k小的异或和等于多少。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=10005;
const int maxbit=63;
ll A[N];
ll P[maxbit];
ll L[maxbit];
int main(){
int t;
scanf("%d",&t);
for(int kase=1;kase<=t;++kase){
printf("Case #%d:\n",kase);
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%lld",&A[i]);
}
memset(P,0,sizeof P);
//处理出线性基P
for(int i=1;i<=n;++i){
for(int j=maxbit-1;j>=0;--j){//63位longlong
if((A[i]>>j)&1){
if(P[j]==0){
P[j]=A[i];
break;
}else{
A[i]^=P[j];
}
}
}
}
//为了求第k小 先对线性基作这样的处理
for(int i=maxbit-1;i>=0;--i){// 对于P[i](最高位1在第i位的某线性基) 对每一个 最高位1的位置大于i的数 P[j=i+1,maxbit) 从[i+1,maxbit) 如果第i位是1 就异或上P[i]
for(int j=i+1;j<maxbit;++j){
if( ( (P[j]>>i) &1 ) )//P[j]第i位是1
P[j]^=P[i];//消掉P[j]第i位的1
//P[i]变成了P数组中唯一的 第i位是1的数 P中其他数的第i位都是0
}
}
int m=0;
for(int i=0;i<maxbit;++i){
if(P[i]){
L[m++]=P[i];//1在第i位的线性基P[i] 按i从小到大存在L[]里
}
}
//求第k小 对k的二进制 枚举L
int Q;
scanf("%d",&Q);
while(Q--){
ll k;
scanf("%lld",&k);//第k小
if(n!=m) k--;//如果数组的元素个数n不等于线性基的个数m 能异或出0 0是第1小
if( k >= 1LL<<m ){//m个线性基能异或出的数量 2^m-1
puts("-1");
}else{
ll ans=0;
for(int j=0;j<maxbit;++j){
if((k>>j)&1)//二进制枚举 从低到高 能求出第k小
ans^=L[j];
}
printf("%lld\n",ans);
}
}
}
return 0;
}
绝了,已全部理解,多不容易,一定要牢牢背住。