您的位置:首页 > 其它

codeforces 251D

2016-04-08 22:25 246 查看

题目描述

给你n≤105n\leq10^5个数,让你分成两个集合,设第一个集合的数的异或值为x1x1,第二个集合的数的异或值为x2x2,空集的异或和定义为00,让你求一个使得x1+x2x1+x2的值最大,并且满足最大条件下x1x1的值最小的方案。

解题思路

首先你会发现,如果二进制中第ii位一共有奇数个11,那么这一位一定会给答案增加2i2^i的贡献,因为奇数个11分成两堆,一定有一堆为奇数个,一堆为偶数个。

如果二进制中第ii位有偶数个11,那么我肯定尽量使得两堆都分得奇数个11,那么这一位就会对答案贡献2∗2i2*2^i,而且肯定是尽量满足高位。

这样的话就可以得到6060个异或方程。

例如:

a1,1∗x1⊕a2,1∗x2⊕...⊕an,1∗xn=f1a_{1,1}*x_1⊕a_{2,1}*x_2⊕...⊕a_{n,1}*x_n=f_1



ai,ja_{i,j}表示第ii个数的第jj位是否为11,⊕⊕表示异或,若这一位一共有奇数个11,那么ff值为0,否则为1.

参考代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<bitset>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define maxn 100005
#define maxsq 62
#define ll long long
using namespace std;

bitset<maxn> f[maxsq+5],g[maxsq+5];

int n,tot;

int ans[maxn];

ll sum;

int p[maxsq+5];

int main(){
scanf("%d",&n);
fo(i,1,n) {
ll x;
scanf("%I64d",&x);
sum ^= x;
fo(j,0,maxsq)
if (x & (1ll << j)) g[j][i]=1;
}
fo(bit,0,1) {
fd(i,maxsq,0)
if (((sum >> i) & 1)==bit) {
f[++tot]=g[i];
if (bit==0) f[tot][n+1]=1;
else f[tot][n+1]=0;
fo(j,1,tot-1)
if (f[tot][p[j]]) f[tot] ^= f[j];
p[tot]=n+2;
fo(j,1,n)
if (f[tot][j]) {
p[tot]=j;
break;
}
if (p[tot]>n) {
tot--;
continue;
}
fo(j,1,tot-1)
if (f[j][p[tot]]) f[j] ^= f[tot];
}
}
fo(i,1,tot) ans[p[i]]=f[i][n+1];
fo(i,1,n) printf("%d ",2-ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: