【CF251D】Two Sets

【CF251D】Two Sets:

Philips非常喜欢数字。最近pwecar送给他了一个由n个非负整数组成的集合。Philips非常喜欢和Bing玩。他立即决定把他n个数字中的一部分送给Bing。为了让游戏更加有趣,Philips决定使得给她的数字集合满足如下条件:
我们用x1表示Philips的数字集合的xor值,用x2表示Bing的数字集合的xor值。要使得x1+x2尽可能地大。假如有多种划分集合的方法使得集合满足上述条件,Philips就要让x1尽可能地小。
Xor运算是“异或”,在Pascal语言中用”xor”表示,在C/C++/Java语言中用”^”表示。
帮助Philips按照上述方法划分集合。如果有多种合适的方法,就找出其中任意一种方法。请注意,Philips将一部分数字给了Bing之后,他可能就没有任何剩余的数字了。反之亦然,Philips也可以不给Bing任何数字。在这两种情况下,我们都假定空集的xor值为0。

n<=100000

题解:

这种题肯定是拆位来讨论了。

对于一位来说。

如果n个数在这一位共有奇数个1,

那么无论怎么分都是奇+偶=1,当然把偶的分给第一组会优一点。

如果n个数在这一位共有偶数个1,

那么分成奇+奇=2会优。

于是我们得出贪心策略。

先偶数的,从高到低。

列出方程,和已有的方程对消,如果这条方程消了以后无解或无限制,则去掉。

方程左边的系数就是每个数在这一位的值,右边是1。未知数的含义是是否分给第一组。

再考虑奇数,从高到低。

方程左边一样,不过右边是0。

用bitset优化可以快点。

时间复杂度: O(n log2n32)

Code:

#include<bitset>
#include<cstdio>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;

const int N = 1e5 + 5;

bitset<N> a[65], b[65];

int n, m, q[65], ans[N]; ll x;

int main() {
    scanf("%d", &n);
    fo(i, 1, n) {
        scanf("%lld", &x);
        int y = 0;
        while(x) a[++ y][i] = x & 1, x >>= 1;
    }
    fo(j, 0, 1) {
        fo(k, 0, 60) if(a[k].count() % 2 == j){
            b[++ m] = a[k]; b[m][0] = 1 - j;
            fo(i, 1, m - 1) if(b[m][q[i]]) b[m] ^= b[i];
            q[m] = n + 1;
            fo(i, 1, n) if(b[m][i]) {
                q[m] = i; break;
            }
            if(q[m] > n) {m --; continue;}
            fo(i, 1, m - 1) if(b[i][q[m]]) b[i] ^= b[m];
        }
    }
    fo(i, 1, m) ans[q[i]] = b[i][0];
    fo(i, 1, n) printf("%d ", 2 - ans[i]);
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值