解析
我对力量一无所知
通过这题,可以看出我对AC自动机还是完全没有理解
qwq
首先容易想到:
建一课trie树,然后建树时记录每个串s的终点,这个点后面每被经过一次,就相当于出现一次该单词s
但是,这种“出现”:只是当s恰好是后面的前缀时,才会被计算
所以我们想到(其实到这我就没想到 )
任何一个以s为后缀的结点被遍历到时,s都会出现一次
同时我们发现,这样统计可以做到不重不漏
所以我们就可以写出一个不伦不类的方程:
ans[s]=∑ans [s1] (s是s1的后缀)
然后利用AC自动机的机制,类似前缀和一样的滚起来,就可以解决本题
另外值得注意的一点是,AC自动机bfs之后用完的那个队列中恰好是按bfs排列的(废话 ),转移时我们可以直接利用
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+100;
int tr[N][27],tot=1;
int n;
char s[N];
int cnt=0;
int k,id[N];
int num[N];
void build(){int l=strlen(s+1),pl=1;for(int i=1;i<=l;i++){int a=s[i]-'a'+1;if(!tr[pl][a]) tr[pl][a]=++tot;pl=tr[pl][a];num[pl]++;}id[k]=pl;//num[pl]++;
}
int q[N],st,ed,nxt[N];
void bfs(){st=ed=q[1]=1;for(int i=1;i<=26;i++) tr[0][i]=1;nxt[1]=0;while(st<=ed){int now=q[st++];for(int i=1;i<=26;i++){if(!tr[now][i]) tr[now][i]=tr[nxt[now]][i];else{q[++ed]=tr[now][i];nxt[tr[now][i]]=tr[nxt[now]][i];}}}for(int i=ed;i>=1;i--){num[nxt[q[i]]]+=num[q[i]];}return;
}int main() {scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%s",s+1);k=i;build();}bfs();for(int i=1;i<=n;i++){printf("%d\n",num[id[i]]);}return 0;
}/*
3
a
aa
aaa
*/