【传送门:SPOJ8222】
简要题意:
给出一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值。求F(1)..F(Lengh(S));
题解:
后缀自动机的模板题(会SAM是没有用的,会DP和广义才有用——Cherish_OI)
只要求出每个状态的Right集合的个数就可以求出当前状态的相同子串的个数
然后DP就好了
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct SAM { int son[27],fail,dep; }tr[510000];int cnt,last,root; int a[310000]; void add(int k) { int x=a[k]; int np=++cnt,p=last;tr[np].dep=k; while(p!=0&&tr[p].son[x]==0) tr[p].son[x]=np,p=tr[p].fail; if(p==0) tr[np].fail=root; else { int q=tr[p].son[x]; if(tr[q].dep==tr[p].dep+1) tr[np].fail=q; else { int nq=++cnt;tr[nq]=tr[q]; tr[nq].dep=tr[p].dep+1; tr[q].fail=tr[np].fail=nq; while(p!=0&&tr[p].son[x]==q) tr[p].son[x]=nq,p=tr[p].fail; } } last=np; } int r[510000],f[310000]; char st[310000]; int Rsort[5100000],sa[510000]; int main() { scanf("%s",st+1); int len=strlen(st+1); cnt=root=last=1; for(int i=1;i<=len;i++) a[i]=st[i]-'a'+1,add(i); for(int i=1;i<=cnt;i++) Rsort[tr[i].dep]++; for(int i=1;i<=len;i++) Rsort[i]+=Rsort[i-1]; for(int i=1;i<=cnt;i++) sa[Rsort[tr[i].dep]--]=i; int p=root; for(int i=1;i<=len;i++) p=tr[p].son[a[i]],r[p]++; for(int i=cnt;i>=1;i--) r[tr[sa[i]].fail]+=r[sa[i]]; memset(f,0,sizeof(f)); for(int i=1;i<=cnt;i++) f[tr[i].dep]=max(f[tr[i].dep],r[i]); for(int i=len-1;i>=1;i--) f[i]=max(f[i+1],f[i]); for(int i=1;i<=len;i++) printf("%d ",f[i]); return 0; }