您的位置:首页 > 其它

spoj8222:Substrings 后缀自动机+DP

2016-03-22 16:20 288 查看
看后缀自动机看的真是生不如死,人太弱表示看不懂,现在还是没有完全理解啊。

这是一道SAM的入门题。

我们首先构造出SAM,然后SAM中每个节点i有一个righti和leni,那么长度在(lenfai,leni]内的都出现了righti次。考虑如果一个长度为leni的出现了x次,那么长度<leni的一定也至少出现了x次,所以我们可以直接算每个righti对leni的贡献。最后递推更新一下答案令fi=max(fi,fi+1)就好了。

现在还有一个问题没解决,就是righti的求法,我们只需要righti的大小而不需要集合内究竟是哪些数,所以可以开始给每个代表s[1..i]的节点i的righti=1,然后按深度合并一下,就能O(|S|)内求出所有的right了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500005
using namespace std;
char s
;
int S,n,cnt,last;
int a[N],f[N],t[N],fa[N],cc[N],len[N],r[N],ch[N][26];
inline void insert(int x)
{
int c=a[x];
int p=last,np=++cnt; last=np;
len[np]=x;
while (p&&!ch[p][c]) ch[p][c]=np,p=fa[p];
if (!p) fa[np]=S;
else
{
int q=ch[p][c];
if (len[p]+1==len[q]) fa[np]=q;
else
{
int nq=++cnt;
len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q]; fa[np]=fa[q]=nq;
while (ch[p][c]==q) ch[p][c]=nq,p=fa[p];
}
}
}
int main()
{
scanf("%s",s+1);
last=S=++cnt;
n=strlen(s+1);
for (int i=1;i<=n;i++)
a[i]=s[i]-'a';
for (int i=1;i<=n;i++)
insert(i);
for (int i=1,p=S;i<=n;i++)
p=ch[p][a[i]],r[p]++;
for (int i=1;i<=cnt;i++) ++cc[len[i]];
for (int i=1;i<=n;i++) cc[i]+=cc[i-1];
for (int i=1;i<=cnt;i++) t[cc[len[i]]--]=i;
for (int i=cnt;i;i--) r[fa[t[i]]]+=r[t[i]];
for (int i=1;i<=cnt;i++) f[len[i]]=max(f[len[i]],r[i]);
for (int i=n;i;i--) f[i]=max(f[i],f[i+1]);
for (int i=1;i<=n;i++) printf("%d\n",f[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: