[BZOJ 2844] albus就是要第一个出场

Description

判断一个异或值是第几小。

Solution

允许有空集存在,则能够异或出的 \(0\) 的个数为 \(2^{n-cnt}\),其中 \(n\) 为插入的数字个数,\(cnt\) 为线性基中的元素个数。

二进制拆分,每个不同的异或值都会出现 \(2^{n-cnt}\) 次,输出时乘上即可。

Code

#include <cstdio>
#include <cstring>

const int mod = 10086;
int T, n, x, cnt = -1, ans, zero, id[35], p[35];

void insert(int x) {
    for (int i = 30; ~i; --i) {
        if (!(x >> i)) continue;
        if (!p[i]) { p[i] = x; break; }
        x ^= p[i];
    }
}
void rebuild() {
    for (int i = 30; ~i; --i)
        for (int j = i - 1; ~j; --j)
            if (p[i] & (1 << j)) p[i] ^= p[j];
    for (int i = 0; i <= 30; ++i)
        if (p[i]) id[i] = ++cnt;
}
int pow(int a, int b) {
    int res = 1;
    for (; b; b >>= 1, a = a * a % mod)
        if (b & 1) res = res * a % mod;
    return res;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &x), insert(x);
    rebuild();
    scanf("%d", &x), zero = pow(2, n - cnt - 1);
    for (int i = 0; i <= 30; ++i)
        if (((x >> i) & 1) && p[i]) ans = (ans + (1 << id[i])) % mod;
    printf("%d\n", (ans * zero + 1) % mod);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fly-in-milkyway/p/10014566.html