主要就是用的AC自动机再对于重复的字符串进行判断处理,避免反复计算相同的字符串,但还是会TLE#subtask1
#include<iostream>
#include<cstdio>
#include<cstring>
#define MAX int(1e7+5)
using namespace std;
int n;
// string s[205];
char s[205][int(1e5+5)];
int l[205];
int ans[205];
int trie[MAX][26],bo[MAX]={},tot=1;
int v[205];
inline void ist(char *s,int l,int id){
int u=1;
for(int i=1;i<=l;i++){
int c=s[i]-'a';
if(!trie[u][c])trie[u][c]=++tot;
u=trie[u][c];
}
if(!bo[u]){
bo[u]=id;//标记首次出现的单词的编号
v[id]++;//非首次出现出现的单词在find函数中不予计算
}
else{
//重复了
v[bo[u]]++;//统计相同单词出现的次数
//然后在find函数计数中直接作为权进行计算
ans[id]=-bo[u];
//用负数来标记相同答案的编号,方便直接引用
}
}
int que[MAX],nxt[MAX];
inline void bfs(){
for(int i=0;i<26;i++){
trie[0][i]=1;
}
que[1]=1,nxt[1]=0;
for(int q1=1,q2=1;q1<=q2;q1++){
int u=que[q1];
for(int i=0;i<26;i++){
if(!trie[u][i])trie[u][i]=trie[nxt[u]][i];
else{
que[++q2]=trie[u][i];
nxt[trie[u][i]]=trie[nxt[u]][i];
}
}
}
}
inline void find(char *s,int l,int id){
int u=1;
for(int i=1;i<=l;i++){
int c=s[i]-'a';
int k=trie[u][c];
while(k>1){
if(bo[k])ans[bo[k]]+=v[id];
k=nxt[k];
}
u=trie[u][c];
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s[i]+1);
l[i]=strlen(s[i]+1);
ist(s[i],l[i],i);
}
bfs();
for(int i=1;i<=n;i++){
if(v[i]){
find(s[i],l[i],i);
}
//主要有优化空间的地方
//第十个点有大量重复a的毒瘤数据
//这里考虑去掉重复数据
}
for(int i=1;i<=n;i++){
if(ans[i]>=0){
printf("%d\n",ans[i]);
}else{
printf("%d\n",ans[-ans[i]]);
//输出重复的,直接引用已经求出来的答案即可
}
}
return 0;
}