loj #6060. 「2017 山东一轮集训 Day1」Set

异或和一般都会想到01trie 或者线性基.

发现是在任意位置选取集合元素.

那么容易想到用线性基做.

考虑令s 等于所有数的异或和.

那么x1 ^ x2 = s

考虑怎么取得max(x1 + x2)且min(x1)

把s化为2进制.

对于s的某一位x,如果该位为0且有某一个数当前位为1,

则说明有偶数个数当前位为1,即可以把集合中s1s2分配进奇数个此位为1的数

那么此时的x1 x2都取到了最大值.

如果s的某一位x,如果该位为1.

则可以把所有当前位为1的都放入s2,

此时x1 不变,x2取到了最大...

最后求出x2的值,用s^x2即可求出x1

c++代码如下:

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x; i <= y ;++ i)
#define repd(i,x,y) for(register int i = x; i >= y ; --i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
    x = 0;char c;int sign = 1;
    do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
    x *= sign;
}

ll a[101000],n,s,ans;
bool p[100];

void print(ll x)
{
	int k[100],cnt = 0;
	while(x)
	{
		k[++cnt] = x &1;
		x >>= 1;
	}
	repd(i,cnt,1) printf("%d",k[i]);
	puts("");
}

int main()
{
	read(n);
	rep(i,1,n) read(a[i]),s ^= a[i];
	repd(i,63,0)
		rep(j,1,n)
			if(!p[j] && (a[j] & (1LL << i)) && !(s & (1LL << i))){
				p[j] = 1;
				if(!(ans & (1LL << i))) ans ^= a[j];
				rep(k,1,n) if((a[k] & (1LL << i)) && !p[k]) a[k] ^= a[j];
				break;
			}
	repd(i,63,0)
		rep(j,1,n)
			if(!p[j] && (a[j] & (1LL << i)) && (s & (1LL << i))){
				p[j] = 1;
				if(!(ans & (1LL << i))) ans ^= a[j];
				rep(k,1,n) if((a[k] & (1LL << i)) && !p[k]) a[k] ^= a[j];
				break;
			}
	
	cout << (s ^ ans) << endl;
	
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值