集合

【问题描述】

小明非常喜欢数字。最近他的妈妈送给他了一个由n个非负整数组成的集合。小明非常喜欢和小刚玩。他立即决定把他n个数字中的一部分送给小刚。为了让游戏更加有趣,小明决定使得给她的数字集合满足如下条件:

我们用x1表示小明的数字集合的xor值,用x2表示小刚的数字集合的xor值。要使得x1+x2尽可能地大。假如有多种划分集合的方法使得集合满足上述条件,小明就要让x1尽可能地小。

帮助小明照上述方法划分集合。如果有多种合适的方法,就找出其中任意一种方法。请注意,小明将一部分数字给了小刚之后,他可能就没有任何剩余的数字了。反之亦然,小明也可以不给小刚任何数字。在这两种情况下,我们都假定空集的xor值为0。

【输入格式】

从文件set.in中输入数据。

输入的第一行包含一个整数n,表示小明的妈妈给了他多少个数字。

第二行包含n个用空格隔开的数字,保证它们都是不超过10^18的非负整数。

【输出格式】

输出到文件set.out中。

输出一行,包含n个用空格隔开的整数,如果第i个数是1,则表示小明保留给出的第i个数字,如果第i个数是2,则表示小明把给出的第i个数字给了小刚。

【样例输入】

8

1 1 2 2 3 3 4 4

【样例输出】

1 2 1 2 2 2 1 2

 

 

【数据规模与约定】

对于30%的数据,保证n<=10;

对于60%的数据,保证n<=1000;

对于100%的数据,保证n<=100000。

 

这道题需要按位考虑。如果总体异或和的某一位是0,那么肯定分成的x1和x2这一位都是1。

先考虑为0的,后考虑为1的是最优策略。

相当于每一步我们都扔进去一个异或方程组,直接消元,线性相关肯定就扔掉了。

用bitset压位一下就好了。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define M 100010
 4 #define LL long long
 5 inline LL read() {
 6     char ch = getchar(); LL x = 0, f = 1;
 7     while(ch < '0' || ch > '9') {
 8         if(ch == '-') f = -1;
 9         ch = getchar();
10     }
11     while('0' <= ch && ch <= '9') {
12         x = x * 10 + ch - '0';
13         ch = getchar();
14     }
15     return x * f;
16 }
17 LL A[M];
18 bitset<100010> a[110];
19 int pos[M];
20 int res[M];
21 int tot;
22 int main() {
23     int n; scanf("%d", &n);
24     LL All = 0;
25     for(int i = 0; i < n; ++ i) {
26         A[i] = read();
27         All ^= A[i];
28     }
29     for(int k = 0; k < 2; ++ k) {
30         for(int i = 60; i >= 0; -- i) if((All >> i & 1) == k){
31             ++ tot;
32             for(int j = 0; j < n; ++ j) if((A[j] >> i & 1)){
33                 a[tot][j] = 1;
34             }
35             a[tot][n] = k ^ 1;
36             for(int j = 1; j < tot; ++ j) {
37                 if(a[tot][pos[j]]) a[tot] ^= a[j];
38             }
39             pos[tot] = -1;
40             for(int j = 0; j < n; ++ j) {
41                 if(a[tot][j]) {
42                     pos[tot] = j;
43                     break;
44                 }
45             }
46             if(pos[tot] == -1) {
47                 -- tot; continue;
48             }
49             for(int j = 1; j < tot; ++ j) {
50                 if(a[j][pos[tot]]) a[j] ^= a[tot];
51             }
52         }
53     }
54     for(int i = 1; i <= tot; ++ i) {
55         res[pos[i]] = a[i][n];
56     }
57     for(int i = 0; i < n; ++ i) {
58         printf("%d ", 2 - res[i]);
59     }
60 }
原文地址:https://www.cnblogs.com/iamqzh233/p/10079281.html