码迷,mamicode.com
首页 > 其他好文 > 详细

【后缀自动机】SPOJ 8222-最多重复子串

时间:2015-01-11 15:59:35      阅读:249      评论:0      收藏:0      [点我收藏+]

标签:

题意:

  一个长度不超过250000的字符串,求出它长度为i的子串最多出现了多少次。

  技术分享

  后缀自动机练习题...虽说是用Cube评测的不过时限仍然鬼畜。

 

考虑SAM的性质:

  一个串的SAM肯定可以接受这个串的所有子串。SAM上的每一个点代表了一个子串。

  主链:SAM上最长的那条链,也就是说从根走到主链的尾端就是整个字符串。

 

  用t[i]记录i号点表示的子串的出现次数,沿着主链走一遍,很明显,主链上所有的点都代表了一个前缀,每个前缀都出现过。因此主链上的点的t初始值为1。

  接着,之前提到过,一个点的pre上的点和它,这些点表示的子串,具有相同的后缀。

  既然i出现过,那么i.pre肯定出现过。因此对一个点+1就代表对整条pre链+1。

  最后,因为step[i]表示i的长度,因此对于所有的step[i]取一个最大值,记录到ans中就可以了。

 

这次换了个SAM的写法,把之前的for循环改成了while,结果忘记了一个迭代步骤,调了统计过程很久才发现原来是SAM构错了...

一开始写的是t[i]+1之后,沿着pre链,将i的pre上的所有点都+1,结果TLE了。参考了一下沐阳神犇的代码,发现只要统计前缀和就行了...

 

技术分享
 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #define maxn 255000*2
 6 using namespace std;
 7 
 8 struct node { int s[26],num,pre; } Suf[maxn];
 9 int step[maxn],ans[maxn],t[maxn],f[maxn];
10 int i,j,n,m,k,cnt = 1,last = 1,root = 1,len;
11 char S[maxn];
12 
13 void add(int nxt)
14 {
15     int now = ++cnt, p = last;
16     step[now] = step[p] + 1;
17     while ( p && !Suf[p].s[nxt] ) Suf[p].s[nxt] = now, p = Suf[p].pre;
18     if (!p) Suf[now].pre = root;
19     else
20     {
21         int q = Suf[p].s[nxt];
22         if (step[q] == step[p] + 1) Suf[now].pre = q;
23         else
24         {
25             int nq = ++cnt;
26             step[nq] = step[p] + 1;
27             Suf[nq] = Suf[q];
28             Suf[q].pre = Suf[now].pre = nq;
29             while ( p && Suf[p].s[nxt] == q ) Suf[p].s[nxt] = nq,p = Suf[p].pre;
30         }
31     }
32     last = now;
33 }
34 
35 bool cmp(int a,int b) { return step[a] < step[b]; }
36 
37 int main()
38 {
39     len = strlen(S+1);
40     
41     for (i = 1; i <= len; i++) add(S[i]-a); 
42     
43     for (i = 1; i <= cnt; i++) f[i] = i;
44     stable_sort(f+1,f+1+cnt,cmp);
45     
46     int now = root;
47     for (i = 1; i <= len; i++)
48     {
49         now = Suf[now].s[S[i]-a];
50         t[now]++;
51     }
52     
53     for (i = cnt; i > 1; i--)
54     {
55         ans[step[f[i]]] = max(ans[step[f[i]]],t[f[i]]);
56         if (Suf[f[i]].pre > 1) t[Suf[f[i]].pre] += t[f[i]];
57     }
58     
59     for (i = 1; i <= len; i++)
60         printf("%d\n",ans[i]);
61     
62     return 0;
63 }
SPOJ 8222

 

 

 

 

  

 

【后缀自动机】SPOJ 8222-最多重复子串

标签:

原文地址:http://www.cnblogs.com/Tsuki/p/4216550.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!