题目问每个”prefix + ’ ’ + suffix”类型的串能匹配上多少个串S。
可以做处理将”prefix + ’ ’ + suffix” 转化为 “suffix + ‘#’ + prefix”类型的串,然后把所有S串扩充成”S + # + S”串。
问题就转化成了,给定m个串,问每个串是多少个s串的子串。
首先不考虑前缀后缀不允许重合的条件。
将m个串建ac自动机,分别用n个串去匹配,遇到end节点就+1即可,需要注意的是一个节点的fail是end节点,那么这个节点也是end节点(fail树的性质)。
之后建立fail树,之后dfs跑一边树上前缀和即可(或者不建树,直接bfs跑一遍)。
现在考虑前缀后缀不允许重合的条件,本质上也就是限制S串匹配的深度,若该S串的长度为len,则当前节点为危险节点时且深度小于等于len+1(我们给S串添加了‘#’字符)时,必然满足条件,因为此时的”prefix + suffix”的长度只会小于等于len。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
vector<int> G[550000];
struct Ac{
static const int maxm = 5500000;
static const int maxn = 30;
int next[maxm][maxn], pos[maxm], fail[maxm], cnt[maxm], deep[maxm], d[maxm], end[maxm];
int root, L;
int getid(char c) {
if(islower(c))
return c-'a';
if(c == '#') return 26;
}
int newnode() {
for(int i = 0; i < maxn; i++) next[L][i] = -1;
d[L] = cnt[L] = end[L] = fail[L] = 0;
pos[L++] = 0;
return L - 1;
}
void init() {
L = 0;
root = newnode();
}
void insert(string s, int ss) {
int len = s.size();
int p = root;
deep[p] = 0;
for(int i = 0; i < len; i++) {
int id = getid(s[i]);
if(next[p][id] == -1)
next[p][id] = newnode();
int v = deep[p];
p = next[p][id];
deep[p] = v + 1;
}
pos[ss] = p;
end[p] = 1;
}
void build() {
queue<int> q;
int p = root;
for(int i = 0; i < 27; i++) {
if(next[p][i] == -1) {
next[p][i] = root;
} else {
fail[next[p][i]] = p;
q.push(next[p][i]);
}
}
while(!q.empty()) {
int now = q.front();
q.pop();
for(int i = 0; i < 27; i++) {
if(next[now][i] == -1) next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
q.push(next[now][i]);
}
}
}
for(int i = 0; i < L; i++)
if(end[fail[i]]) end[i] = 1;
}
void ask(string s, int h) {
int len = s.size();
int now = root;
for(int i = 0; i < len; i++) {
int v = getid(s[i]);
now = next[now][v];
while(deep[now] > h)
now = fail[now];
if(end[now]) cnt[now]++;
}
}
void getans() {
queue<int> q;
for(int i = 0; i < L; i++) d[fail[i]] ++;
for(int i = 0; i < L; i++) if(d[i] == 0) q.push(i);
while(!q.empty()) {
int v = q.front();
q.pop();
cnt[fail[v]] += cnt[v];
v = fail[v];
d[v]--;
if(d[v] == 0) q.push(v);
}
}
}ac;
int t, n, q;
string str[550000];
int len[550000];
int main(){
// freopen("1001.in", "r", stdin);
// freopen("out.txt", "w", stdout);
cin.tie(0);
ios::sync_with_stdio(0);
cin >> t;
while(t--) {
cin >> n >> q;
string tmp;
for(int i = 1; i <= n; i++) {
cin >> tmp;
str[i].clear();
str[i] += tmp;
str[i] += '#';
len[i] = tmp.size() + 1;
str[i] += tmp;
}
// ss = str;
ac.init();
for(int i = 1; i <= q; i++) {
string s1, s2;
cin >> s1 >> s2;
tmp = s2;
tmp += '#';
tmp += s1;
ac.insert(tmp, i);
}
ac.build();
for(int i = 1; i <= n; i++)
ac.ask(str[i], len[i]);
ac.getans();
for(int i = 1; i <= q; i++)
cout<<ac.cnt[ac.pos[i]]<<'\n';
for(int i = 0; i < ac.L; i++)G[i].clear();
}
return 0;
}