[USACO17DEC]Standing Out from the Herd(广义后缀自动机)

题意

定义一个字符串的「独特值」为只属于该字符串的本质不同的非空子串的个数。如 "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 ( N10^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 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9473445.html