USACO18DEC Platinum

standing out from the field 

给你n个串,对于每个串求出只包含在这个串中的本质不同的子串?

后缀自动机,建树,对于每一个点打上包含在哪个串中的标记。

叶子都是前缀,直接在sam_build时预处理;其余的dfs一遍,由于x是son[x]的后缀,故x的状态由son[x]影响,如果son[x]有出现在不同串中的,标记x为-1。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=200005;
 5 char s[N+1];
 6 int last,sc,p,np,l[N],son[N][26],fa[N],cnt,head[N],f[N];
 7 ll ans[N]; 
 8 struct node{int to,next;}num[N];
 9 void add(int x,int y)
10 {num[++cnt].to=y;num[cnt].next=head[x];head[x]=cnt;}
11 void Sam(int c,int id)
12 {
13     p=last; np=last=++sc; l[np]=l[p]+1;
14     for (;p&&!son[p][c];p=fa[p]) son[p][c]=np;
15     if (!p) fa[np]=1;
16     else {
17         int q=son[p][c];
18         if (l[p]+1==l[q]) fa[np]=q;
19         else {
20             int nq=++sc; l[nq]=l[p]+1;
21             memcpy(son[nq],son[q],sizeof(son[q])); 
22             fa[nq]=fa[q];fa[q]=fa[np]=nq;
23             for (;son[p][c]==q;p=fa[p]) son[p][c]=nq;
24         }
25     }
26     if (f[np]&&f[np]!=id) f[np]=-1;else f[np]=id;//处理叶子及一部分为前缀的非叶子 
27 }
28 void dfs(int x)
29 {
30     for (int i=head[x];i;i=num[i].next)
31       if (num[i].to!=fa[x]) dfs(num[i].to);
32     if (f[x]&&f[x]!=-1) ans[f[x]]+=l[x]-l[fa[x]];
33    if (f[fa[x]]&&f[fa[x]]!=f[x]) f[fa[x]]=-1;else f[fa[x]]=f[x];
34 }
35 int main()
36 {
37     int T;scanf("%d",&T);
38     sc=1;
39     for (int i=1;i<=T;i++)
40     {
41         scanf("%s",s+1); int sl=strlen(s+1);
42         last=1;
43         for (int j=1;j<=sl;j++) Sam(s[j]-'a',i);
44     }
45     for (int i=2;i<=sc;i++) add(fa[i],i);
46     dfs(1);
47     for (int i=1;i<=T;i++) printf("%lld\n",ans[i]);
48    return 0;
49 }
View Code

猜你喜欢

转载自www.cnblogs.com/Scx117/p/9216582.html