题解
设一个拼接之后的合法的字符串为 ,因为
中每个字符串中字母出现的次数都是奇数,所以长度也肯定是奇数,所以我们不用管第二个条件。
我们来看第三个条件,恰好有 个不同字母不好做,我们可以枚举那个没出现的字母
。
我们设数组 和
,分别表示第
个字符串,其中二进制的第
位如果等于
,就表示字母出现次数为奇数和至少出现一次。
cpp
for(int i=1;i<=n;i++){
scanf("%s",c+1);
m=strlen(c+1);
for(int j=1;j<=m;j++){
s[i]^=1<<(c[j]-'a');
t[i]|=1<<(c[j]-'a');
}
}
我们定义一个函数 求出一个表示每个字符出现次数的字符串将第
位去掉之后将剩下的位不动的数传下去。
cpp
int f(int S,int i){
return ((S>>(i+1))<<i)+(S&((1<<i)-1));
}
然后我们枚举缺失的字母 和每个字符串
,将所有没有字母
的字符串放到一个桶
里。我们再定义一个桶
表示字符串
去掉
的状态,也就是我们定义的
函数。
然后我们枚举每个状态,将答案变量加上枚举的状态异或上一个第 位是
,其余都是
的掩码。
cpp
for(int i=0;i<26;i++){//枚举缺失的字母
v.clear();
for(int j=1;j<=n;j++){
if((t[j]>>i)&1) continue;//包含字母i,跳过
v.push_back(s[j]);
mp[f(s[j],i)]++;
}
for(int k : v){
ans+=mp[f(k^(((1<<26)-1)^(1<<i)),i)];
}
for(int k : v){
mp[f(k,i)]=0;
}
}
代码
cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,M=5e6+5;
int n,m,t[N],s[N],mp[M<<3],ans;//s表示奇偶性,t表示出现
char c[M];
vector<int> v;
int f(int S,int i){
return ((S>>(i+1))<<i)+(S&((1<<i)-1));
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%s",c+1);
m=strlen(c+1);
for(int j=1;j<=m;j++){
s[i]^=1<<(c[j]-'a');
t[i]|=1<<(c[j]-'a');
}
}
for(int i=0;i<26;i++){//枚举缺失的字母
v.clear();
for(int j=1;j<=n;j++){
if((t[j]>>i)&1) continue;//包含字母i,跳过
v.push_back(s[j]);
mp[f(s[j],i)]++;
}
for(int k : v){
ans+=mp[f(k^(((1<<26)-1)^(1<<i)),i)];
}
for(int k : v){
mp[f(k,i)]=0;
}
}
printf("%lld\n",ans>>1);
return 0;
}