struct ACAM {
int tr[N][26] = {} ; // N表示单词字符个数之和
int ne[N] = {} ;
int idx = 0 ;
int cnt[N] = {} ;
int q[N] = {} ; //记录路径
int hh = 0 , tt = 0 ;
void insert(string s) {
int p = 0 ;
for(auto t : s) {
int c = t - 'a' ;
if(!tr[p][c]) tr[p][c] = ++ idx ;
p = tr[p][c] ;
}
//以下是你要进行的操作
cnt[p] ++ ; //p表示字符串在trie树上的位置
}
void build() {
for(int i = 0 ; i < 26 ; i ++)
if(tr[0][i])
q[tt ++] = {tr[0][i]} ;
while(hh < tt) {
int t = q[hh ++] ;
for(int i = 0 ; i < 26 ; i ++) {
int p = tr[t][i] ;
if(!p) tr[t][i] = tr[ne[t]][i] ;
else {
ne[p] = tr[ne[t]][i] ;
q[tt ++] = p ;
}
}
}
}
//以下随意添加
};
例题 https://www.acwing.com/problem/content/description/1284/
#include <iostream>
using namespace std ;
const int N = 5e5 + 10 ;
struct ACAM {
int tr[N][26] = {} ; // N表示单词字符个数之和
int ne[N] = {} ;
int idx = 0 ;
int cnt[N] = {} ;
int q[N] = {} ; //记录路径
int hh = 0 , tt = 0 ;
void insert(string s) {
int p = 0 ;
for(auto t : s) {
int c = t - 'a' ;
if(!tr[p][c]) tr[p][c] = ++ idx ;
p = tr[p][c] ;
}
//以下是你要进行的操作
cnt[p] ++ ; //p表示字符串在trie树上的位置
}
void build() {
for(int i = 0 ; i < 26 ; i ++)
if(tr[0][i])
q[tt ++] = {tr[0][i]} ;
while(hh < tt) {
int t = q[hh ++] ;
for(int i = 0 ; i < 26 ; i ++) {
int p = tr[t][i] ;
if(!p) tr[t][i] = tr[ne[t]][i] ;
else {
ne[p] = tr[ne[t]][i] ;
q[tt ++] = p ;
}
}
}
}
//以下随意添加
int op(string s){ //你要执行的操作
int p = 0 ;
int ans = 0 ;
for(auto t : s) {
char c = t - 'a' ;
p = tr[p][c] ;
int f = p ;
while(f) {
ans += cnt[f] ;
cnt[f] = 0 ;
f = ne[f] ;
}
}
return ans ;
}
};
int main(){
int T ;
cin >> T ;
while(T --) {
int n ;
cin >> n ;
ACAM acam ;
for(int i = 0 ; i < n ; i ++) {
string s ;
cin >> s ;
acam.insert(s) ;
}
acam.build() ;
string res ;
cin >> res ;
cout << acam.op(res) << endl ;
}
}