loj #114. k 大异或和
#114. k 大异或和
题目描述
这是一道模板题。
给由 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
#include<iostream> #include<cstdio> #include<cstring> #define maxn 100010 using namespace std; int n,tot,m,cnt; long long a[maxn],b[51],p[51]; long long query(long long k){ if(!k)return 0; if(k>=(1LL<<cnt))return -1; long long res=0; for(int i=0;i<=cnt;i++)if((k>>i)&1)res^=p[i]; return res; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<=n;i++) for(int j=50;j>=0;j--) if((a[i]>>j)&1){ if(b[j])a[i]^=b[j]; else { b[j]=a[i];cnt++; for(int k=j-1;k>=0;k--)if((b[j]>>k)&1)b[j]^=b[k]; for(int k=j+1;k<=50;k++)if((b[k]>>j)&1)b[k]^=b[j]; break; } } for(int i=0;i<=50;i++)if(b[i])p[tot++]=b[i]; int w=cnt<n; scanf("%d",&m); while(m--){ long long k;cin>>k; if(w)k--; cout<<query(k)<<endl; } return 0; }