【线性基】Petrozavodsk Winter Training Camp 2018 Day 1: Jagiellonian U Contest, Tuesday, January 30, 2018 Problem A. XOR

题意:给你一些数,问你是否能够将它们划分成两个集合,使得这两个集合的异或和之差的绝对值最小。

设所有数的异或和为S,集合A的异或和为A。

首先,S的0的位对答案不造成影响。

S的最高位1,所对应的A的那一位一定可以为1,不妨设它为1。

然后考虑后面的S的1位,尽量使A对应的位置为0,这样才能使S xor A,即B的值最大化,最接近A。

用线性基来进行判定,看能否将最高位到目前这位(假定目前这位是0)的这个区间用给定的数线性表出,如果能,就将这位设成0,否则,就将这位设成1。

妈的,其实整个过程只需要取出最大的线性基,然后尽量用较小的线性基去消掉除了最高位以外的1即可,得到的就是A!

队友的代码:

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for (LL i=(a);i<=(b);++i)
#define ROF(i,b,a) for (LL i=(b);i>=(a);--i)
typedef long long LL;
LL read(){
	LL x=0,f=1; char ch=getchar();
	while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
	while (ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
	return x*f;
}

const LL MAXN=300005;
LL n,m,q,a[MAXN],b[MAXN],c[MAXN],f[100];
int main() {
	LL T=read();
	while (T--) {
		n=read(); m=0;
		FOR(i,1,n) m^=a[i]=read();
		FOR(i,1,n) a[i]&=m;
		memset(f,0,sizeof(f));
		FOR(i,1,n) {
			ROF(j,62,0)
			if ((a[i]>>j)&1) {
				if (!f[j]) { f[j]=a[i]; break; }
				else {
					//if (a[i]<f[j]) swap(a[i],f[j]);
					a[i]^=f[j];
				}
			}
		}
		LL x=-1,y=0;
		ROF(i,62,0) if (f[i]) { x=i; break; }
		if (x>=0) y=f[x];
		//cerr<<y<<' '<<m<<endl;
		ROF(i,x-1,0)
		if (f[i])
			if ((y>>i)&1) y^=f[i];
		cout<<abs(y-(y^m))<<endl;
	}
	return 0;
}

/*
2
4
1 2 3 4
5
3 7 3 9 5

*/
posted @ 2018-04-15 20:14  AutSky_JadeK  阅读(409)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト