CF1045I Palindrome Pairs 题解
题目分析
首先得出两个串加在一起构成回文的要求:最多只有 $1$ 个字母总共有奇数个。
想也很好想,同个字母两两对应,对应不了的那个放中间就行。
然后我们发现每个字符串只需要存储每个字母的数量的奇偶性 $0,1$ 两个量,很容易想到用一个 $26$ 位二进制来存字符串。
满足要求的对数可以分成两种情况考虑:
- 每个字母总共都是偶数个。
观察下列式子:$0+0=0,1+1 = 2$
可以发现只有二进制数相等的两个字符串可以构成这种情况,开一个数组记录每个二进制数的个数。然后这其中任选两个都能构成回文,即贡献为 $C_{n}^{2}$。
- 有且仅有一个字母为奇数个。
也很容易得出两个字符串的二进制仅有一个位不同。那么也只需要开一个哈希记录每一个二进制数可以被“匹配”的数量(“匹配”即为仅有一个位不同)。然后贡献为每个字符串对应的二进制数被“匹配”的个数。
最后答案为上述两种情况的和。
代码
#include<bits/stdc++.h>
using namespace std;
unordered_map<long long,long long> mp,ct;
vector<long long> v;
long long n,x,res;
int main()
{
scanf("%lld",&n);
for (int e = 1;e <= n;e++)
{
x = 0;//将字符串存为一个二进制数
string s;cin >> s;
for (int i = 0;i < s.size();i++) x ^= (1 << (s[i]-'a'));//存第s[i]位
v.push_back(x);
for (int i = 0;i < 26;i++)
if (((x >> i) & 1) == 0)
ct[(x+(1 << i))]++; //第i位不同的匹配
mp[x]++;
}
for (auto e:mp) res += e.second*(e.second-1)/2; //偶数的情况贡献为cn2
for (auto t:v) res += ct[t]; // 可以被匹配
cout << res <<endl;
return 0;
}

浙公网安备 33010602011771号