zoukankan      html  css  js  c++  java
  • SPOJ LCS2 (后缀自动机)

    SPOJ LCS2

    Problem : 给若干个串,询问这些串的最长公共子串。
    Solution :对第一个串建立后缀自动机,对于之后的每个串在后缀自动机上进行匹配。每个节点记录当前串所匹配到的长度以及所有串所匹配到的长度最小值,需要注意的是如果一个串在某个节点匹配成功,那么其fail到根的路径的所有节点都可以匹配成功,需要在最后建立出fail后缀树,进行一遍dfs进行更新。

    #include <iostream>
    #include <string>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 100008;
    
    struct node
    {
    	int u, v, nt;
    };
    
    struct Suffix_Automaton
    {
    	int nt[N << 1][26], fail[N << 1], a[N << 1];
    	int tot, root, last;
    	int p, q, np, nq;
    	node eg[N << 2];
    	int lt[N << 1], sum;
    
    	int qmax[N << 1], qmin[N << 1];
    
    	void add(int u, int v)
    	{
    		eg[++sum] = (node){u, v, lt[u]}; lt[u] = sum;
    		eg[++sum] = (node){v, u, lt[v]}; lt[v] = sum;
    	}
    	int newnode(int len)
    	{
    		for (int i = 0; i < 26; ++i) nt[tot][i] = -1;
    		fail[tot] = -1; a[tot] = len;
    		return tot++;
    	}
    	void clear()
    	{
    		last = tot = sum = 0;
    		memset(lt, 0, sizeof(lt));
    		root = newnode(0);
    	}	
    	void insert(char ch)
    	{
    		p = last; last = np = newnode(a[p] + 1);
    		for (; ~p && nt[p][ch] == -1; p = fail[p]) nt[p][ch] = np;
    		if (p == -1) fail[np] = root;
    		else
    		{
    			q = nt[p][ch];
    			if (a[q] == a[p] + 1) fail[np] = q;
    			else
    			{
    				nq = newnode(a[p] + 1);
    				for (int i = 0; i < 26; ++i) nt[nq][i] = nt[q][i];
    				fail[nq] = fail[q];
    				fail[q] = fail[np] = nq;
    				for (; ~p && nt[p][ch] == q; p = fail[p]) nt[p][ch] = nq;
    			}
    		}
    	}
    	void build()
    	{
    		for (int i = 1; i < tot; ++i) add(fail[i], i);
    		for (int i = 1; i < tot; ++i) qmin[i] = a[i];
    	}
    	void dfs(int u, int fa)
    	{
    		for (int i = lt[u]; i; i = eg[i].nt)
    		{
    			if (eg[i].v != fa)
    			{
    				dfs(eg[i].v, u);
    				if (qmax[eg[i].v]) qmax[u] = a[u];
    			}
    		}
    	}
    	void solve(const string &s)
    	{
    		int p = root, cnt = 0;
    		for (int i = 0; i < tot; ++i) qmax[i] = 0;
    		for (int i = 0, len = s.length(); i < len; ++i)
    		{
    			int ch = s[i] - 'a';
    			if (~nt[p][ch]) ++cnt, p = nt[p][ch];
    			else
    			{
    				for (; ~p && nt[p][ch] == -1; p = fail[p]);
    				if (p == -1) cnt = 0, p = root;
    				else
    				{
    					cnt = a[p] + 1;
    					p = nt[p][ch];
    				}
    			}
    			qmax[p] = max(qmax[p], cnt);
    		}
    		dfs(root, -1);
    		for (int i = 1; i < tot; ++i) qmin[i] = min(qmin[i], qmax[i]);
    	}
    }sam;
    
    int main()
    {
    	cin.sync_with_stdio(0);
    	string s;
    	cin >> s;
    	sam.clear();
    	for (int i = 0, len = s.length(); i < len; ++i)
    		sam.insert(s[i] - 'a');
    	sam.build();
    	while (cin >> s) sam.solve(s);
    	int ans = 0;
    	for (int i = 1; i < sam.tot; ++i) ans = max(ans, sam.qmin[i]);
    	cout << ans << endl;
    }
    
    
  • 相关阅读:
    【笔记】vue中websocket心跳机制
    【笔记】MySQL删除重复记录保留一条
    oss上传实例
    jquery实现图片点击旋转
    IDEA卡顿解决方法
    斐波那契数列
    【笔记】接口发送数据及接收
    【笔记】获取新浪财经最新的USDT-CNY的汇率
    【笔记】Java 信任所有SSL证书(解决PKIX path building failed问题)
    IDEA中报错“cannot resolve symbol toDF”,但编译正确可以运行
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/7217388.html
Copyright © 2011-2022 走看看