spoj 8222

8222. Substrings

Problem code: NSUBSTR

You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as the maximal number of times that some string with length x appears in S. For example for string ‘ababa‘ F(3) will be 2 because there is a string ‘aba‘ that occurs twice. Your task is to output F(i) for every i so that 1<=i<=|S|.

Input

String S consists of at most 250000 lowercase latin letters.

Output

Output |S| lines. On the i-th line output F(i).

Example

Input:

ababa

Output:

3
2
2
1
1

题目大意:

给出一个字符串(len <= 2.5e5),求出这个串中,长度为 i (1 <= i <= len) 并且出现次数最多的串,并且输出出现次数.

思路:

根据Spoj1811所提出的这个性质,我们现在SAM上自己匹配自己.得到一个出事的状态.

不难发现.当这个点的后继(parnet关系)出现了之后,这点所表示的字符串也同样的出现了.

那么这个点所表示的字符串也出现了.

那么这个点所表示的字符串出现了多少次呢?

其实是这个点的后缀节点的和.......

然后我们就能够统计这个东西了.

我有个地方没有弄明白,就是,这个点所能够接受的字串有若干个....为什么只用判断这个最长的串呢?

一点初步的想法: 因为par表示这个点的所有的串的最长公共后缀,所以我们能够保证par至少 sz[x] 次,

虽然不知到为什么这个par表示的其他串不用计算,但是似乎在par更新par_par 的时候会计算进去.

根据意识流大法......好像是这么回事....下次再补上吧.

代码也就顺理成章了.

 1 #include<cstdlib>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn = (int)2.55e5, sigma = 26;
 7 char str[maxn];
 8 int cnt[maxn];
 9 int id[maxn];
10 int ans[maxn];
11 int cmp(int,int);
12 struct Sam{
13     int ch[maxn * 2][sigma],par[maxn * 2],stp[maxn * 2];
14     int sz,last;
15     void init(){
16         sz = last = 1;
17         memset(ch,0,sizeof(ch));
18         memset(par,0,sizeof(par));
19         memset(stp,0,sizeof(stp));
20     }
21     void add(int c){
22         stp[++sz] = stp[last] + 1;
23         int p = last, np = sz;
24         for(; !ch[p][c]; p = par[p]) ch[p][c] = np;
25         if(p == 0) par[np] = 1;
26         else{
27             int q = ch[p][c];
28             if(stp[q] != stp[p] + 1){
29                 stp[++sz] = stp[p] + 1;
30                 int nq = sz;
31                 memcpy(ch[nq],ch[q],sizeof(ch[q]));
32                 par[nq] = par[q];
33                 par[q] = par[np] = nq;
34                 for(; ch[p][c] == q; p = par[p]) ch[p][c] = nq;
35             }
36             else par[np] = q;
37         }
38         last = np;
39     }
40     void ins(char *pt){
41         int i;
42         init();
43         for(i = 0; pt[i]; ++i) add(pt[i] - ‘a‘);
44     }
45     void solve(char *pt){
46         memset(id,0,sizeof(id)); memset(cnt,0,sizeof(cnt)); memset(ans,0,sizeof(ans));
47         int i,p = 1;
48         for(i = 1; i <= sz; ++i) id[i] = i;
49         sort(id+1,id+sz+1,cmp);
50         for(i = 0; pt[i]; ++i)
51             ++cnt[p = ch[p][pt[i] - ‘a‘]];
52         for(i = 1; i <= sz; ++i){
53             ans[stp[id[i]]] = max(ans[stp[id[i]]], cnt[id[i]]);
54             if(par[id[i]] != 0) cnt[par[id[i]]] += cnt[id[i]];
55         }
56         for(i = 0; pt[i]; ++i) printf("%d\n",ans[i + 1]);
57     }
58 }sam;
59 int cmp(int x,int y){
60     return sam.stp[x] > sam.stp[y];
61 }
62 int main()
63 {
64     freopen("substr.in","r",stdin);
65     freopen("substr.out","w",stdout);
66     while(scanf("%s",str) != EOF){
67         sam.ins(str);
68         sam.solve(str);
69     }
70     return 0;
71 }

时间: 2024-12-08 05:39:36

spoj 8222的相关文章

SPOJ 8222 NSUBSTR Substrings

SAM的简单应用.... 由SAM可知从root到达的每个节点所经过的路径都对着应原串的一个子串,每个节点能到几次接收态就等于这个子串出现了几次.从最后一个节点往上走,就可以用DP更新出每个子串出现了多少次. 出现了5次的子串一定也出现了4,3,2,1次...所以最后再用长度长的给长度小的更新一下.... Substrings Time Limit: 1000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu [Submit]  

