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\n",f[i]); 47 return 0; 48 }
posted on 2016-02-18 11:03 hahalidaxin 阅读(367) 评论(0) 编辑 收藏 举报