题目描述
这是一道模板题。
给由 n nn 个数组成的一个可重集 S SS,每次给定一个数 k kk,求一个集合 T⊆S T \subseteq ST⊆S,使得集合 T TT 在 S SS 的所有非空子集的不同的异或和中,其异或和 T1xorT2xor…xorT|T| 是第 k kk 小的。
输入格式
第一行一个数 n nn。
第二行 n nn 个数,表示集合 S SS。
第三行一个数 m mm,表示询问次数。
第四行 m mm 个数,表示每一次询问的 k kk。
输出格式
输出 m mm 行,对应每一次询问的答案,第 k kk 小的异或和。如果集合 S SS 的所有非空子集中,不同的异或和数量不足 k kk,输出 −1 -1−1。
样例
样例输入
3
1 2 3
5
1 2 3 4 5
样例输出
0
1
2
3
-1
数据范围与提示
1≤n,m≤105,0≤Si≤250 1 \leq n, m \leq 10 ^ 5, 0 \leq S_i \leq 2 ^ {50}1≤n,m≤105,0≤Si≤250
题意:给N个数和M个询问,找出这N个数任意异或的第K小的数。
思路:首先构造个线性基,因为异或的大小和最高位的1有关,所以改造一下线性基,使得bit[i]不为0时,只有bit[i]的第i位是1,这样就能直接构造出第K小的值了,注意0要特判。
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL bit[64], a[64], x, k;
int main(){
int n, m, cnt=0;
scanf("%d",&n);
for(int i=0; i<n; ++i){
scanf("%lld",&x);
for(int j=50; ~j; --j){
if(x&(1LL<<j)){
if(!bit[j]) {bit[j] = x; break;}
x ^= bit[j];
}
}
}
for(int i=50; ~i; --i)
for(int j=i-1; ~j; --j)
if(bit[i]&(1LL<<j)) bit[i] ^= bit[j];
for(int i=0; i<=50; ++i)
if(bit[i]) a[cnt++] = bit[i];
scanf("%d",&m);
while(m--){
scanf("%lld",&k);
if(cnt != n) --k;
if(k >= (1LL<<cnt)) puts("-1");
else{
LL ans = 0;
for(int i=0; i<cnt; ++i)
if(k&(1LL<<i)) ans ^= a[i];
printf("%lld\n",ans);
}
}
return 0;
}