SPOJ NSUBSTR

题目大意:

给定一个字符串,求每个对应的长度能产生的相同子串的最大个数

这里构建好后缀自动机之后,再将整个字符串从头到尾扫一遍,然后将每个对应的点上的sc值+1

表示从头走到尾的前提下,所能产生的子串能够得到的最大数量为1

然后再去考虑其他子串

每个后缀自动机上的节点上的长度表示的是当前点所能接收的最大长度的后缀

我们只考虑这个最大长度即可,因为其他没考虑的长度,最后都不断通过dp[i] = max(dp[i] , dp[i+1]) 得到即可

拓扑排序后,从尾节点开始不断往前,相当于由子节点不断更新父节点所能得到的值

也就是b[i]->f->sc += b[i]->sc;

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4
 5 using namespace std;
 6 #define N 500010
 7 #define M 26
 8
 9 struct SamNode{
10     SamNode *son[26] , *f;
11     int l , sc;
12 }*root , *last , sam[N] , *b[N];
13
14 int cnt , dp[N] , num[N];
15 char s[N];
16
17 void init(){
18     root = last = &sam[cnt=0];
19 }
20
21 void add(int x)
22 {
23     SamNode *p = &sam[++cnt] , *jp=last;
24     p->l = jp->l+1;
25     last = p;
26     for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x]=p;
27     if(!jp) p->f = root;
28     else{
29         if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];
30         else{
31             SamNode *r = &sam[++cnt] , *q = jp->son[x];
32             *r = *q;
33             r->l = jp->l+1;
34             q->f = p->f = r;
35             for( ; jp && jp->son[x]==q ; jp=jp->f) jp->son[x]=r;
36         }
37     }
38 }
39
40
41 void solve()
42 {
43     init();
44     int len = strlen(s);
45     for(int i=0 ; i<len ; i++) add(s[i]-‘a‘);
46     //后面三个for循环相当于进行拓扑排序
47     for(int i=0 ; i<=cnt ; i++) num[sam[i].l]++;
48     for(int i=1 ; i<=len ; i++) num[i]+=num[i-1];
49     for(int i=0 ; i<=cnt ; i++) b[--num[sam[i].l]] = &sam[i];
50
51     SamNode *cur = root;
52     for(int i=0 ; i<len ; i++){
53         cur = cur->son[s[i]-‘a‘];
54         cur->sc++;
55     }
56     for(int i=cnt ; i>0 ; i--){
57         int l = b[i]->l;
58         dp[l] = max(dp[l] , b[i]->sc);
59         b[i]->f->sc += b[i]->sc;
60     }
61     for(int i=len-1 ; i>=1 ; i--) dp[i]=max(dp[i] , dp[i+1]);
62     for(int i=1 ; i<=len ; i++) printf("%d\n" , dp[i]);
63 }
64
65 int main()
66 {
67    // freopen("a.in" , "r" , stdin);
68     scanf("%s" , s);
69     solve();
70     return 0;
71 }
时间: 2024-10-29 13:31:57

SPOJ NSUBSTR的相关文章

SPOJ - NSUBSTR 后缀自动机板子

SPOJ - NSUBSTR #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> #define PLI pair<LL, int> #define PDD pair<double,double> #define ull unsigned long long

SPOJ NSUBSTR - Substrings

NSUBSTR - Substrings no tags 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 b

并不对劲的[spoj nsubstr]substrings

题意是求一个字符串每个长度的子串出现次数最多的那个出现了多少次,也就是求每个到根的最长路的right集合最大值 . 先建后缀自动机,然后将每个前缀所在的集合的初值设为1,因为所有前缀的right集合肯定不相同,而且它们包含了所有位置. 接下来按到根的最长距离从大到小排序,将right集合累加到parent上.这么排序是因为到根的最长距离长的状态肯定不是到根的最长距离短的状态的parent. 最后直接求到根的不同的最长距离的最大的right集合就行. #include<iostream> #in

【SPOJ -NSUBSTR】Substrings 【后缀自动机+dp】

题意 给出一个字符串,要你找出所有长度的子串分别的最多出现次数. 分析 我们建出后缀自动机,然后预处理出每个状态的cnt,cnt[u]指的是u这个状态的right集合大小.我们设f[len]为长度为len的子串的最多出现次数.我们对于自动机的每个状态都更新f,f[st[u].len]=max(f[st[u].len],cnt[u]).然后这样更新完以后,可以神奇的dp一下.f[len]=max(f[len],f[len+1]).想想为什么? 1 #include <cstdio> 2 #inc

后缀自动机/后缀树

只是笔记罢了,不要看 关于DAWG: 见紫书P390 把后缀自动机上所有节点都设为接受态就形成DAWG,可以接受一个字符串的所有子串. 一个子串的end-set是它在原串w中出现位置(从1开始编号)的右端点集合. 在DAWG中,end-set相同的子串属于同一个状态. 原因没原因,这应该算定义吧? 任意两个节点的end-set要么不相交,要么是包含关系. 原因:在DAWG上走一步,当前end-set的变化是将原end-set中各个元素+1(要去掉超出字符串长度的元素),然后拆分成1个或多个新en

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 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 Substrings(后缀自动机)

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