spoj 1812

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 consecutive sequence of characters occurrences at least once in a string.

Now your task is a bit harder, for some 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 at most 10 lines, each line consists of no more than 100000 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

aaaajfaaaa

Output:

2

大意:

求出多个串的最长公共字串,输出长度.

分析:

我们这么想:

我们先拿两个串A,B匹配,然后在两个串的匹配过程中计算出后缀自动机SAM_A中某个节点x能在B中匹配的最长的长度.

那么这个问题就解决了.(我可以继续匹配C,D)最后取个min.

裸地解决这个问题是O(L2)的.

所以我们应用上spoj1811中的性质: parent _x 和 x 节点的最长公共部分是 max_parent_x.

那么我们只要利用孩子的匹配长度就能够直接推出parent的匹配长度. min(Min[par[x]], Max[x])

(Min[x] 表示从x节点开始在当前已经考虑的串中,从x节点出发能够拓展的最长的长度. Max[x] 表示在当前串内, 从x节点出发, 能够匹配的最长的长度.)

值得注意的是,当 Min[par[x]] != 0 && Max[x] != 0 时, Min[par[x]] + 1 <= Max[x].

所以,我们现在的关键在于面对 Max[x] == 0 的情况.

这种情况下,表明从x这个点无法进行拓展,所以自然表示par[x] 也无法进行拓展,因为par是x的极大后缀串.

所以我们迭代更新Min的值,最后取Min就ok了.

代码中加入了一个特判来验证我的猜想:

偷懒没有用"鸡排"....见谅.

 1 #include<cstdlib>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cassert>
 6 using namespace std;
 7 const int maxn = (int)1.01e6,sigma = 26;
 8 char str[maxn];
 9 int Min[maxn * 2],Max[maxn * 2],id[maxn * 2];
10 int cmq(int,int);
11 struct Sam{
12     int ch[maxn * 2][sigma],par[maxn * 2],stp[maxn * 2];
13     int sz,last;
14     void init(){
15         sz = last = 1;
16     }
17     void ext(int c){
18         stp[++sz] = stp[last] + 1;
19         int p = last, np = sz;
20         for(; !ch[p][c]; p = par[p]) ch[p][c] = np;
21         if(p == 0) par[np] = 1;
22         else{
23             int q = ch[p][c];
24             if(stp[q] != stp[p] + 1){
25                 stp[++sz] = stp[p] + 1;
26                 int nq = sz;
27                 memcpy(ch[nq],ch[q],sizeof(ch[q]));
28                 par[nq] = par[q];
29                 par[q] = par[np] = nq;
30                 for(; ch[p][c] == q; p = par[p]) ch[p][c] = nq;
31             }
32             else par[np] = q;
33         }
34         last = np;
35     }
36     void ins(char *pt){
37         int i;
38         init();
39         for(i = 0; pt[i]; ++i) ext(pt[i] - ‘a‘);
40     }
41     void prep(){
42         int i;
43         for(i = 1; i <= sz; ++i) Min[i] = stp[i];
44         for(i = 1; i <= sz; ++i) id[i] = i;
45         sort(id + 1, id + sz + 1,cmq);
46     }
47     void cmp(char *pt){
48         int i,x = 1,cnt = 0;
49         fill(Max, Max + sz + 2, 0);
50         for(i = 0; pt[i]; ++i){
51             if(ch[x][pt[i] - ‘a‘]){
52                 x = ch[x][pt[i] - ‘a‘];
53                 Max[x] = max(Max[x],++cnt);
54             }
55             else{
56                 while(x != 1 && !ch[x][pt[i] - ‘a‘]) x = par[x], cnt = stp[x];
57                 if(ch[x][pt[i] - ‘a‘]) x = ch[x][pt[i] - ‘a‘],Max[x] = max(Max[x],++cnt);
58             }
59         }
60         for(i = 1; i <= sz; ++i){
61             if(id[i] != 1 && Min[par[id[i]]] && Max[id[i]])
62                 assert(Min[par[id[i]]] + 1 <= Max[id[i]]);
63             Min[id[i]] = min(Min[id[i]], Max[id[i]]);
64             Max[par[id[i]]] = max(Max[par[id[i]]], Max[id[i]]);
65         }
66     }
67 }sam;
68 int cmq(int x,int y){
69     return sam.stp[x] > sam.stp[y];
70 }
71 int main()
72 {
73     freopen("substr.in","r",stdin);
74     freopen("substr.out","w",stdout);
75     scanf("%s",str);
76     sam.ins(str);
77     sam.prep();
78     while(scanf("%s",str) != EOF)
79         sam.cmp(str);
80     printf("%d\n",*max_element(Min + 1, Min + sam.sz + 1));
81     return 0;
82 }

时间: 2024-10-10 07:20:52

spoj 1812的相关文章

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 -

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

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

SPOJ 1812 Longest Common Substring II

http://www.spoj.com/problems/LCS2/ 题意: 求10个串的LCS 1.用第一个串建立后缀自动机 2.len[s] 表示状态s 所能代表的字符串的最大长度 mx[s] 表示状态s 在 当前匹配的串的最长匹配后缀长度 ans[s] 表示状态s 在所有串的最长匹配后缀长度 3.用第2——第10个串在后缀自动机上跑,每次mx[s]=max(mx[s],当前匹配长度) 每一个串跑完之后,更新 ans[s]=min(ans[s],mx[s]) 4.每次匹配完一个字符串的时候,

SPOJ 1812 LCS2 [后缀自动机]

题意: 求多个串<=10的最长连续子串 一个串建SAM,然后其他串在上面走 每个状态记录所有串在这个状态的公共子串的最小值 一个串在上面走的时候记录与每个状态公共子串的最大值,注意出现次数向父亲传递,一个状态能到达说明了Suffix Link指向的状态可以取到最大子串,这一步对val后基数排序然后倒着更新就行了 注意两点: 1.空间要开两倍,基数排序用的东西也要两倍哦 2.答案不能用mn[1]更新!!!!因为mn[1]没有意义啊root状态一个子串也没有还可能有某些bug #include <

spoj 1812 LCS2(SAM+DP)

Longest Common Substring II Time Limit: 236MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Description A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring,

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-LCSII

题意: 给出最多10个长度不超过100000的字符串,求他们的LCS的长度.时限是鬼畜的0.25s . 后缀自动机练习...虽然有人这么说但我并不觉得hash能过. 本题可以说是[论SAM中按step排序更新pre的重要性]: 总的来说做法和1811-LCS有点类似,不同的是因为有多个字符串,因此每个字符串都需要在SAM上跑一次. 记录下每个节点最长能容纳长度为多少的字符,最后取个MAX就行了. 用nans[i]表示匹配当前字符串时,i号点能容纳的子串长度,如果i的pre上的当前答案比i还要小的

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

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