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

  对于本题,我们只需要保持一下之后每一个串在第一个串的$SAM$的每一个状态上的最大匹配长度,然后最后对于每一个状态,取$min(该状态的Max值,其他所有字符串在该状态上面的最大匹配长度的最小值)$即可。

  于是,我们先像SPOJ LCS一样,让所有串都走一遍,然后记录一下值。

  注意到,每一个状态的结果都会对其$fa$做贡献。

  于是我们可以基数排序预处理拓扑序,然后逆序更新即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=200005;
int n,m=0,last=1,size=1,Max[15][N];
int id[N],tax[N];
char s[N];
struct SAM{
	int Next[26],fa,Max;
}t[N];
void expend(int c){
	int p=last,np=++size,q,nq;
	t[np].Max=t[p].Max+1;
	for (;!t[p].Next[c];p=t[p].fa)
		t[p].Next[c]=np;
	q=t[p].Next[c];
	if (t[q].Max==t[p].Max+1)
		t[np].fa=q;
	else {
		nq=++size;
		t[nq]=t[q],t[nq].Max=t[p].Max+1;
		t[q].fa=t[np].fa=nq;
		for (;t[p].Next[c]==q;p=t[p].fa)
			t[p].Next[c]=nq;
	}
	last=np;
}
int main(){
	t[0].Max=-1;
	for (int i=0;i<26;i++)
		t[0].Next[i]=1;
	gets(s);
	n=strlen(s);
	for (int i=0;i<n;i++)
		expend(s[i]-‘a‘);
	for (int i=1;i<=size;i++)
		tax[t[i].Max]++;
	for (int i=1;i<=size;i++)
		tax[i]+=tax[i-1];
	for (int i=1;i<=size;i++)
		id[tax[t[i].Max]--]=i;
	while (gets(s)&&strlen(s)){
		n=strlen(s);
		for (int i=0,now=1,len=0;i<n;i++){
			int c=s[i]-‘a‘;
			if (t[now].Next[c]){
				len++;
				now=t[now].Next[c];
				Max[m][now]=max(Max[m][now],len);
				continue;
			}
			while (!t[now].Next[c])
				now=t[now].fa;
			len=t[now].Max+1;
			now=t[now].Next[c];
			Max[m][now]=max(Max[m][now],len);
		}
		for (int i=size;i>=1;i--)
			Max[m][t[id[i]].fa]=max(Max[m][t[id[i]].fa],Max[m][id[i]]);
		m++;
	}
	int ans=0;
	for (int i=1;i<=size;i++){
		int now=t[i].Max;
		for (int j=0;j<m;j++)
			now=min(now,Max[j][i]);
		ans=max(ans,now);
	}
	printf("%d",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/zhouzhendong/p/8982484.html

时间: 2024-07-29 17:54:47

SPOJ LCS2 - Longest Common Substring II 字符串 SAM的相关文章

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 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 (后缀自己主动机)

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 -

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】Longest Common Substring II

[SPOJ]Longest Common Substring II 多个字符串求最长公共子串 还是将一个子串建SAM,其他字符串全部跑一边,记录每个点的最大贡献 由于是所有串,要对每个点每个字符串跑完后去最小值才是每个点的最终贡献 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm

【SPOJ】Longest Common Substring II (后缀自动机)

[SPOJ]Longest Common Substring II (后缀自动机) 题面 Vjudge 题意:求若干个串的最长公共子串 题解 对于某一个串构建\(SAM\) 每个串依次进行匹配 同时记录\(f[i]\)表示走到了\(i\)节点 能够匹配上的最长公共子串的长度 当然,每个串的\(f[i]\)可以更新\(f[i.parent]\) 所以需要拓扑排序 对于每个串求出每个节点的最长匹配 然后对他们取\(min\),表示某个节点大家都能匹配的最长长度 最后对于所有点的值都取个\(max\)

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

SPOJ 1812 Longest Common Substring II(后缀自动机)

[题目链接] http://www.spoj.com/problems/LCS2/ [题目大意] 求n个串的最长公共子串 [题解] 对一个串建立后缀自动机,剩余的串在上面跑,保存匹配每个状态的最小值, 取最小值中的最大值即可.由于跑的地方只记录了匹配结尾的状态, 所以还需要更新parent树上的状态,既然匹配到了子节点, 那么parent树链上的值就都能够取到l, 一开始给每个不同状态按照l从小到大分配储存地址, 这样,我们就可以从匹配长度最长的开始更新parent树的情况. [代码] #inc