loj 114
loj114 k大异或和
1 题目描述
给定一个有n个元素组成的集合,每次给定一个数k,求一个集合\(T,T\in S\),使得T在S的所有非空子集的不同的异或和中,其异或和$T_1 xor T_2 xor T_3...xor T_p $是第k小的。
2 思路
本题其实就是就是一个线性基的问题,题目恶心的在于要非空子集,这个也就是如果子集可以异或为0,那么0是可以存在的,但是如果非空子集不能异或为0,0是不能存在的。
假设我们当前要求第x大的数,我们考虑当前的\(ans \space xor \space d[i]\)是否大于\(ans\),如果大于,那么看x是否大于接下来的可能性数量,如果大于,就x减去可能性数量,否则就把\(d[i]\)异或到\(ans\)里面。 同理,如果当前的\(ans \space xor \space d[i]\)小于\(ans\),那么就还是不要异或比较大。
每次构造的时间复杂度不超过\(O(50)\)。
3 代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100003
ll d[60],n,m,x,tot,one=1,num[60],wy;
int add(ll x){
for(ll i=50;i>=0;i--)
if(x&(one<<i)){
if(!d[i]){
d[i]=x;
return 1;
}else x^=d[i];
}
wy=1;
return 0;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
tot+=add(x);
}
if(d[0]) num[0]=1;
for(int i=1;i<=50;i++)
num[i]=num[i-1]+(d[i]>0);
cin>>m;
while (m--){
cin>>x;
if(!wy && x>(one<<num[50])-1 || wy && x>(one<<num[50])){
printf("-1\n");
continue;
}
if(!wy) x++;
x=(one<<num[50])-x+1;
ll ans=0;
for(int i=50;i>=0;i--) {
if(d[i]==0) continue;
ll t;
if(i) t=one<<num[i-1];
else t=1;
if((ans^d[i])>ans)
{
if(x>t)
x-=t;
else ans^=d[i];
}else {
if(x>t)
x-=t,ans^=d[i];
}
}
printf("%lld\n",ans);
}
return 0;
}