码迷,mamicode.com
首页 > 其他好文 > 详细

【线性基】hdu3949 XOR

时间:2017-09-12 01:23:52      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:cst   uil   turn   stdin   ase   main   mem   插入   query   

给你n个数,问你将它们取任意多个异或起来以后,所能得到的第K小值?

求出线性基来以后,化成简化线性基,然后把K二进制拆分,第i位是1就取上第i小的简化线性基即可。注意:倘若原本的n个数两两线性无关,也即线性基的大小恰好为n时,异或不出零,否则能异或出零,要让K减去1。

这也是线性基的模板。

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
ll d[64],p[64];
int cnt;//简化线性基的大小
bool Insert(ll val){//尝试插入线性基,返回是否插入成功
	for(int i=62;i>=0;--i){
		if(val&(1ll<<i)){
			if(!d[i]){
				d[i]=val;
				break;
			}
			val^=d[i];
		}
	}
	return val>0;
}
ll QueryMax(){
	ll res=0;
	for(int i=62;i>=0;--i){
		if((res^d[i])>res){
			res^=d[i];
		}
    }      
	return res;
}
ll QueryMin(){
	for(int i=0;i<=62;++i){
		if(d[i]){
			return d[i];
		}
	}
	return 0;
}
void Rebuild(){//化为简化线性基
	for(int i=62;i>=0;--i){
		for(int j=i-1;j>=0;--j){
			if(d[i]&(1ll<<j)){
				d[i]^=d[j];
			}
		}
	}
	for(int i=0;i<=60;++i){
		if(d[i]){
			p[cnt++]=d[i];
		}
	}
}
int T,n,m;
ll Kth(ll K){
	if(cnt<n){
		--K;//如果并非原本的n个数都线性无关的话,那么是能异或出零的
	}
	ll res=0;
	if(K>=(1ll<<cnt)){
		return -1ll;
	}
	for(int i=60;i>=0;--i){
		if(K&(1ll<<i)){
			res^=p[i];
		}
	}
	return res;
}
int main(){
//	freopen("hdu3949.in","r",stdin);
	ll x;
	scanf("%d",&T);
	for(int zu=1;zu<=T;++zu){
		memset(d,0,sizeof(d));
		memset(p,0,sizeof(p));
		cnt=0;
		printf("Case #%d:\n",zu);
		scanf("%d",&n);
		for(int i=1;i<=n;++i){
			scanf("%lld",&x);
			Insert(x);
		}
		Rebuild();
		scanf("%d",&m);
		for(;m;--m){
			scanf("%lld",&x);
			printf("%lld\n",Kth(x));
		}
	}
	return 0;
}

【线性基】hdu3949 XOR

标签:cst   uil   turn   stdin   ase   main   mem   插入   query   

原文地址:http://www.cnblogs.com/autsky-jadek/p/7508067.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!