分析
这个数量平方的异或和感觉没有什么性质,那么我们只能想办法对每个集合求出数量。
一个想法是先预处理出集合大小为 $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;
}