zoukankan      html  css  js  c++  java
  • Longest Common Substring II SPOJ

    Longest Common Substring II

    [Time Limit: 236msquad Memory Limit: 1572864 kB ]

    题意

    给出(n)个子串,要求这(n)个子串的最长连续公共子串长度。

    思路

    • 前置技能:当 (n=2) 时的做法,可以先做做这题:SPOJ-LCS,我的博客:SPOJ-LCS题解
      这里为了方便,我们定义 (LCS) 为题中所求的最长连续公共子串。
    • (n>2) 时,我们可以对第一个串构建后缀自动机,然后用上一题一样的做法,求出后缀自动机上每个节点和当前串(LCS) ,用 (tmplen[i]) 数组来保存。那么当前节点对于所有串(LCS) 就是每一个串的 (tmplen[i]) 的最小值,用 (anslen[i]) 来表示。

    对于一个串,求出 (tmplen[i]) 是很好求的,在每次更新的时候加上一句话就可以了

    tmplen[p] = max(tmplen[p], res);
    

    但是这样会不会漏情况?答案是会的!我们现在只找到了当前串的在 (p) 节点的 (LCS) ,但是对于 (p)(father) 那些节点,是不是也会匹配上,只是长度更小而已?

    • (n=2) 的时候,不往 (father) 上更新,由于长度更短,所以并不会影响最终的答案。
    • (n>2) 的时候,这时候 (tmplen[father]) 虽然不会影响当前串的答案,但是它却会影响到全部串的 (anslen[father]) ,也就是说虽然 (father) 这个节点在当前串中不是最优答案,但他却可能是全部串的最优答案,所以我们需要将 (tmplen[i])(tmplen[father]) 上更新。

    那么要怎么更新呢?

    • 想想后缀自动机的性质,我们可以发现与(p)匹配的串,一定也可以与(node[p].fa)匹配上,又由于 (tmplen) 的含义是当前串的 (LCS),所以我们可以得到
    tmplen[father] = max(tmplen[father], tmplen[p]);
    
    • 但是取 (max) 的时候,我们又要限制不超出这个节点的总长度,进而得到
    tmplen[father] = min(tmplen[father], node[father].len);
    

    我这里比较懒,不想用基数排序,直接用 (dfs)(parent) 树上更新了,也是 (O(N)) 的复杂度。(代码中的变量和上述有差,但思路意思是一样的)。

    void dfs(int u) {
    	for(auto v : vv[u]) {
    		dfs(v);
    		tmplen[u] = max(tmplen[u], min(tmplen[v], node[u].len));
    	}
    }
    

    如此下来,我们就成功的将每一个串的 (tmplen) 求出来了,最后在更新一下 (anslen) ,最后的答案就是 (anslen) 中的最大值。

    #include <map>
    #include <set>
    #include <list>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <queue>
    #include <cfloat>
    #include <string>
    #include <vector>
    #include <cstdio>
    #include <bitset>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define  lowbit(x)  x & (-x)
    #define  mes(a, b)  memset(a, b, sizeof a)
    #define  fi         first
    #define  se         second
    #define  pii        pair<int, int>
    #define  INOPEN     freopen("in.txt", "r", stdin)
    #define  OUTOPEN    freopen("out.txt", "w", stdout)
    
    typedef unsigned long long int ull;
    typedef long long int ll;
    const int    maxn = 3e5 + 10;
    const int    maxm = 1e5 + 10;
    const ll     mod  = 1e9 + 7;
    const ll     INF  = 1e18 + 100;
    const int    inf  = 0x3f3f3f3f;
    const double pi   = acos(-1.0);
    const double eps  = 1e-8;
    using namespace std;
    
    int n, m;
    int cas, tol, T;
    
    struct SAM {
    	struct Node{
    		int next[27];
    		int len, fa;
    		void init() {
    			mes(next, 0);
    			fa = len = 0;
    		}
    	} node[maxn<<1];
    	vector<int> vv[maxn<<1];
    	int anslen[maxn<<1];
    	int tmplen[maxn<<1];
    	int sz, last;
    	void init() {
    		sz = last = 1;
    		node[1].init();
    	}
    	void insert(int k) {
    		int p = last, np = last = ++sz;
    		node[np].init();
    		node[np].len = node[p].len + 1;
    		for(; p&&!node[p].next[k]; p=node[p].fa)
    			node[p].next[k] = np;
    		if(p==0) {
    			node[np].fa = 1;
    		} else {
    			int q = node[p].next[k];
    			if(node[q].len == node[p].len+1) {
    				node[np].fa = q;
    			} else {
    				int nq = ++sz;
    				node[nq] = node[q];
    				node[nq].len = node[p].len+1;
    				node[np].fa = node[q].fa = nq;
    				for(; p&&node[p].next[k]==q; p=node[p].fa)
    					node[p].next[k] = nq;
    			}
    		}
    	}
    	void handle() {
    		for(int i=1; i<=sz; i++) {
    			vv[i].clear();
    			anslen[i] = node[i].len;
    		}
    		for(int i=2; i<=sz; i++) {
    			vv[node[i].fa].push_back(i);
    		}
    	}
    	void dfs(int u) {
    		for(auto v : vv[u]) {
    			dfs(v);
    			tmplen[u] = max(tmplen[u], min(tmplen[v], node[u].len));
    		}
    	}
    	void solve(char *s) {
    		mes(tmplen, 0);
    		int len = strlen(s+1);
    		int p = 1, res = 0;
    		for(int i=1; i<=len; i++) {
    			int k = s[i]-'a'+1;
    			while(p && !node[p].next[k]) {
    				p = node[p].fa;
    				res = node[p].len;
    			}
    			if(p==0) {
    				res = 0;
    				p = 1;
    			} else {
    				p = node[p].next[k];
    				res++;
    			}
    			tmplen[p] = max(tmplen[p], res);
    		}
    		dfs(1);
    		for(int i=1; i<=sz; i++) {
    			anslen[i] = min(anslen[i], tmplen[i]);
    		}
    	}
    } sam;
    char s[maxn];
    
    int main() {
    	sam.init();
    	scanf("%s", s+1);
    	int len = strlen(s+1);
    	for(int i=1; i<=len; i++) {
    		sam.insert(s[i]-'a'+1);
    	}
    	sam.handle();
    	int ans = 0;
    	while(~scanf("%s", s+1)) {
    		sam.solve(s);
    	}
    	for(int i=1; i<=sam.sz; i++) {
    		ans = max(ans, sam.anslen[i]);
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    Python 学习笔记(九)Python元组和字典(二)
    Python 学习笔记(九)Python元组和字典(一)
    Java适配器模式
    Java原型模式
    Java建造者模式
    java工厂模式
    封装图片处理方法
    TP中的图片水印
    THINKphp中复杂的查询
    THINKphp中常见的Request请求类
  • 原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/10903614.html
Copyright © 2011-2022 走看看