spoj 1812 LCS2 - Longest Common Substring II (后缀自己主动机)

spoj 1812 LCS2 - Longest Common Substring II

题意:

给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串。

限制:

1 <= n <= 10

|A[i]| <= 1e5

思路:

和spoj 1811 LCS几乎相同的做法

把当中一个A建后缀自己主动机

考虑一个状态s, 假设A之外的其它串对它的匹配长度各自是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1], Max(s))就能够更新答案。

注意:

我们求的是对于随意一个Right集合中的r。最大的匹配长度。那么对于一个状态s。它的结果自然也能够作为它Parent的结果,我们能够从底到上更新一遍。

这个能够通过一次拓扑排序搞定。

/*spoj 1812 LCS2 - Longest Common Substring II
  题意:
  给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串。

限制:
  1 <= n <= 10
  |A[i]| <= 1e5
  思路:
  和spoj 1811 LCS几乎相同的做法

  把当中一个A建后缀自己主动机
  考虑一个状态s, 假设A之外的其它串对它的匹配长度各自是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1], Max(s))就能够更新答案。

注意:
  我们求的是对于随意一个Right集合中的r,最大的匹配长度。那么对于一个状态s,它的结果自然也能够作为它Parent的结果。我们能够从底到上更新一遍。
  这个能够通过一次拓扑排序搞定。

*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1e5 + 5;
char str[15][N];

int maxx[2 * N], minn[2 * N];

struct SAM {
	struct Node {
		int fa, ch[27];
		int val;
		void init() {
			fa = val = 0;
			memset(ch, 0, sizeof(ch));
		}
	} node[2 * N];

	int tot;
	int new_node() {
		node[++tot].init();
		return tot;
	}

	int root, last;
	void init() {
		root = last = tot = 1;
		node[0].init();
		node[1].init();
	}

	void add(int x) {
		int p = last;
		int np = new_node(); node[np].val = node[p].val + 1;
		while(p && node[p].ch[x] == 0) {
			node[p].ch[x] = np;
			p = node[p].fa;
		}
		if(p == 0)
			node[np].fa = root;
		else {
			int q = node[p].ch[x];
			if(node[p].val + 1 == node[q].val)
				node[np].fa = q;
			else {
				int nq = new_node(); node[nq].val = node[p].val + 1;
				memcpy(node[nq].ch, node[q].ch, sizeof(node[q].ch));
				node[nq].fa = node[q].fa;
				node[q].fa = node[np].fa = nq;
				while(p && node[p].ch[x] == q) {
					node[p].ch[x] = nq;
					p = node[p].fa;
				}
			}
		}
		last = np;
	}
	void debug() {
		for(int i = 1; i <= tot; ++i) {
			printf("id=%d, fa=%d, step=%d, ch=[ ", i, node[i].fa, node[i].val);
			for(int j = 0; j < 26; ++j) {
				if(node[i].ch[j])
					printf("%c,%d ", j+‘a‘, node[i].ch[j]);
			}
			puts("]");
		}
	}

	void gao(int);
} sam;

int du[2 * N];
int que[2 * N], fr, ta;
int b[2 * N], b_tot;

void SAM::gao(int n) {
	init();
	int len1 = strlen(str[0]);
	for(int i = 0; i < len1; ++i)
		add(str[0][i] - ‘a‘);

	//debug();

	b_tot = fr = ta = 0;
	for(int i = 1; i <= tot; ++i)
		++du[node[i].fa];
	for(int i = 1; i <= tot; ++i)
		if(du[i] == 0) que[ta++] = i, b[b_tot++] = i;
	while(fr != ta) {
		int u = que[fr++];
		int v = node[u].fa;
		--du[v];
		if(du[v] == 0) que[ta++] = v, b[b_tot++] = v;
	}

	for(int i = 1; i <= tot; ++i)
		minn[i] = node[i].val;
	for(int i = 1; i < n; ++i) {
		int len = strlen(str[i]);
		int p = root;
		int tmp = 0;
		fill(maxx, maxx + tot + 1, 0);
		for(int j = 0; j < len; ++j) {
			int x = str[i][j] - ‘a‘;
			if(node[p].ch[x]) {
				++tmp;
				p = node[p].ch[x];
			} else {
				while(p && node[p].ch[x] == 0)
					p = node[p].fa;
				if(p) {
					tmp = node[p].val + 1;
					p = node[p].ch[x];
				} else {
					p = root;
					tmp = 0;
				}
			}
			maxx[p] = max(maxx[p], tmp);
		}
		for(int j = 0; j < tot; ++j) {
			int u = b[j];
			minn[u] = min(minn[u], maxx[u]);
			int v = node[u].fa;
			maxx[v] = max(maxx[v], maxx[u]);
		}
	}
	int ans = 0;
	for(int i = 1; i <= tot; ++i)
		ans = max(ans, minn[i]);
	printf("%d\n", ans);
}

int main() {
	int n = 0;
	while(scanf("%s", str[n]) != EOF) ++n;
	sam.gao(n);
	return 0;
}
时间: 2024-12-26 04:07:16

spoj 1812 LCS2 - Longest Common Substring II (后缀自己主动机)的相关文章

spoj 1812 LCS2 - Longest Common Substring II (后缀自动机)

spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 <= n <= 10 |A[i]| <= 1e5 思路: 和spoj 1811 LCS差不多的做法 把其中一个A建后缀自动机 考虑一个状态s, 如果A之外的其他串对它的匹配长度分别是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1]

SPOJ 1812 LCS2 - Longest Common Substring II (后缀自动机)【两种做法】

手动博客搬家: 本文发表于20181217 23:54:35, 原地址https://blog.csdn.net/suncongbo/article/details/85058680 人生第一道后缀自动机. 说实话SAM我还没学多么明白. 但是题还是要做的. 说起来这玩意真的很妙.可惜我智商低理解不了. 再次验证了代码能力菜到没边.hyw 30min写完我写2.5h. 题目链接 (洛谷) https://www.luogu.org/problemnew/show/SP1812 题目大意 给\(n

spoj1812 LCS2 - Longest Common Substring II

地址:http://www.spoj.com/problems/LCS2/ 题面: LCS2 - Longest Common Substring II no tags A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor, is a cons

Spoj LCS2 - Longest Common Substring II

题目描述 A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string. Now your t

SPOJ - LCS2 Longest Common Substring II(后缀自动机)题解

题意: 求\(n\)个串的最大\(LCS\). 思路: 把第一个串建后缀自动机,然后枚举所有串.对于每个串,求出这个串在\(i\)节点的最大匹配为\(temp[i]\)(当前串在这个节点最多取多少),然后我们求出最终所有串在\(i\)节点的匹配最小值\(mn[i]\)(即为所有串在\(i\)节点都能取到多少),答案即为\(max\{min[i]\}\). 但是我们能发现,如果我们更新了\(temp[i]\),那么其实\(fa[i]\)的\(temp[fa[i]]\)也应该要更新,因为父节点是我的

SPOJ LCS2 - Longest Common Substring II 字符串 SAM

原文链接http://www.cnblogs.com/zhouzhendong/p/8982484.html 题目传送门 - SPOJ LCS2 题意 求若干$(若干<10)$个字符串的最长公共连续子串长度. 串长$\leq 100000$ 题解 建议在做本题之前,先去做SPOJ LCS,本题是其升级版. 题解链接 - SPOJ LCS - http://www.cnblogs.com/zhouzhendong/p/8982392.html 对于本题,我们只需要保持一下之后每一个串在第一个串的$

spoj1812 Longest Common Substring II( 后缀自动机 )

贴个代码... --------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 200009; const int cn = 26; struct Node { Node *fa, *ch[cn]; int le

SP1812 LCS2 - Longest Common Substring II

\(\color{#0066ff}{ 题目描述 }\) 题面描述 给定一些字符串,求出它们的最长公共子串 输入格式 输入至多\(10\) 行,每行包含不超过\(100000\) 个的小写字母,表示一个字符串 输出格式 一个数,最长公共子串的长度 若不存在最长公共子串,请输出\(0\) . \(\color{#0066ff}{输入格式}\) 几个字符串 \(\color{#0066ff}{输出格式}\) 一个整数,为 所求答案 \(\color{#0066ff}{输入样例}\) alsdfkjfj

SPOJ LCS2 1812. Longest Common Substring II

SPOJ Problem Set (classical) 1812. Longest Common Substring II Problem code: LCS2 A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor, is a consecu