HDU - 3949 :XOR(线性基,所有集合的不同异或和中,求从小到大第K个)
InputFirst line of the input is a single integer T(T<=30), indicates there are T test cases.
For each test case, the first line is an integer N(1<=N<=10000), the number of numbers below. The second line contains N integers (each number is between 1 and 10^18). The third line is a number Q(1<=Q<=10000), the number of queries. The fourth line contains Q numbers(each number is between 1 and 10^18) K1,K2,......KQ.OutputFor each test case,first output Case #C: in a single line,C means the number of the test case which is from 1 to T. Then for each query, you should output a single line contains the Ki-th smallest number in them, if there are less than Ki different numbers, output -1.Sample Input
2 2 1 2 4 1 2 3 4 3 1 2 3 5 1 2 3 4 5
Sample Output
Case #1: 1 2 3 -1 Case #2: 0 1 2 3 -1
题意:给定N个数,所有集合的不同异或和中,求从小到大第K个,不存在则输出-1。
思路:我们知道线性基可以表示用不超过64个数,表示出所有集合的异或和,那么为0的部位不考虑,我们求第K个,就是等效表示成二进制。。。ok了。
先求线性基,得到p数组。然后把为0的忽略,并且前面的p对后面的效果求出来。 有个注意的问题就是0,因为线性基我们没有考虑0,所以0单独考虑,如果线性基的大小和原数组大小一样,则可以表示出来,那么K--;
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) #define rep2(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=100010; ll p[66],x; int main() { int T,N,Q,Cas=0; scanf("%d",&T); while(T--){ scanf("%d",&N); rep(i,0,63) p[i]=0; rep(i,1,N) { scanf("%lld",&x); rep2(j,63,0){ if(x&(1LL<<j)){ if(p[j]) x^=p[j]; else { p[j]=x;break;} } } } ll num=0,ans,K; rep(i,0,63) if(p[i]){ p[num++]=p[i]; rep(j,i+1,63) if((p[j]>>i)&1) p[j]^=p[i]; } scanf("%d",&Q); printf("Case #%d:\n",++Cas); while(Q--){ scanf("%lld",&K); if(N!=num) K--; //here,notice!考虑0的存在性 if(K>=(1LL<<num)) puts("-1"); else { ans=0; rep(j,0,63) { if(K&(1LL<<j)) ans^=p[j]; //不能加,还是用异或,可能有尾巴,相互抵消 } printf("%I64d\n",ans); } } } return 0; }