CF1045I Palindrome Pairs 题解

题目传送门~

题目分析

首先得出两个串加在一起构成回文的要求:最多只有 $1$ 个字母总共有奇数个

想也很好想,同个字母两两对应,对应不了的那个放中间就行。

然后我们发现每个字符串只需要存储每个字母的数量的奇偶性 $0,1$ 两个量,很容易想到用一个 $26$ 位二进制来存字符串。

满足要求的对数可以分成两种情况考虑:

  1. 每个字母总共都是偶数个。

观察下列式子:$0+0=0,1+1 = 2$

可以发现只有二进制数相等的两个字符串可以构成这种情况,开一个数组记录每个二进制数的个数。然后这其中任选两个都能构成回文,即贡献为 $C_{n}^{2}$。

  1. 有且仅有一个字母为奇数个。

也很容易得出两个字符串的二进制仅有一个位不同。那么也只需要开一个哈希记录每一个二进制数可以被“匹配”的数量(“匹配”即为仅有一个位不同)。然后贡献为每个字符串对应的二进制数被“匹配”的个数。

最后答案为上述两种情况的和。

代码

#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;
}
posted @ 2023-11-11 11:31  codwarm  阅读(21)  评论(0)    收藏  举报  来源