题意:
给n(1<n<2e5)个字符串,总的长度不超过5e6,判断多少对字符串对<i,j>组合后,满足长度为奇数,不同字母刚好有25种,且每个字母个数为奇数。
思路:
用哈希表法,用状态压缩,把a∼z映射到0∼25。对于第i个字符串si,定义ai为si中出现的字母的状态,如果字母c出现过,那么ai的第c位应该为1,否则为0。定义bi为每个字母出现次数奇偶性的状态,如果字母c出现了奇数次,那么bi的第c位应该为1,否则为0。
对于一个正确的字符串s,应该满足ai中有25个1,bi中也有25个1,并且1的位置应该是一样的,
通过枚举c,一共有26个,来看看拼接字符串中少了哪个字母,对应ai=bi=2^26-1-2^c。然后对于每个c,枚举每一个字符串i,si对应的ai的第c位应该为0,才能满足题意。所以看看i前面有多少个
j,满足aj的第c位为0,且有bj或与bi=2^26-1-2^c.
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
typedef long long int ll;
using namespace std;
const int N = 2e5 + 10;
ll a[N], b[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
map<ll, ll>mp;
ll res = 0;
int i;
for (i = 1; i <= n; i++)
{
string s;
cin >> s;
for (auto c : s)
{
a[i] ^= 1 << (c - 'a');//记录奇数字符的个数
b[i] |= 1 << (c - 'a');//记录有多少个字符
}
}
int j;
for (j = 0; j < 26; j++)
{
ll sta = ((1 << 26) - 1) ^ (1 << j);//记录第几个字符
mp.clear();
for (i = 1; i <= n; i++)
{
if (!(b[i] >> j & 1))//说明b的第j位元素不是奇数的话
{
res += mp[sta ^ a[i]];//加上与a[i]偶数元素相对于的缺少的字符串数列
mp[a[i]]++;//更新mp中的相应奇数的a[i]的数量;
}
}
}
cout << res << endl;
return 0;
}