spoj 1811

1811. Longest Common Substring

Problem code: LCS

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 task is simple, for two given strings, find the length of the longest common substring of them.

Here common substring means a substring of two or more strings.

Input

The input contains exactly two lines, each line consists of no more than 250000 lowercase letters, representing a string.

Output

The length of the longest common substring. If such string doesn‘t exist, print "0" instead.

Example

Input:

alsdfkjfjkdsal

fdjskalajfkdsla

Output:

3

题目大意:
求两个字符串的最长公共字串.输出长度.

分析:
们引入这个记号:

max:即代码中 step 变量,它表示该状态能够接受的最长的字符串长度。
min:表示该状态能够接受的最短的字符串长度。实际上等于该状态的 par 指针指向的结点的 step + 1。
max-min+1:表示该状态能够接受的不同的字符串数。

如果你很好奇这个性质为什么成立,不妨参看范浩强的博文:后缀自动机与线性构造后缀树 
从后缀树的角度来思考这个问题就非常简单了.

我们先进行贪心的匹配,如果在某个点上发生失配,说明 min_x ~ max_x 之间的字符串都是不匹配的.

那么我们该如何回退呢?

这个点和parent之间的关系是: 它的parent能够接受的最长串是这个点所能接受的串的最长公共前缀.

你又非常好奇, 那么这么说吧.后缀树上parent是这个点的父节点.那么你要走到这个点,就必须经过parent.

所以我们只要沿着par边向上跳就ok了.

接下来跟KMP比较类似就不详细说了.

代码也不长:

 1 #include<cstdlib>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn = (int)3e5, sigma = 26;
 7 char s1[maxn],s2[maxn];
 8 struct Sam{
 9     int ch[maxn][sigma],par[maxn];
10     int stp[maxn];
11     int sz,last;
12     void init(){
13         memset(ch,0,sizeof(ch)); memset(par,0,sizeof(par));    memset(stp,0,sizeof(stp));
14         sz = last = 1;
15     }
16     void ext(int c){
17         stp[++sz] = stp[last] + 1;
18         int p = last, np = sz;
19         while(!ch[p][c]) ch[p][c] = np, p = par[p];
20         if(p == 0) par[np] = 1;
21         else{
22             int q = ch[p][c];
23             if(stp[q] != stp[p] + 1){
24                 stp[++sz] = stp[p] + 1;
25                 int nq = sz;
26                 memcpy(ch[nq],ch[q],sizeof(ch[q]));
27                 par[nq] = par[q];
28                 par[q] = par[np] = nq;
29                 while(ch[p][c] == q) ch[p][c] = nq, p = par[p];
30             }
31             else par[np] = q;
32         }
33         last = np;
34     }
35     void build(char *pt){
36         int i;
37         init();
38         for(i = 0; pt[i]; ++i) ext(pt[i] - ‘a‘);
39     }
40     int vis(char *pt){
41         int x = 1,i,ret = 0,ans = 0;
42         for(i = 0; pt[i]; ++i){
43             if(ch[x][pt[i] - ‘a‘])
44                 x = ch[x][pt[i] - ‘a‘], ans = max(ans,++ret);
45             else x = par[x],ret = stp[x],i -= (x != 0);
46             if(x == 0) x = 1;
47         }
48         return ans;
49     }
50 }sam;
51 int main()
52 {
53     freopen("substr.in","r",stdin);
54     freopen("substr.out","w",stdout);
55     scanf("%s\n",s1);
56     scanf("%s\n",s2);
57     sam.build(s1);
58     printf("%d\n",sam.vis(s2));
59     return 0;
60 } 



 

时间: 2024-10-23 08:37:49

spoj 1811的相关文章

spoj 1811 LCS - Longest Common Substring (后缀自动机)

spoj 1811 LCS - Longest Common Substring 题意: 给出两个串S, T, 求最长公共子串. 限制: |S|, |T| <= 1e5 思路: dp O(n^2) 铁定超时 后缀数组 O(nlog(n)) 在spoj上没试过,感觉也会被卡掉 后缀自动机 O(n) 我们考虑用SAM读入字符串B; 令当前状态为s,同时最大匹配长度为len; 我们读入字符x.如果s有标号为x的边,那么s=trans(s,x),len = len+1; 否则我们找到s的第一个祖先a,它

【刷题】SPOJ 1811 LCS - Longest Common Substring

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 task i

SPOJ 1811 Longest Common Substring(求两个串的最长公共子串)

http://www.spoj.com/problems/LCS/ 题目:求两个串的最长公共子串 分析: 以A建立SAM 让B在SAM上匹配可以类比于kmp思想,我们知道在Parent树上,fa是当前节点的子集,也就是说满足最大前缀,利用这个就可以做题了 #include <bits/stdc++.h> #define LL long long #define P pair<int, int> #define lowbit(x) (x & -x) #define mem(a

SPOJ 1811 SAM 初探

思路: 一个串建SAM 另一个串在SAM上跑 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=500050; int n;char a[N],b[N]; struct SAM{ int ch[N][26],dis[N],fa[N],root,tot,last; void init(){root=tot=las

SPOJ 1811 Longest Common Substring

Description 给出两个字符串,求最长公共子串. Sol SAM. 这题随便做啊...后缀数组/Hash+二分都可以. SAM就是模板啊...直接在SAM上跑就行,没有了 \(go[w]\) 就往 \(par\) 跳. 每走一步统计一下答案. Code #include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N = 250005; struct St

●SPOJ 1811 Longest Common Substring

题链: http://poj.org/problem?id=2774 题解: 求两个字符串(S,T)的最长公共子串.对 S串建后缀自动机.接下来就用这个自动机去求出能和 S串匹配的 T的每一个前缀的最长的后缀.最终答案就是对每个 T的前缀得到的答案取最大值就好了. 代码: #include<cstdio> #include<cstring> #include<iostream> #define MAXN 250050 #define filein(x) freopen(

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 -

后缀自动机(SAM)学习指南

*在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符串所有后缀的自动机. 它最早在陈立杰的 2012 年 noi 冬令营讲稿中提到. 在2013年的一场多校联合训练中,陈立杰出的 hdu 4622 可以用 SAM 轻松水过,由此 SAM 流行了起来. 一般来说,能用后缀自动机解决的问题都可以用后缀数组解决.但是后缀自动机也拥有自己的优点. 1812.