后缀自动机小结 (spoj 8222)

后缀自动机理解关键点: 1. 根到任意一个结点都可以形成S的一个子串,并且S的所有子串都可以通过这种方式形成; 2. 到达该节点是所有路径就是一个right集合,一个拥有相同后缀的right集合; 3. 设某子串为str,这后缀自动机读入str后能到达的状态为right(str),即str在S中出现的位置的集合; 4. 假设node[b].fa = a,则状态a可以代替状态b进行识别. 附图: 更详细的资料: http://wenku.baidu.com/view/90f22eec551810a

SPOJ 8222 Substrings(后缀自动机)

[题目链接] http://www.spoj.com/problems/NSUBSTR/ [题目大意] 给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值. 求出所有的F. [题解] 在SAM中,一个串出现的次数就是|Right(s)|,我们按长度从小到大分配内存单位, 从后往前计算可以获得Right值大小,用所有的Right去更新相应长度的答案即可. [代码] #include <cstdio> #include <cstring> #include <

●SPOJ 8222 NSUBSTR - Substrings

题链: http://www.spoj.com/problems/NSUBSTR/ 题解: 后缀自动机的水好深啊!懂不了相关证明,带着结论把这个题做了.看来这滩深水要以后再来了. 本题要用到一个叫 Right[P] 的数组,表示 P对应的子串在原串中出现的所有位置的末尾位置下标的集合.本题中,用这个数组存储集合大小就好了,即 P对应的子串在原串中出现了Right[p]次. 而Right[P]的值,等于从改点出发到结束状态的方案数.但这个不好求,而是要用到另一个求法:用 Parent树: (暂时由

SPOJ 8222 NSUBSTR(SAM)

这几天看了N多论文研究了下后缀自己主动机.刚開始蛋疼的看着极短的代码和clj的论文硬是看不懂,后来结合其它几篇论文研究了下.总算是明确了一些 推荐文章http://blog.sina.com.cn/s/blog_70811e1a01014dkz.html 看了几篇文章认为还是这篇写的清晰明了,建议看几遍明确怎样建SAM再看了clj的论文. clj的论文中对性质的研究比較深入 以下是clj论文里推荐的一题,题意:给一个字符串S,令F(x)表示S的全部长度为x的子串中,出现次数的最大值.求F(1).

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

题意: 一个长度不超过250000的字符串,求出它长度为i的子串最多出现了多少次. 后缀自动机练习题...虽说是用Cube评测的不过时限仍然鬼畜. 考虑SAM的性质: 一个串的SAM肯定可以接受这个串的所有子串.SAM上的每一个点代表了一个子串. 主链:SAM上最长的那条链,也就是说从根走到主链的尾端就是整个字符串. 用t[i]记录i号点表示的子串的出现次数,沿着主链走一遍,很明显,主链上所有的点都代表了一个前缀,每个前缀都出现过.因此主链上的点的t初始值为1. 接着,之前提到过,一个点的pre

后缀自动机(SAM)学习指南

*在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符串所有后缀的自动机. 它最早在陈立杰的 2012 年 noi 冬令营讲稿中提到. 在2013年的一场多校联合训练中,陈立杰出的 hdu 4622 可以用 SAM 轻松水过,由此 SAM 流行了起来. 一般来说,能用后缀自动机解决的问题都可以用后缀数组解决.但是后缀自动机也拥有自己的优点. 1812.

后缀自己主动机(SAM)学习指南

*在学习后缀自己主动机之前须要熟练掌握WA自己主动机.RE自己主动机与TLE自己主动机* 什么是后缀自己主动机 后缀自己主动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造.可以接受一个字符串全部后缀的自己主动机. 它最早在陈立杰的 2012 年 noi 冬令营讲稿中提到. 在2013年的一场多校联合训练中,陈立杰出的 hdu 4622 能够用 SAM 轻松水过.由此 SAM 流行了起来. 一般来说.能用后缀自己主动机解决的问题都能够用后缀数组解决.可是后缀自己

后缀自动机(SAM)

*在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符串所有后缀的自动机. 它最早在陈立杰的 2012 年 noi 冬令营讲稿中提到. 在2013年的一场多校联合训练中,陈立杰出的 hdu 4622 可以用 SAM 轻松水过,由此 SAM 流行了起来. 一般来说,能用后缀自动机解决的问题都可以用后缀数组解决.但是后缀自动机也拥有自己的优点. 1812.