给定一篇由 \(n\) 个单词构成的文章,问每个单词以子串的形式出现了多少次。\(n\leq 200, len \leq 10^6\)
对所有单词建立 AC 自动机,再把它们扔上去跑,每走到一个位置就对该位置计数器 \(+1\),最后答案就是对应节点的子树和,于是将所有计数标记沿着 fail 树上传即可
#include <bits/stdc++.h>
using namespace std;
const int N = 2000005;
queue <int> q;
int c[N][26],val[N],fi[N],cnt,tag[N];
vector <int> g[N];
void ins(char *str,int id) {
int len=strlen(str), p=0;
for(int i=0; i<len; i++) {
int v=str[i]-'a';
if(!c[p][v]) c[p][v]=++cnt;
p=c[p][v];
}
val[id]=p;
}
void build() {
for(int i=0; i<26; i++) if(c[0][i]) fi[c[0][i]]=0, q.push(c[0][i]);
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=0; i<26; i++)
if(c[u][i]) fi[c[u][i]]=c[fi[u]][i], q.push(c[u][i]);
else c[u][i]=c[fi[u]][i];
}
}
int query(char *s) {
int len=strlen(s);
int p=0;
for(int i=0; i<len; i++) {
p=c[p][s[i]-'a'];
tag[p]++;
}
}
int n;
string s[205];
char str[N];
void dfs(int p) {
for(int q:g[p]) {
dfs(q);
tag[p]+=tag[q];
}
}
signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) {
cin>>s[i];
for(int j=0;j<s[i].length();j++) str[j]=s[i][j];
str[s[i].length()]=0;
ins(str,i);
}
build();
for(int i=1;i<=n;i++) {
for(int j=0;j<s[i].length();j++) str[j]=s[i][j];
str[s[i].length()]=0;
query(str);
}
for(int i=1;i<=cnt;i++) g[fi[i]].push_back(i);
dfs(0);
for(int i=1;i<=n;i++) cout<<tag[val[i]]<<endl;
}
原文:https://www.cnblogs.com/mollnn/p/12449797.html