码迷,mamicode.com
首页 > 其他好文 > 详细

2019 Nowcoder Multi-University Training Contest 1 H-XOR

时间:2019-10-14 18:41:46      阅读:75      评论:0      收藏:0      [点我收藏+]

标签:ret   put   假设   for   答案   continue   c11   cli   alt   

 

由于每个元素贡献是线性的,那么等价于求每个元素出现在多少个异或和为$0$的子集内。因为是任意元素可以去异或,那么自然想到线性基。
先对整个集合A求一遍线性基,设为$R$,假设$R$中元素个数为$r$,那么任取一个不在$R$内的元素,$R$中肯定存在一种取法能和这个元素异或和为$0$。
同理,取定一个不在$R$内的元素,再随便取另外任意个不在$R$内的元素,$R$内仍然存在一种取法使得这个异或和为$0$。那么每个不在$R$内的元素包含在$2^{n - r - 1}$个集合内(其他不在$R$内的元素可以任取)。所以所有不在$R$内的元素对答案的贡献就是$\left(n - r + 1\right) \times 2^{n - r + 1}$。
考虑在$R$内的元素,最多只有$62$个元素。它们对答案的贡献其实就跟上面的一样。
对不在线性基内的元素求一遍线性基,设为$other$,这样其实就缩成了$2$个包含$62$个元素的集合。枚举$R$的每个元素$a_i$,把其他$123$个元素加入一个线性基中,设这个线性基为$temp$,元素个数为$r‘$,最后看$a_i$能否加入线性基中,如果不行就说明$temp$能让它异或和为$0$。同理可得对答案的贡献为$2^{n - r‘ - 1}$。
其实到这我只check了$a_i$能否加入$temp$,并没有check另外$n - r‘ - 1$个元素能否加入$temp$,但是其实在之前已经check过了,对于在$R$内和$other$的其他元素显然,因为我暴力枚举了它们去加入$temp$。对于其他元素其实都已经在得到$R$和$other$的时候尝试着让它们加入$R$和$other$,那么它们其实也是不能加入$temp$的。

 

技术图片
#include <bits/stdc++.h>
#define ll long long
using namespace std;
 
const int sz = 70;
const int N = 1e5 + 10;
const ll MOD = 1e9 + 7;
bool vis[N];
vector<ll> G;
ll a[N], bin[N];
 
struct XO {
    ll p[sz];
    void init() {
        memset(p, 0, sizeof(p));
    }
    bool ins(ll x) {
        for (int i = 62; ~i; i--)
            if (x >> i & 1) {
                if (!p[i]) { p[i] = x; return true; }
                x ^= p[i];
            }
        return false;
    }
} R, other, temp;
 
int main() {
    int n;
    bin[0] = 1;
    for (int i = 1; i < N; i++) bin[i] = bin[i - 1] * 2 % MOD;
    while (~scanf("%d", &n)) {
        R.init(); other.init();
        G.clear();
        int r = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            vis[i] = 0;
            if (R.ins(a[i])) {
                r++;
                vis[i] = 1;
                G.push_back(a[i]);
            }
        }
        if (r == n) {
            puts("0");
            continue;
        }
        ll ans = (n - r) * bin[n - r - 1] % MOD;
        for (int i = 1; i <= n; i++) {
            if (!vis[i]) other.ins(a[i]);
        }
        for (auto x: G) {
            int tol = 0;
            temp.init();
            for (auto y: G) {
                if (x == y) continue;
                if (temp.ins(y)) tol++;
            }
            for (int i = 0; i <= 62; i++) {
                if (temp.ins(other.p[i])) tol++;
            }
            if (!temp.ins(x)) ans = (ans + bin[n - tol - 1]) % MOD;
        }
        printf("%lld\n", ans);
    }
    return 0;
}
View Code

 

2019 Nowcoder Multi-University Training Contest 1 H-XOR

标签:ret   put   假设   for   答案   continue   c11   cli   alt   

原文地址:https://www.cnblogs.com/Mrzdtz220/p/11673051.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!