[HDU1403]Longest Common Substring(后缀数组)

传送门

求两个串的公共子串(注意,这个公共子串是连续的一段)

把两个串连在一起,中间再加上一个原字符串中不存在的字符,避免过度匹配。

求一遍height,再从height中找满足条件的最大值即可。

为什么只需要相邻两字典序的后缀呢?因为字典序相邻公共前缀一定最大。

——代码

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #define N 200005
 5 #define max(x, y) ((x) > (y) ? (x) : (y))
 6
 7 int len, n, ans, m = ‘z‘ + 1;
 8 int buc[N], x[N], y[N], sa[N], rank[N], height[N];
 9 char s[N];
10
11 inline void build_sa()
12 {
13     int i, k, p;
14     for(i = 0; i < m; i++) buc[i] = 0;
15     for(i = 0; i < len; i++) buc[x[i] = s[i]]++;
16     for(i = 1; i < m; i++) buc[i] += buc[i - 1];
17     for(i = len - 1; i >= 0; i--) sa[--buc[x[i]]] = i;
18     for(k = 1; k <= len; k <<= 1)
19     {
20         p = 0;
21         for(i = len - 1; i >= len - k; i--) y[p++] = i;
22         for(i = 0; i < len; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
23         for(i = 0; i < m; i++) buc[i] = 0;
24         for(i = 0; i < len; i++) buc[x[y[i]]]++;
25         for(i = 1; i < m; i++) buc[i] += buc[i - 1];
26         for(i = len - 1; i >= 0; i--) sa[--buc[x[y[i]]]] = y[i];
27         std::swap(x, y);
28         p = 1, x[sa[0]] = 0;
29         for(i = 1; i < len; i++)
30             x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
31         if(p >= len) break;
32         m = p;
33     }
34 }
35
36 inline void build_height()
37 {
38     int i, j, k = 0;
39     for(i = 0; i < len; i++) rank[sa[i]] = i;
40     for(i = 0; i < len; i++)
41     {
42         if(!rank[i]) continue;
43         if(k) k--;
44         j = sa[rank[i] - 1];
45         while(s[i + k] == s[j + k] && i + k < len && j + k < len) k++;
46         height[rank[i]] = k;
47     }
48 }
49
50 int main()
51 {
52     int i;
53     while(~scanf("%s", s))
54     {
55         n = strlen(s);
56         s[n] = ‘#‘;
57         scanf("%s", s + n + 1);
58         len = strlen(s);
59         build_sa();
60         build_height();
61         ans = 0;
62         for(i = 1; i < len; i++)
63             if((sa[i - 1] < n && sa[i] > n) || (sa[i - 1] > n && sa[i] < n))
64                 ans = max(ans, height[i]);
65         printf("%d\n", ans);
66     }
67     return 0;
68 }

时间: 2024-10-12 06:22:20

[HDU1403]Longest Common Substring(后缀数组)的相关文章

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,它

hdu1403 Longest Common Substring

地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=1403 题目: Longest Common Substring Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6296    Accepted Submission(s): 2249 Problem Description Give

hdu_1403_Longest Common Substring(后缀数组的应用)

题目链接:hdu_1403_Longest Common Substring 题意: 给你两个字符串,然你找最长的公共子串 题解: 后缀数组的经典应用,要找两个字符串的公共子串,那么就相当于找两个串的后缀的最长公共前缀,我们将两个字符串拼接在一起,中间插一个特殊字符 然后我们考虑height数组,height数组存的是排i和i-1的最长前缀,如果sa[i]和sa[i-1]在特殊字符的两边,那么这个height[i]记录的就是这两个串的最长 子串,然后扫一遍height数组更新一下答案就行了 1

HDU 1403 Longest Common Substring(后缀数组,最长公共子串)

hdu题目 poj题目 参考了 罗穗骞的论文<后缀数组——处理字符串的有力工具> 题意:求两个序列的最长公共子串 思路:后缀数组经典题目之一(模版题) //后缀数组sa:将s的n个后缀从小到大排序后将 排序后的后缀的开头位置 顺次放入sa中,则sa[i]储存的是排第i大的后缀的开头位置.简单的记忆就是“排第几的是谁”. //名次数组rank:rank[i]保存的是suffix(i){后缀}在所有后缀中从小到大排列的名次.则 若 sa[i]=j,则 rank[j]=i.简单的记忆就是“你排第几”

HDU 1403 Longest Common Substring(后缀数组啊 求最长公共子串 模板题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 Problem Description Given two strings, you have to tell the length of the Longest Common Substring of them. For example: str1 = banana str2 = cianaic So the Longest Common Substring is "ana", a

spoj1811 Longest Common Substring,后缀自动机

spoj1811LCS 问两个字符串最长公共子串. 做法很简单.匹配成功,则tl++,失败,从父指针回退,tl=t[now].len. 从这题可以清楚了解后缀自动机fa指针的性质: 指向一个状态,这个状态的接受串s[x..x+i]是与当前状态的接受串后缀s[j-i..j]匹配是最长的一个. 这里是不是发现了一个和KMP很像的性质? KMP在失配时通过next数组回退,那么这个回退到的位置i是s[0..i]与当前串的后缀s[j-i..j]匹配最长的一个. 所以. 利用后缀自动机可以求解一个串的子串

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】Longest Common Substring II (后缀自动机)

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