Codeforces

分析

这个数量平方的异或和感觉没有什么性质,那么我们只能想办法对每个集合求出数量。

一个想法是先预处理出集合大小为 $1$ 时的数量,然后做子集和,但是这样子会算重:对于 $abc$,$ab$ 处将其计算了两次。

于是考虑容斥:我们在 $a, b, c$ 处加 $1$,$ab, ac, bc$ 处减 $1$、$abc$ 处加 $1$,那么这样子做子集和求出来的数量就是正确的了。

如果有 $y$ 或 $z$,直接忽略掉即可。

其实容斥还是麻烦了,事实上可以直接子集和求出不含任何元音字母的数量,然后减一下就是答案了。

代码

这个是容斥的版本。

// ====================================
//   author: M_sea
//   website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define popcount __builtin_popcount
using namespace std;
typedef long long ll;

int read() {
    int X = 0, w = 1; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
    while (c >= '0' && c <= '9') X = X * 10 + c - '0', c = getchar();
    return X * w;
}

int n, f[1 << 24];

void FWT(int *A, int n) {
    for (int i = 1; i < n; i <<= 1)
        for (int j = 0; j < n; j += i << 1)
            for (int k = 0; k < i; ++k)
                A[j + k + i] += A[j + k];
}

int main() {
    n = read();
    for (int i = 1; i <= n; ++i) {
        char s[5]; scanf("%s", s);
        for (int S = 1; S < 8; ++S) {
            int flag = 1, T = 0;
            for (int i = 0; i < 3; ++i) {
                if (S & (1 << i)) {
                    if (s[i] > 'x') { flag = 0; break; }
                    T |= (1 << (s[i] - 'a'));
                }
            }
            if (!flag) continue;
            if (popcount(S) & 1) ++f[T];
            else --f[T];
        }
    }
    FWT(f, 1 << 24);
    int ans = 0;
    for (int S = 1; S < 1 << 24; ++S) ans ^= f[S] * f[S];
    printf("%d\n", ans);
    return 0;
}
最后修改:2021 年 04 月 06 日 07 : 12 PM