题意
定义一个字符串的「独特值」为只属于该字符串的本质不同的非空子串的个数。如 "amy" 与 “tommy” 两个串,只属于 "amy" 的本质不同的子串为 "a" "am" "amy" 共 3 个。只属于 "tommy" 的本质不同的子串为 "t" "to" "tom" "tomm" "tommy" "o" "om" "omm" "ommy" "mm" "mmy" 共 11 个。 所以 "amy" 的「独特值」为 3 ,"tommy" 的「独特值」为 11 。
给定 N ( N≤10^5 ) 个字符集为小写英文字母的字符串,所有字符串的长度和小于 10^5 ,求出每个字符串「独特值」。
题解
这题和喵星人的点名那题有点像啊……会了那题做这题挺简单的
先把所有串一起建一个广义SAM,然后把所有串放上去跑一遍,记录一下每一个子串属于多少个原串。然后再把所有串放上去跑一边,如果这个子串只属于一个原串,那么就把它的答案加上$l[i]-l[fa[i]]$(都是后缀自动机上的节点)
1 // luogu-judger-enable-o2 2 //minamoto 3 #include<cstring> 4 #include<cstdio> 5 using namespace std; 6 char sr[1<<21],z[20];int C=-1,Z; 7 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 8 inline void print(int x){ 9 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 10 while(z[++Z]=x%10+48,x/=10); 11 while(sr[++C]=z[Z],--Z);sr[++C]=' '; 12 } 13 const int N=1e5+5; 14 char c[N];int len[N],tot,ans[N],s[N]; 15 int fa[N<<1],ch[N<<1][26],l[N<<1],sz[N<<1],las[N<<1]; 16 int n,cnt=1,last=1; 17 void ins(int c){ 18 int p=last,np=++cnt;last=np,l[np]=l[p]+1; 19 for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np; 20 if(!p) fa[np]=1; 21 else{ 22 int q=ch[p][c]; 23 if(l[p]+1==l[q]) fa[np]=q; 24 else{ 25 int nq=++cnt;l[nq]=l[p]+1; 26 memcpy(ch[nq],ch[q],sizeof(ch[q])); 27 fa[nq]=fa[q];fa[q]=fa[np]=nq; 28 for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 29 } 30 } 31 } 32 void update(int x,int y){ 33 for(;x&&las[x]!=y;x=fa[x]) 34 ++sz[x],las[x]=y; 35 } 36 void query(int x,int y){ 37 for(;x&&las[x]!=y;x=fa[x]){ 38 if(sz[x]==1) ans[y]+=l[x]-l[fa[x]]; 39 las[x]=y; 40 } 41 } 42 int main(){ 43 scanf("%d",&n); 44 for(int i=1;i<=n;++i){ 45 scanf("%s",c+1); 46 len[i]=strlen(c+1); 47 last=1; 48 for(int j=1;j<=len[i];++j) s[++tot]=c[j]-'a',ins(s[tot]); 49 } 50 tot=0; 51 for(int i=1;i<=n;++i) 52 for(int j=1,x=1;j<=len[i];++j) 53 update(x=ch[x][s[++tot]],i); 54 for(int i=1;i<=cnt;++i) las[i]=0; 55 tot=0; 56 for(int i=1;i<=n;++i) 57 for(int j=1,x=1;j<=len[i];++j) 58 query(x=ch[x][s[++tot]],i); 59 for(int i=1;i<=n;++i) print(ans[i]); 60 Ot(); 61 return 0; 62 }