题意

对于字符串s,t,定义f(s,t)为s的前缀和t的后缀的最长匹配长度。
给n个字符串,求图片说明

题解

预处理出n个字符串所有后缀的hash值,并记录个数。枚举每一个字符串的所有前缀,求出前缀的hash值,答案加上与前缀相同hash值的后缀个数就行,但是因为要求的是si和sj的最长前后缀长度,例如si=abaa 和 sj=aba匹配,si的前缀a和sj的后缀a匹配,但是最长的是si的前缀aba和sj的后缀aba,所以要减去前面短的不合法的答案。对于以i结尾的前缀字符串,如果前面存在更短的字符串匹配的情况,那么nex[i+1]不为0,res[nex[i+1]-1] -= res[i]。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 7, base = 133, mod = 998244353;
typedef unsigned long long ull;
typedef long long ll;
string s[100005];
int n, nex[maxn];
map<ull,int> mp;
void Hash(string t) {
    ull sum = 0, b = 1;//后缀的计算方法与前缀不同
    for (int i = t.size() - 1; i >= 0; i--, b *= base) {
        sum += b * (t[i] - 'a' + 1);
        mp[sum]++;
    }
}
void get_next(string t) {
    int len = t.size();
    nex[0] = -1;
    int i = 0, j = -1;
    while (i < len) {
        if(j == -1 || t[i] == t[j]) {
            i++; j++;
            nex[i] = j;
        }
        else j = nex[j];
    }
}
int res[maxn];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    ll ans = 0;
    for (int i = 1; i <= n; i++) cin >> s[i], Hash(s[i]);
    for (int i = 1; i <= n; i++) {
        ull sum = 0;
        for (int j = 0; j < s[i].size(); j++) {
            sum = sum * base + (s[i][j] - 'a' + 1);
            res[j] = mp[sum];
        }
        get_next(s[i]);
        for (int j = 0; j < s[i].size(); j++)
            if(nex[j + 1]) res[nex[j + 1] - 1] -= res[j];
        for (int j = 0; j < s[i].size(); j++) {
            ans = (ans + (ll)res[j] * (j + 1) % mod * (j + 1) % mod) % mod;
        }
    }
    cout << ans << endl;
}