题意:
定义【独特值】表示只需要该字符串的本质不同的非空子串的个数,如 “amy” 与 “tommy” 两个串,只属于 “amy” 的本质不同的子串为 “a” “am” “amy” 共 3 个。只属于 “tommy” 的本质不同的子串为 “t” “to” “tom” “tomm” “tommy” “o” “om” “omm” “ommy” “mm” “mmy” 共 11 个。 所以 “amy” 的「独特值」为 3 ,“tommy” 的「独特值」为 11 。
题解:
对所有串建立广义SAM,然后考虑怎么计算独特值,我们想如果一个节点,如果之前没有出现过,我们就置 v i s [ r t ] = vis[rt]= vis[rt]=该串的编号,如果之前出现过了,就说明这个子串不满足独特性,直接置为-1就好了,这样就能保证都是符合条件的。
然后遍历一遍求贡献即可,每个点的贡献都是 l e n [ i ] − l e n [ f a [ i ] ] len[i] - len[fa[i]] len[i]−len[fa[i]].
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5+50;
int nxt[MAXN][26],fa[MAXN],len[MAXN],l[MAXN],vis[MAXN],ans[MAXN];
char s[MAXN],ss[MAXN]; int ls=0,last,tot=1,n;
inline void Insert(int x){
int p=last,np=++tot;
last=np,len[np]=len[p]+1;
for(;p&&!nxt[p][x];p=fa[p]) nxt[p][x]=np;
if(!p) fa[np]=1;
else{
int q=nxt[p][x];
if(len[p]+1==len[q]) fa[np]=q;
else{
int nq=++tot;
len[nq]=len[p]+1;
memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for(;nxt[p][x]==q;p=fa[p]) nxt[p][x]=nq;
}
}
}
inline void update(int rt,int k){
for(int p=rt;p && vis[p]!=k && vis[p]!=-1;p=fa[p])
if(vis[p]!=0) vis[p]=-1;
else vis[p]=k;
}
inline void solve(){
int op=0;
for(int i=1;i<=n;i++)
for(int j=1,rt=1;j<=l[i];j++)
rt=nxt[rt][s[++op]-'a'],update(rt,i);
for(int i=1;i<=tot;i++)
if(vis[i]!=-1)
ans[vis[i]] += len[i]-len[fa[i]];
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",ss);
int lss=strlen(ss); last=1;
l[i]=lss;
for(int j=0;j<lss;j++) Insert(ss[j]-'a'),s[++ls]=ss[j];
}
solve();
return 0;
}