【SPOJ -NSUBSTR】Substrings 【后缀自动机+dp】

题意

 给出一个字符串,要你找出所有长度的子串分别的最多出现次数。

分析

  我们建出后缀自动机,然后预处理出每个状态的cnt,cnt[u]指的是u这个状态的right集合大小。我们设f[len]为长度为len的子串的最多出现次数。我们对于自动机的每个状态都更新f,f[st[u].len]=max(f[st[u].len],cnt[u])。然后这样更新完以后,可以神奇的dp一下。f[len]=max(f[len],f[len+1]).想想为什么?

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 
 6 using namespace std;
 7 const int maxn=250000+100;
 8 char s[maxn];
 9 int n;
10 struct state{
11     int len,link;
12     int ch[26];
13 }st[maxn*2];
14 int sz,last,cur,cnt[2*maxn],c[2*maxn],f[maxn];
15 void init(){
16     cur=last=0;
17     sz=1;
18     st[0].link=-1;
19     st[0].len=0;
20     memset(st[0].ch,-1,sizeof(st[0].ch));
21 }
22 void build_sam(int c){
23     cur=sz++;
24     st[cur].len=st[last].len+1;
25     cnt[cur]=1;
26     memset(st[cur].ch,-1,sizeof(st[cur].ch));
27     int p;
28     for(p=last;p!=-1&&st[p].ch[c]==-1;p=st[p].link)
29         st[p].ch[c]=cur;
30     if(p==-1)
31         st[cur].link=0;
32     else{
33         int q=st[p].ch[c];
34         if(st[q].len==st[p].len+1)
35             st[cur].link=q;
36         else{
37             int clone=sz++;
38             st[clone].len=st[p].len+1;
39             st[clone].link=st[q].link;
40             for(int i=0;i<26;i++)
41                 st[clone].ch[i]=st[q].ch[i];
42             for(;p!=-1&&st[p].ch[c]==q;p=st[p].link)
43                 st[p].ch[c]=clone;
44             st[q].link=st[cur].link=clone;
45         }
46     }
47     last=cur;
48 }
49 int cmp(int a,int b){
50     return st[a].len>st[b].len;
51 }
52 int main(){
53     scanf("%s",s);
54     n=strlen(s);
55     init();
56     for(int i=0;i<n;i++)
57         build_sam(s[i]-'a');
58     for(int i=0;i<sz;i++)
59         c[i]=i;
60     sort(c,c+sz,cmp);
61 //    for(int i=0;i<sz;i++){
62 //        printf("%d
",st[i].link);
63 //    }
64 //    printf("!!
");
65 
66     for(int i=0;i<sz;i++){
67         int o=c[i];
68         cnt[st[o].link]+=cnt[o];
69     }
70 //    for(int i=0;i<sz;i++)
71 //        printf("%d ",cnt[i]);
72 //    printf("
");
73 
74     for(int i=0;i<sz;i++)
75         f[st[i].len]=max(f[st[i].len],cnt[i]);
76     for(int i=n-1;i>=1;i--)
77         f[i]=max(f[i],f[i+1]);
78     for(int i=1;i<=n;i++){
79         printf("%d
",f[i]);
80     }
81 return 0;
82 }
View Code
原文地址:https://www.cnblogs.com/LQLlulu/p/9882228.html