loj #114. k 大异或和

#114. k 大异或和

 

题目描述

这是一道模板题。

给由 n nn 个数组成的一个可重集 S SS,每次给定一个数 k kk,求一个集合 T⊆S T \subseteq STS,使得集合 T TT 在 S SS 的所有非空子集的不同的异或和中,其异或和 T1xorT2xorxorT|T| 是第 k kk小的。

输入格式

第一行一个数 n nn。
第二行 n nn 个数,表示集合 S SS。
第三行一个数 m mm,表示询问次数。
第四行 m mm 个数,表示每一次询问的 k kk。

输出格式

输出 m mm 行,对应每一次询问的答案,第 k kk 小的异或和。如果集合 S SS 的所有非空子集中,不同的异或和数量不足 k kk,输出 −1 -11。

样例

样例输入

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}1n,m105​​,0Si​​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;
}

 

posted @ 2018-04-14 16:13  Echo宝贝儿  阅读(596)  评论(0)    收藏  举报