将字符减去偏移量 'a', 将字符 a,b,c,d,e,f 映射为 0,1, 2, 3, 4, 5。用二进制中0-5位来表示他们出现的次数,用异或和来判断是出现了偶数次还是奇数次。偶数次该位最终结果为0,奇数次结果为1。将所有二进制状的十进制数作为下标,使该下标的计数++。则数组每个元素的值表示可以产生相同二进制状态的结点个数,从这些节点中任选出两个来均可得到一条各个字符出现次数均为偶数次的路径,所以其计算公式为。
ACcode
#include <bits/stdc++.h>
using namespace std;
void TLE() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); }
#define int long long
typedef long long ll;
typedef unsigned long long ULL;
const int N = 2e5 + 10;
const ll mod = 1000000007;
int sz[N];
signed main()
{
cin.tie(0)->sync_with_stdio(false);
int n;
cin >> n;
vector<vector<pair<int, int>>> edge(n + 1);
for (int i = 1; i < n; i++)
{
int u, v;
char s;
cin >> u >> v >> s;
edge[u].push_back({v, s - 'a'});
edge[v].push_back({u, s - 'a'});
}
vector<int> dp(1ll << 6);
function<void(int, int, int)> dfs = [&](int u, int fa, int st)
{
dp[st]++;
for (auto t : edge[u])
{
int v = t.first, w = t.second;
if (v == fa)
{
continue;
}
dfs(v, u, st ^ (1ll << w));
}
};
dfs(1, -1, 0);
int res = 0;
for (int i = 0; i <= (1 << 6); i++)
{
res += dp[i] * (dp[i] - 1) / 2;
}
cout << res << endl;
return 0;
}