USACO 2017 December Contest Platinum T1: 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 (N1e5) 个字符集为小写英文字母的字符串,所有字符串的长度和小于 1e5,求出每个字符串「独特值」。

 

题目分析

看到这种有多个字符串的题,我们一般会去考虑使用广义SAM或把每个字符串连起来中间以特殊字符隔开。

这里考虑广义SAM,其实就是每次加入新字符串时把lst置为1就行。

我们对这些字符串建出广义SAM,每一个串都从根节点开始遍历,我们沿着ch数组往下跳,每到一个新节点时,再沿着parent树往上跳,这样可以保证遍历它的所有子串。

最后统计一下只经过一次的节点 i 有哪些,把它的贡献 l[i]-l[fa[i]] 加给对应字符串即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int MAXN=2e5+10;
 5 
 6 int n,tot;
 7 int len[MAXN],s[MAXN];
 8 
 9 struct Suffix_Automation{
10     int lst,cnt;
11     int ch[MAXN][27],fa[MAXN],l[MAXN],vis[MAXN],ans[MAXN];
12     Suffix_Automation(){lst=cnt=1;}
13     inline void Extend(int x){
14         int p=lst,np=++cnt;lst=np;
15         l[np]=l[p]+1;
16         while(p&&!ch[p][x]) ch[p][x]=np,p=fa[p];
17         if(!p) fa[np]=1;
18         else{
19             int q=ch[p][x];
20             if(l[q]==l[p]+1) fa[np]=q;
21             else{
22                 int nq=++cnt;
23                 memcpy(ch[nq],ch[q],sizeof(ch[q]));
24                 l[nq]=l[p]+1;
25                 fa[nq]=fa[q];
26                 fa[q]=fa[np]=nq;
27                 while(ch[p][x]==q) ch[p][x]=nq,p=fa[p];
28             }
29         }
30     }
31     inline void Update(int x,int y){
32         for(;x&&vis[x]!=y&&vis[x]!=-1;x=fa[x]){
33             if(vis[x]!=0) vis[x]=-1;
34             else vis[x]=y;
35         }
36     }
37     inline void Work(){
38         tot=0;
39         for(int i=1;i<=n;++i)
40             for(int j=1,x=1;j<=len[i];++j)
41                 Update(x=ch[x][s[++tot]],i); 
42         for(int i=1;i<=cnt;++i)
43             if(vis[i]!=-1){
44                 int x=vis[i];
45                 ans[x]+=l[i]-l[fa[i]];
46             }
47         for(int i=1;i<=n;++i)
48             printf("%d\n",ans[i]);
49     } 
50 }SAM; 
51 
52 int main(){
53     cin>>n;getchar();
54     for(int i=1;i<=n;++i){
55         char ch;
56         SAM.lst=1;
57         while((ch=getchar())!='\n'&&ch!=EOF){
58             ch-='a';
59             ++len[i];s[++tot]=ch;
60             SAM.Extend(ch);
61         } 
62     }
63     SAM.Work();
64     return 0;
65 }

 

posted @ 2019-07-24 07:35  LI_dox  阅读(204)  评论(0编辑  收藏  举报