考虑贪心
按照位从高到低考虑,假设当前正在考虑第i位
如果第i位是1的数有奇数个,那么无论怎么分配,总会有一个人拿到奇数个,另一个人拿到偶数个,所以X1和X2的第i位一定有一个是1,另一个是0,无论怎么分配都是不会影响X1+X2的
如果第i位是1的数有偶数个,那么要么两个人都拿偶数个,这时X1和X2的第i位都是0,要么两个人都拿奇数个,这时X1和X2的第i位都是1,后者的X1+X2肯定是大于前者的,由二进制的性质可得,只要能满足后者,就一定应该满足
考虑怎样描述这样的一个限制;我们设第i位是1的数的下标是
a1
a
1
,
a2
a
2
…
ak
a
k
,对每一个位置记录一个
Xi
X
i
,
Xi=1
X
i
=
1
表示这个数分给第一个人,
Xi=0
X
i
=
0
表示分给第二个人,这样我们的限制条件可以写成这样:
xa1⨁xa2⨁...⨁xak=1
x
a
1
⨁
x
a
2
⨁
.
.
.
⨁
x
a
k
=
1
这样的一些异或方程组可以用高斯消元搞,每次添一个方程,检查是否还有解
注意添加一个新方程后,不要把整个方程组解一遍,只要对新方程消元就好了
用bitset压位,总复杂度
O(n∗64)
O
(
n
∗
64
)
*感觉学完线性基以后,理解高斯消元更加深刻。感觉这两个东西其实很像
*判断方程无解的方法是:消元之后,如果有一个方程,左边全是0,右边不为0,则无解
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;
const int MOD=1e9+7;
const LL LINF=2e16;
const int INF=1e9;
const int magic=348;
const double eps=1e-10;
const double pi=3.14159265;
inline int getint()
{
char ch;int res;bool f;
while (!isdigit(ch=getchar()) && ch!='-') {}
if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
while (isdigit(ch=getchar())) res=res*10+ch-'0';
return f?res:-res;
}
inline LL getLL()
{
char ch;LL res;bool f;
while (!isdigit(ch=getchar()) && ch!='-') {}
if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
while (isdigit(ch=getchar())) res=res*10+ch-'0';
return f?res:-res;
}
typedef bitset<100048> bs;
struct equation
{
bs b;int res;
inline void init() {b=0;res=0;}
}cur;
map<int,equation> b;
bool exist[100048];
int n;
LL a[100048];
int maxbit;
int ans[148];
int sol[100048];
inline bool check()
{
int bit,i;
for (i=1;i<=n;i++)
if (cur.b[i])
if (exist[i]) cur.b^=b[i].b,cur.res^=b[i].res; else {b[i]=cur;exist[i]=true;return true;}
if (cur.res) return false; else return true;
}
inline void find_solution()
{
int i,j;
for (i=n;i>=1;i--)
{
if (!exist[i]) {sol[i]=0;continue;}
for (j=i+1;j<=n;j++)
if (b[i].b[j]) b[i].res^=sol[j];
sol[i]=b[i].res;
}
}
int main ()
{
int i,bit;n=getint();
for (i=1;i<=n;i++) a[i]=getLL();
for (maxbit=63;maxbit;maxbit--)
{
bool f=false;
for (i=1;i<=n;i++)
if (a[i]&(1ll<<(maxbit-1))) {f=true;break;}
if (f) break;
}
for (bit=maxbit;bit;bit--)
{
cur.init();
for (i=1;i<=n;i++)
if (a[i]&(1ll<<(bit-1))) cur.b[i]=1,cur.res++;
if (cur.res%2==1) {ans[bit]=1;continue;}
cur.res=1;
if (check()) ans[bit]=2; else ans[bit]=0;
}
for (bit=maxbit;bit;bit--)
if (ans[bit]==1)
{
cur.init();
for (i=1;i<=n;i++)
if (a[i]&(1ll<<(bit-1))) cur.b[i]=1;
cur.res=0;
check();
}
find_solution();
for (i=1;i<=n;i++) printf("%d ",2-sol[i]);
return 0;
}