给出W个模板串和N个匹配串,问每个模板串在所有匹配串中一共出现了多少次。
先把所有模板串放进AC自动机,然后用每个匹配串在AC自动机上跑,走过的节点权值++。最后在fail树上做个前缀和,查询每个模板串的结尾节点的权值就好了。
一开始求前缀和写了深搜,但是看了策爷代码,发现可以利用求fail时的广搜队列来跑前缀和,orz%%%。
模板串和匹配串长度不一样,数组开小了WA了一发。
/* Pigonometry */
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 505, maxnode = 2500005, maxq = maxnode;
int n, val[maxn], fail[maxnode], son[maxnode][63], sum[maxnode], acmcnt, q[maxq], h, t;
char str[50005];
inline int get(char ch) {
if(ch >= 'a' && ch <= 'z') return ch - 'a';
if(ch >= 'A' && ch <= 'Z') return ch - 'A' + 26;
if(ch >= '0' && ch <= '9') return ch - '0' + 52;
if(ch == '-') return 62;
}
inline int insert() {
int now = 0, len = strlen(str);
for(int i = 0; i < len; i++) {
int &pos = son[now][get(str[i])];
if(!pos) pos = ++acmcnt;
now = pos;
}
return now;
}
inline void getfail() {
h = 0, t = 0;
for(int i = 0; i < 63; i++) if(son[0][i]) q[t++] = son[0][i];
while(h != t) {
int u = q[h++];
for(int i = 0; i < 63; i++)
if(!son[u][i]) son[u][i] = son[fail[u]][i];
else fail[q[t++] = son[u][i]] = son[fail[u]][i];
}
}
inline void work() {
int now = 0, len = strlen(str);
for(int i = 0; i < len; i++) {
now = son[now][get(str[i])];
sum[now]++;
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%s", str);
val[i] = insert();
}
getfail();
int T; scanf("%d", &T);
while(T--) {
scanf("%s", str);
work();
}
for(int i = t - 1; i >= 0; i--) sum[fail[q[i]]] += sum[q[i]];
for(int i = 1; i <= n; i++) printf("%d\n", sum[val[i]]);
return 0;
}