spoj 8222 Substrings(后缀自动机+DP)

【题目链接】

  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28005  

【题意】

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

【思路】

    建立一个SAM。

  对于SAM的一个结点u所代表的串,它的长度为|min(u),max(u)|,出现次数为|right(s)|,出现次数可以通过fa边将max并到一块得到。

  max(fa)=min(u)-1

  这只考虑了结点的最长串,对于介于max(fa)与max(u)长度之间的串我们还需要按长度递推一遍,f[i]=max{ f[i+1],f[i] },这样保证长度i得到了至少应得到的值。

【代码】

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int N = 5*1e5+10;
 7 
 8 char s[N];
 9 int S,sz,last,ch[N][26],fa[N],l[N];
10 
11 void add(int x) {
12     int c=s[x]-'a';
13     int p=last,np=++sz; last=np;
14     l[np]=x;
15     for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
16     if(!p) fa[np]=S;
17     else {
18         int q=ch[p][c];
19         if(l[p]+1==l[q]) fa[np]=q;
20         else {
21             int nq=++sz; l[nq]=l[p]+1;
22             memcpy(ch[nq],ch[q],sizeof(ch[q]));
23             fa[nq]=fa[q];
24             fa[np]=fa[q]=nq;
25             for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
26         }
27     }
28 }
29 
30 int b[N],r[N],f[N],t[N];
31 
32 int main() {
33     scanf("%s",s+1);
34     last=S=++sz;
35     int len=strlen(s+1);
36     for(int i=1;i<=len;i++) add(i);
37     for(int i=1,p=S;i<=len;i++) {
38         p=ch[p][s[i]-'a']; r[p]++;
39     }
40     for(int i=1;i<=sz;i++) b[l[i]]++;
41     for(int i=1;i<=len;i++) b[i]+=b[i-1];
42     for(int i=1;i<=sz;i++) t[b[l[i]]--]=i;                 //基排 
43     for(int i=sz;i;i--) r[fa[t[i]]]+=r[t[i]];
44     for(int i=1;i<=sz;i++) f[l[i]]=max(f[l[i]],r[i]);
45     for(int i=len;i;i--) f[i]=max(f[i],f[i+1]);            //被包含的情况
46     for(int i=1;i<=len;i++) printf("%d
",f[i]);
47     return 0;
48 }
原文地址:https://www.cnblogs.com/lidaxin/p/5197527.html