zoukankan      html  css  js  c++  java
  • 后缀自动机SAM与广义后缀自动机

    后缀自动机SAM

    参见sxTQX的博客

    后缀自动机的性质

    本质不同子串个数

    实际上是后缀自动机的DAG上DP,求DAG的路径数

    但是我们有不需要DP的做法

    答案为

    [sum_{i=2}^{tot}len[i]-len[fa[i]] ]

    设这个节点的最短长度为(minlen_u),最长长度为(len_u),那么这个节点包含的不同子串数是(maxlen-minlen+1)

    注意到(minlen_u=maxlen_{fa[u]}+1),就可以得到上面的结论了

    其他的很多问题都可以在DAG上DP完成

    求LCS

    即为(parent)树上的(LCA)(len)

    广义后缀自动机 广义SAM

    离线版

    将所有模式串插入Trie,对Trie进行bfs依次插入,插入过程与SAM基本相同,只不过要从Trie树上的父亲在SAM中对应的节点往后插入

    namespace SAM{
    	int ch[N][26],fa[N],len[N],tot=1;
    	inline int insert(int last,int a){
    		int cur=last,id=++tot;
    		len[id]=len[cur]+1;
    		for(;cur&&!ch[cur][a];cur=fa[cur])ch[cur][a]=id;
    		if(!cur){fa[id]=1;return id;}
    		int q=ch[cur][a];
    		if(len[q]==len[cur]+1){fa[id]=q;return id;}
    		int nq=++tot;fa[nq]=fa[q];fa[id]=fa[q]=nq;
    		for(int i=0;i<26;++i)ch[nq][i]=ch[q][i];
    		len[nq]=len[cur]+1;
    		for(;cur&&ch[cur][a]==q;cur=fa[cur])ch[cur][a]=nq;
    		return id;
    	}
    }
    namespace Trie{
    	int ch[N][26],rt=1,tot=1,fa[N];
    	inline void insert(char *s){
    		int n=strlen(s+1),a,cur=rt;
    		for(int i=1;i<=n;++i){
    			a=s[i]-'a';
    			if(!ch[cur][a])ch[cur][a]=++tot,fa[tot]=cur;
    			cur=ch[cur][a];
    		}
    	}
    	queue<int> q;
    	int pos[N];
    	inline void build(){
    		q.push(1);pos[1]=1;
    		while(!q.empty()){
    			int u=q.front();q.pop();
    			for(int i=0;i<26;++i)
    				if(ch[u][i]){
    					q.push(ch[u][i]);
    					pos[ch[u][i]]=SAM::insert(pos[u],i);
    				}
    		}
    	}
    }
    

    在线版

    咕咕咕

  • 相关阅读:
    hdu 3068 最长回文
    Educational Codeforces Round 1 C. Nearest vectors
    Educational Codeforces Round 6 C. Pearls in a Row
    poj 3304 Segments
    Toy Storage
    poj 2318 TOYS
    CFA二级中文精讲(第2版)
    探秘大香格里拉
    巴西:热辣里约
    巴西:性感圣保罗
  • 原文地址:https://www.cnblogs.com/harryzhr/p/14682495.html
Copyright © 2011-2022 走看看