SPOJ 8222 Substrings (后缀自动机)

转载:http://hzwer.com/4420.html

 

给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值。

求F(1)..F(Length(S)) Length(S) <= 250000

我们构造S的后缀自动机(SAM),那么对于一个节点s,它的长度范围是 [Min(s),Max(s)],同时他的出现次数是|Right(s)|。

那么我们用 |Right(s)|去更新F(Max(s))的值。 同时最后从大到小依次用F(i)去更新F(i-1)即可。

对于SAM,我口胡几句吧

自动机每个结点信息是一个right集合

比如串aaabbaaabd

aaab在其中1-4 6-9出现

则自动机在读入aaab到达的结点是{4,9}

aab和ab也应该到达这个结点,因为他们出现的结尾也是{4,9}

而b是{4,5,9}不到达这个结点

显然,对于一个状态s,若长度l<=r所对应的al,ar满足

ST(al)=ST(ar)=s那么对于任意的l<=x<=r,ST(ax)=s

不妨设s所有合法集合为[Min(s),Max(s)]

al指的是串a的前l个

显然节点信息是集合包含关系

随着串长增加就是集合元素减少

构建自动机的目标就是让所有包含关系变为一棵树

构建实际上很简单。。。

  1 1
  2 2
  3 3
  4 4
  5 5
  6 6
  7 7
  8 8
  9 9
 10 10
 11 11
 12 12
 13 13
 14 14
 15 15
 16 16
 17 17
 18 18
 19 19
 20 20
 21 21
 22 22
 23 23
 24 24
 25 25
 26 26
 27 27
 28 28
 29 29
 30 30
 31 31
 32 32
 33 33
 34 34
 35 35
 36 36
 37 37
 38 38
 39 39
 40 40
 41 41
 42 42
 43 43
 44 44
 45 45
 46 46
 47 47
 48 48
 49 49
 50 50
 51 51
 52 52
 53 53
 54 #include<iostream>
 55 #include<cstdio>
 56 #include<cstring>
 57 #include<cstdlib>
 58 #include<algorithm>
 59 #include<cmath>
 60 #define N 500005
 61 #define ll long long
 62 using namespace std;
 63 char s[N];
 64 int S,cnt,last;
 65 int a[N],b[N],f[N],t[N],fa[N],l[N],r[N],ch[N][26];
 66 void add(int x)
 67 {
 68     int c=a[x];
 69     int p=last,np=++cnt;last=np;
 70     l[np]=x;
 71     for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
 72     if(!p)fa[np]=S;
 73     else 
 74     {
 75         int q=ch[p][c];
 76         if(l[p]+1==l[q])fa[np]=q;
 77         else 
 78         {
 79             int nq=++cnt;l[nq]=l[p]+1;
 80             memcpy(ch[nq],ch[q],sizeof ch[q]);
 81             fa[nq]=fa[q];
 82             fa[np]=fa[q]=nq;
 83             for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
 84         }
 85     }
 86 }
 87 int main()
 88 {
 89     scanf("%s",s+1);
 90     last=S=++cnt;
 91     int len=strlen(s+1);
 92     for(int i=1;i<=len;i++)a[i]=s[i]-'a';
 93     for(int i=1;i<=len;i++)add(i);
 94     for(int i=1,p=S;i<=len;i++)
 95     {
 96         p=ch[p][a[i]];r[p]++;
 97     }
 98     for(int i=1;i<=cnt;i++)b[l[i]]++;
 99     for(int i=1;i<=len;i++)b[i]+=b[i-1];
100     for(int i=1;i<=cnt;i++)t[b[l[i]]--]=i;
101     for(int i=cnt;i;i--)r[fa[t[i]]]+=r[t[i]];
102     for(int i=1;i<=cnt;i++)f[l[i]]=max(f[l[i]],r[i]);
103     for(int i=len;i;i--)f[i]=max(f[i+1],f[i]);
104     for(int i=1;i<=len;i++)printf("%d\n",f[i]);
105     return 0;
106 }

 

posted @ 2017-10-19 23:17  抓不住Jerry的Tom  阅读(241)  评论(0编辑  收藏  举报