判断一个串是否在至少k个字符串里面的方法后3473一样,每添加一个新的字符就沿fail链更新。
剩下的问题就只是剩下了,每增加一个新的字符,共多出现了多少个新的字符串,如果不要求重复,那么很显然就是len[u]-len[fail[u]],这里重复的字串也需要加入答案所以只用沿fail链dfs一下,sum[u]=fail链上所有的坏和就好了
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 200021
#include<vector>
#define LL long long
using namespace std;
int len[maxn],n,K,son[maxn][26],sz[maxn];
LL sum[maxn];
int fail[maxn],now,bg[maxn],bl[maxn],last=1,tot=1,rt=1;
char s[maxn];
vector<int>g[maxn],e[maxn];
void insert(int c){
int p=last,np=++tot,q,nq;
last=np;len[np]=len[p]+1;
while(p&&!son[p][c])son[p][c]=np,p=fail[p];
if(!p)fail[np]=rt;
else{
q=son[p][c];
if(len[q]==len[p]+1)fail[np]=q;
else{
nq=++tot;
len[nq]=len[p]+1;
sz[nq]=sz[q],fail[nq]=fail[q],bl[nq]=bl[q];
memcpy(son[nq],son[q],sizeof(son[nq]));
fail[np]=fail[q]=nq;
while(p&&son[p][c]==q)son[p][c]=nq,p=fail[p];
}
}
g[now].push_back(np);
while(np&&bl[np]!=now){
sz[np]++;
bl[np]=now;
np=fail[np];
}
}
void dfs(int u){
for(int v,i=0;i<e[u].size();i++){
v=e[u][i];
sum[v]+=sum[u];
dfs(v);
}
}
int main(){
scanf("%d%d",&n,&K);
for(int l,i=1;i<=n;i++){
last=rt;
scanf("%s",s+bg[i]);l=strlen(s+bg[i]);
bg[i+1]=bg[i]+l;
now=i;
for(int j=bg[i];j<bg[i+1];j++)insert(s[j]-'a');
}
for(int i=tot;i>1;i--){
e[fail[i]].push_back(i);
if(sz[i]>=K)sum[i]=len[i]-len[fail[i]];
}sum[1]=0;
dfs(1);
for(int i=1;i<=n;i++){
LL ans=0;
for(int u,j=0;j<g[i].size();j++){
u=g[i][j];
ans+=sum[u];
}
printf("%lld ",ans);
}
return 0;
}