zoukankan      html  css  js  c++  java
  • SPOJ NSUBSTR Substrings

    题意

    给出一个字符串S,令({F(x)})表示S的所有长度为x的子串出现次数的最大值。求({F(1)......F(length(S))})

    MashiroSky的题解

    另外我觉得他的总结写得也不错。

    后缀自动机例题,下面写几点自己认为理解后缀自动机的重点。

    • 后缀自动机相对于后缀树就是将Right集合相同的子串合用一个节点来表示。每一个节点代表一个状态S,这个状态可能包含很多长度区间连续的子串,这些子串的右端点固定,它们的Right集合相同。
    • 往上跳parent的过程相当于将子串的前面一节截掉,得到一个长度更短的子串,它们的Right集合变多了。走状态转移边的过程相当于在子串的后面添加新的字符,到达新的状态。
    • 构造过程中,情况一很好理解,考虑情况二和情况三的区别。情况二是parent中存在x边到达某一个状态({V_q}),并且这个状态的所有子串都可以接受当前插入的这个这个后缀。情况三是虽然存在状态({V_q}),但是这个状态所包含一部分长度比较长的的子串无法接受要插入的这个后缀,所以将它拆成两份,一份可以接受,一份不能接受。

    对于这道题,我们需要做的就是计算SAM中每个节点的Right集合的大小,即在串中的出现次数。因为parent树的某个节点Right集合是它父亲的真子集,所以我们考虑从parent树的底端向上不断更新祖先的Right集合。因为len更大的节点在parent树上肯定深度更深,所以用基数排序确定拓扑序,然后更新。由于是树形结构,所以不会重复计算。

    时间复杂度(O(|S|))

    代码

    随便取个名字都重名了。

    co int N=2.5e5+2;
    char s[N];
    int n,root,last,sz;
    int ch[N*2][26],len[N*2],link[N*2];
    void extend(int c){
    	int np=++sz,p=last;last=np;
    	len[np]=len[p]+1;
    	for(;p&&!ch[p][c];p=link[p]) ch[p][c]=np;
    	if(!p) link[np]=root;
    	else{
    		int q=ch[p][c];
    		if(len[q]==len[p]+1) link[np]=q;
    		else{
    			int nq=++sz;len[nq]=len[p]+1;
    			memcpy(ch[nq],ch[q],sizeof ch[q]);
    			link[nq]=link[q],link[np]=link[q]=nq;
    			for(;p&&ch[p][c]==q;p=link[p]) ch[p][c]=nq;
    		}
    	}
    }
    int b[N],ref[N*2],right[N*2],f[N];
    int main(){
    	// insert
    	scanf("%s",s+1),n=strlen(s+1);
    	root=last=sz=1;
    	for(int i=1;i<=n;++i) extend(s[i]-'a');
    	// topu-sort
    	for(int p=root,i=1;i<=n;++i) p=ch[p][s[i]-'a'],::right[p]=1;
    	for(int i=1;i<=sz;++i) ++b[len[i]];
    	for(int i=1;i<=n;++i) b[i]+=b[i-1];
    	for(int i=1;i<=sz;++i) ::ref[b[len[i]]--]=i;
    	for(int i=sz;i>=1;--i) ::right[link[::ref[i]]]+=::right[::ref[i]];
    	// solve
    	for(int i=1;i<=sz;++i) f[len[i]]=max(f[len[i]],::right[i]);
    	for(int i=n;i>=1;--i) f[i]=max(f[i],f[i+1]);
    	for(int i=1;i<=n;++i) printf("%d
    ",f[i]);
    	return 0;
    }
    
  • 相关阅读:
    C#生成MD5的方法
    平常心是道
    Android 三种动画的使用 – Tween Animation
    17个Javascript日期选择器
    Javascript解码编码常用函数
    mysql 命令行导入导出数据
    技术驱动还是产品驱动
    Ubuntu 和 Redhat / Fedora 服务管理命令对比表
    jquery常用技巧
    Fedora 17安装JDK1.7
  • 原文地址:https://www.cnblogs.com/autoint/p/10674088.html
Copyright © 2011-2022 走看看