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; 
} 
posted @ 2020-08-16 21:37  zjxxcn  阅读(271)  评论(0编辑  收藏  举报