思路:
- 首先,我们盯一下题目,发现符合要求的组合,25个字母,每个都是奇数个,那这个字符串显然也是奇数长度。ok,排除一个条件。
- 我们目的是字符串匹配,显然利用哈希是一种方便的方式。因为只有26个字母,所以32位的二进制足够我们表示所有情况。
- 我们可以开一个数组a,a[i]哪一位上有1,表示该位表示的字母存在。
- 因为,我们不需要知道一个字母一共出现多少次,只需要知道出现的奇偶次数即可。我们开个b数组,如果b[i]上哪一位为0,表示有偶数个该字母,为1,该字母出现奇数次(不开a,b同一个数组就是因为0是有这个字母还是没有会引发歧义)
- 我们如何进行i字符串与j字符串的哈希匹配呢?
- 前提是他们至少缺同一个字母。
- 剩下只需要剩下25个字母的数量异或都为1,就满足了条件。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
int a[N], b[N];
int mp[1 << 26];
int main()
{std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
string s;
cin >> n;
for (int i = 1; i <= n; ++i)
{
cin >> s;
for (auto &c : s)
{
a[i] |= 1 << (c - 'a'); //或运算记录是否出现
b[i] ^= 1 << (c - 'a'); //异或运算计算出现奇偶次数
}
}
ll ans = 0;
for (int c = 0; c < 26; ++c)
{
int tmp = (1 << 26) - 1 - (1 << c); //(1<<26)-1使得前25位都是1,-(1<<c)使得只有第c位不是1,用于后面异或匹配奇偶
for (int i = 1; i <= n; ++i)
{
if (~(a[i] >> c) & 1) //如果第i串没有第c个字母
{
mp[b[i]]++;
ans += mp[tmp ^ b[i]]; //tmp^b[i]就是与i串每个字母奇偶性匹配的哈希值
}
}
//每次匹配的前提是缺少同一个字母c,所有缺少这个字母的匹配统计后,哈希匹配数要清空
for (int i = 1; i <= n; ++i)if (~(a[i] >> c) & 1)mp[b[i]] = 0;
}
cout << ans << endl;
return 0;
}