​传送门​

现在给出 n n n个长度为三,由前 24 24 24个字母组成的字符串

如果一个字符串包含至少一个元音我们说这个字符串是正确的

现在让你规定每个字母是否是元音

对于元音的 2 24 2^{24} 224种组合,计算所有组合[ 正确单词平方 ]的异或和


把 n n n个字符串压缩成 24 24 24位的二进制数字,把元音的组合也这样压缩

那么预处理一个 a x a_x ax表示二进制为 x x x的字符有 a x a_x ax个

当元音组合的二进制是 m a s k mask mask时,需要知道所有与 m a s k mask mask有交集的 x x x的 f [ m a s k ] = ∑ a x f[mask]=\sum a_x f[mask]=∑ax

这样答案就是 f [ 0 ] 2 ⊕ f [ 1 ] 2 . . . . . . . f[0]^2\oplus f[1]^2....... f[0]2⊕f[1]2.......

但是我们处理不出这样的 f f f数组…

但是使用 S O S D P SOSDP SOSDP可以快速处理 f [ m a s k ] f[mask] f[mask]表示所有 m a s k mask mask子集的 ∑ a x \sum a_x ∑ax

那么和 m a s k mask mask没有交集的数目就是: f [ ∼ m a s k ] f[\sim mask] f[∼mask]

那么 n − f [ ∼ m a s k ] n-f[\sim mask] n−f[∼mask]就是和 m a s k mask mask有交集的数目

经过这个奇妙的转化,只需要用 s o s d p sosdp sosdp的模板即可快速得解


然后还有另一种理解思路,就是先求所有不正确的字符串个数

我们令 m a s k mask mask为非元音字母的状态

也就是求 f [ m a s k ] f[mask] f[mask]表示所有是 m a s k mask mask子集的 ∑ a x \sum a_x ∑ax

那么这些 f [ m a s k ] f[mask] f[mask]都是不正确的,因为都被非元音包括了

拿 n n n减去即可​​别人写的博客​


然后还有一种容斥的做法别问我为什么那么多做法你一个都不知道

正确单词=包含一个元音的个数-包含两个元音的个数+包含三个元音的个数

那么枚举每个单词的非空子集,根据子集中 1 1 1个数的奇偶来给 f f f数组加或者减

这样作为初始化,做一遍 s o s d p sosdp sosdp即可,​​别人写的博客​


下面是我写的,第一种做法的代码

#include <bits/stdc++.h>
using namespace std;
const int mx = 1<<24;
int f[mx],n;
int main()
{
scanf("%d",&n); getchar();
for(int i=1;i<=n;i++)
{
int temp = 0;
for(int j=1;j<=3;j++)
{
char w; scanf("%c",&w);
temp |= (1<<(w-'a'));
} getchar();
f[temp]++;
}
for(int i=0;i<24;i++)
for(int j=mx-1;j>=0;j--)
if( j&(1<<i) ) f[j] += f[j^(1<<i)];//所有是j子集的和
int ans = 0;
for(int i=0;i<mx;i++)
ans ^= (n-f[(mx-1)^i])*(n-f[(mx-1)^i]);
cout << ans;
}