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)..F(Length(S)) (感谢clj的翻译>_<)

首先按顺序建SAM。一个串的|Right|就是出现次数。

因为父节点的Right集合正好等于子节点Right集合的并集,于是能够拓扑排序从后往前找,然后每次再把子节点的Right加到pre节点上就可以。这里拓扑排序使用了类似于计数排序的思想。见代码

#include<iostream>//SAM
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=250005<<1;
int last,tot,son[N][26],pre[N],step[N],cnt[N],Q[N],g[N],f[N];
char s[N];
void ins(int x,int m){
	int p=last,np=++tot;
	step[np]=m,last=np,g[np]++;
	for(;!son[p][x] && p!=-1;p=pre[p])	son[p][x]=np;
	if(p==-1)	return;
	else{
		int q=son[p][x];
		if(step[q]==step[p]+1)	pre[np]=q;
		else{
			step[++tot]=step[p]+1;
			int nq=tot;
			memcpy(son[nq],son[q],sizeof(son[q]));
			pre[nq]=pre[q];
			pre[q]=pre[np]=nq;
			for(;son[p][x]==q && p!=-1;p=pre[p])	son[p][x]=nq;
		}
	}
}
int main(){
	pre[0]=-1;
	scanf("%s",s);
	int l=strlen(s);
	for(int i=0;i<l;++i)	ins(s[i]-‘a‘,i+1);
	for(int i=1;i<=tot;++i)	cnt[step[i]]++;
	for(int i=1;i<=tot;++i)	cnt[i]+=cnt[i-1];
	for(int i=1;i<=tot;++i)	Q[cnt[step[i]]--]=i;
	for(int i=tot;i>=1;--i)	printf("%d\n",step[Q[i]]);
	for(int i=tot;i>=1;--i)	f[step[Q[i]]]=max(f[step[Q[i]]],g[Q[i]]),g[pre[Q[i]]]+=g[Q[i]];
	for(int i=1;i<=l;++i)	printf("%d\n",f[i]);
	return 0;
}
时间: 2024-11-05 02:37:28

SPOJ 8222 NSUBSTR(SAM)的相关文章

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)

后缀自动机理解关键点: 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

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) w

ACM中常用算法----字符串

ACM中常用算法--字符串 ACM中常用的字符串算法不多,主要有以下几种: Hash 字典树 KMP AC自动机 manacher 后缀数组 EX_KMP SAM(后缀自动机) 回文串自动机 下面来分别介绍一下: 0. Hash 字符串的hash是最简单也最常用的算法,通过某种hash函数将不同的字符串分别对应到不同的数字.进而配合其他数据结构或STL可以做到判重,统计,查询等操作. #### 字符串的hash函数: 一个很简单的hash函数代码如下: ull xp[maxn],hash[max

后缀自动机详解 -----转载

转载于:http://blog.csdn.net/qq_35649707/article/details/66473069 原论文(俄文)地址:suffix_automata 后缀自动机 后缀自动机(单词的有向无环图)——是一种强有力的数据结构,让你能够解决许多字符串问题. 例如,使用后缀自动机可以在某一字符串中搜索另一字符串的所有出现位置,或者计算不同子串的个数——这都能在线性 时间内解决. 直觉上,后缀自动机可以被理解为所有子串的简明信息.一个重要的事实是,后缀自动机以压缩后的形式包含了一个

后缀自动机(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 流行了起来. 一般来说.能用后缀自己主动机解决的问题都能够用后缀数组解决.可是后缀自己