题意:
给定一个字符串 t t t,以及 n n n 个字符串 s i s_i si,定义 f ( t , s ) f(t, s) f(t,s) 为 串 s s s 在串 t t t 中出现的次数, t + s t + s t+s 为字符串的拼接,求 ∑ i = 1 n ∑ i = 1 n f ( t , s i + s j ) \sum\limits_{i = 1}^{n}\sum\limits_{i = 1}^{n}f(t, s_i + s_j) i=1∑ni=1∑nf(t,si+sj)。 ( n , ∣ t ∣ , ∑ ∣ s i ∣ ≤ 2 × 1 0 5 ) (n, |t|, \sum |s_i| \leq 2×10^5) (n,∣t∣,∑∣si∣≤2×105)
链接:
https://codeforces.com/problemset/problem/1202/E
解题思路:
多模式串的匹配,可以考虑 A C AC AC 自动机。显然不能直接枚举模式串的拼接,那么反过来枚举主串 t t t 的匹配位置,在 A C AC AC 自动机上跑主串,每到一个结点,其 f a i l fail fail 父链上的模式串都可以在该位置和主串匹配,因此可以得到主串 t t t 以位置 i i i 结束的匹配数 g i g_i gi,再将所有字符串反向,再得到主串 t ′ t' t′ 以位置 i ′ i' i′ 结束的匹配数 g i ′ g'_i gi′,那么枚举字符串拼接点的下标位置,对每个下标 i i i,贡献为 g i ′ ∗ g n − i ′ g_i' * g'_{n-i} gi′∗gn−i′。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 2e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
char s[maxn], t[maxn];
int n, m;
struct AC{
int nxt[maxn][26], fail[maxn], num[maxn], g[maxn];
int cnt;
int add(){
++cnt; fail[cnt] = num[cnt] = 0; return cnt;
}
void init(){
cnt = -1; add();
}
void insert(char *s){
int p = 0;
while(*s){
int t = *s - 'a';
if(!nxt[p][t]) nxt[p][t] = add();
p = nxt[p][t];
++s;
}
++num[p];
}
void cFail(){
queue<int> q;
for(int i = 0; i < 26; ++i) if(int v = nxt[0][i]) q.push(v);
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = 0; i < 26; ++i){
if(int v = nxt[u][i]) fail[v] = nxt[fail[u]][i], num[v] += num[fail[v]], q.push(v);
else nxt[u][i] = nxt[fail[u]][i];
}
}
}
void solve(){
cFail();
int p = 0;
for(int i = 1; i <= n; ++i){
p = nxt[p][t[i] - 'a'];
g[i] = num[p];
}
}
} ac1, ac2;
int main() {
ios::sync_with_stdio(0); cin.tie(0);
cin >> t + 1;
n = strlen(t + 1);
cin >> m;
ac1.init(), ac2.init();
for(int i = 1; i <= m; ++i){
cin >> s + 1;
ac1.insert(s + 1);
int tn = strlen(s + 1);
reverse(s + 1, s + 1 + tn);
ac2.insert(s + 1);
}
ac1.solve();
reverse(t + 1, t + 1 + n);
ac2.solve();
ll ret = 0;
for(int i = 1; i < n; ++i){
ret += ac1.g[i] * 1ll * ac2.g[n - i];
}
cout << ret << endl;
return 0;
}