思路:我们先对每个串hash一下,记录所有后缀出现次数。然后枚举每个前缀,看相同的后缀出现了多少次。但是可能会重复计算。因为显然如果有一个形如xy…xy的前缀,匹配到xy…xy的后缀有x个,那么xy前缀匹配到xy后缀的y个必然包含x。但其实这x个不是合法的。。。要把不合法的去掉。就其实是每个位置的next值。。把不合法的去掉即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<<x<<endl;
int n;
vector<char>v[N];
unordered_map<unsigned long long,int>vis;
struct hash_table{
unsigned long long seed, p;
unsigned long long Hash[N], tmp[N];
void set(LL _seed) {
seed = _seed;
}
void work(char *s, int n) {
tmp[0] = 1;
Hash[0] = 0;
for (int i = 1; i <= n; i++){
tmp[i] = tmp[i - 1] * seed;
Hash[i] = (Hash[i - 1] * seed + (unsigned long long )(s[i])); //may need change
}
}
unsigned long long get(int l, int r) {
return ((Hash[r] - Hash[l - 1] * tmp[r - l + 1]));
}
}g;
int ne[N];
void get_ne(char *p){
int n=strlen(p);
ne[0]=-1;
for(int i=1;i<n;i++){
int j=ne[i-1];
while(j>=0 &&p[j+1]!=p[i]){
j=ne[j];
}
if(p[j+1]==p[i])j++;
ne[i]=j;
}
}
char a[N*10];
int cnt[N];
int main() {
ios::sync_with_stdio(false);
cin>>n;g.set(131);
for(int i=1;i<=n;i++){
cin>>a+1;int len=strlen(a+1);
g.work(a,len);
for(int j=len;j>=1;j--){
vis[g.get(j,len)]++;
}
for(int j=1;j<=len;j++)v[i].pb(a[j]);
}
LL ans=0;
const int mod=998244353;
for(int i=1;i<=n;i++){
int sz=v[i].size();
for(int j=0;j<sz;j++){
a[j+1]=v[i][j];
}
a[sz+1]='\0';
get_ne(a+1);
g.work(a,sz);
for(int j=1;j<=sz;j++){
cnt[j]=vis[g.get(1,j)];
if(ne[j-1]!=-1)cnt[ne[j-1]+1]-=cnt[j];
}
for(int j=1;j<=sz;j++){
ans+=1ll*cnt[j]*j*j%mod;
ans%=mod;
cnt[j]=0;
}
}
cout<<ans<<'\n';
return 0;
}