传送门
题解:
比较套路的题,建广义SAM然后暴跳fail更新所属串集合。
所属串集合大小为1的保留那个元素,否则存为-1。最后直接把答案加到对应串上即可。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
cs int N=1e5+7;
int n;
char s[N];int len;
int L[N],ans[N];
namespace SAM{
cs int N=::N<<1|1;
int fa[N],len[N],son[N][26],vis[N],now=1;
inline int work(int p,int c){
int nq=++now,q=son[p][c];
memcpy(son[nq],son[q],sizeof son[q]);
len[nq]=len[p]+1,fa[nq]=fa[q],fa[q]=nq;
for(;p&&son[p][c]==q;p=fa[p])son[p][c]=nq;
return nq;
}
inline int push_back(int p,int c){
if(son[p][c]){
if(len[son[p][c]]==len[p]+1)return son[p][c];
else return work(p,c);
}
int cur=++now;len[cur]=len[p]+1;
for(;p&&!son[p][c];p=fa[p])son[p][c]=cur;
if(!p)fa[cur]=1;
else if(len[son[p][c]]==len[p]+1)fa[cur]=son[p][c];
else fa[cur]=work(p,c);
return cur;
}
inline void update(int u,int id){
for(;u&&vis[u]!=id&&vis[u]!=-1;u=fa[u])vis[u]=vis[u]?-1:id;
}
inline void solve(){
for(int re i=1;i<=n;++i)
for(int re cur=1,j=L[i-1]+1;j<=L[i];++j)
update(cur=son[cur][s[j]-'a'],i);
for(int re i=1;i<=now;++i)if(vis[i]>0)ans[vis[i]]+=len[i]-len[fa[i]];
}
}
signed main(){
#ifdef zxyoi
freopen("herd.in","r",stdin);
#endif
scanf("%d",&n);
for(int re i=1;i<=n;++i){
scanf("%s",s+L[i-1]+1);
L[i]=strlen(s+L[i-1]+1)+L[i-1];int p=1;
for(int re j=L[i-1]+1;j<=L[i];++j)
p=SAM::push_back(p,s[j]-'a');
}
SAM::solve();
for(int re i=1;i<=n;++i)std::cout<<ans[i]<<"\n";
return 0;
}