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

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", and the length is 3.

Input

The input contains several test cases. Each test case contains two strings, each string will have at most 100000 characters. All the characters are in lower-case.

Process to the end of file.

Output

For each test case, you have to tell the length of the Longest Common Substring of them.

Sample Input

banana
cianaic

Sample Output

3

Author

Ignatius.L

思路:把两个字符串连接起来,中间用一个没出现过的字符隔开。

  然后二分答案,二分check时对height进行分组,判断height值全大于x的组内 是否同时包含两个字符串的子串

  

 1 #include <cstdlib>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5
 6 const int N = 200005;
 7 int sa[N],s[N],wa[N], wb[N], ws[N], wv[N];
 8 int rank[N], height[N];
 9
10 bool cmp(int r[], int a, int b, int l)
11 {
12     return r[a] == r[b] && r[a+l] == r[b+l];
13 }
14
15 void da(int r[], int sa[], int n, int m)
16 {
17     int i, j, p, *x = wa, *y = wb;
18     for (i = 0; i < m; ++i) ws[i] = 0;
19     for (i = 0; i < n; ++i) ws[x[i]=r[i]]++;
20     for (i = 1; i < m; ++i) ws[i] += ws[i-1];
21     for (i = n-1; i >= 0; --i) sa[--ws[x[i]]] = i;
22     for (j = 1, p = 1; p < n; j *= 2, m = p)
23     {
24         for (p = 0, i = n - j; i < n; ++i) y[p++] = i;
25         for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
26         for (i = 0; i < n; ++i) wv[i] = x[y[i]];
27         for (i = 0; i < m; ++i) ws[i] = 0;
28         for (i = 0; i < n; ++i) ws[wv[i]]++;
29         for (i = 1; i < m; ++i) ws[i] += ws[i-1];
30         for (i = n-1; i >= 0; --i) sa[--ws[wv[i]]] = y[i];
31         for (std::swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i)
32             x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
33     }
34 }
35
36 void calheight(int r[], int sa[], int n)
37 {
38     int i, j, k = 0;
39     for (i = 1; i <= n; ++i) rank[sa[i]] = i;
40     for (i = 0; i < n; height[rank[i++]] = k)
41         for (k?k--:0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k++);
42 }
43 bool check(int la,int lb,int lc,int x)
44 {
45     int m1=0,m2=0;
46     if(sa[1]<la)m1=1;
47     if(sa[1]>la)m2=1;
48     for(int i=2;i<=lc;i++)
49     {
50         if(height[i]<x)
51         {
52             if(m1&&m2)
53                 return 1;
54             m1=m2=0;
55         }
56         if(sa[i]<la)m1=1;
57         if(sa[i]>la)m2=1;
58     }
59     return m1&&m2;
60 }
61 char ss[N];
62 int main()
63 {
64     while(scanf("%s",ss)==1)
65     {
66         int la=strlen(ss),lb,n=0;
67         for(int i=0;i<la;i++)
68             s[n++]=ss[i]-‘a‘+1;
69         s[n++]=28;
70         scanf("%s",ss);
71         lb=strlen(ss);
72         for(int i=0;i<lb;i++)
73             s[n++]=ss[i]-‘a‘+1;
74         s[n]=0;
75         da(s,sa,n+1,30);
76         calheight(s,sa,n);
77         int l=1,r=la,ans=0;
78         while(l<=r)
79         {
80             int mid=l+r>>1;
81             if(check(la,lb,n,mid))
82                 ans=mid,l=mid+1;
83             else
84                 r=mid-1;
85         }
86         printf("%d\n",ans);
87     }
88     return 0;
89 }
时间: 2024-10-12 04:01:12

hdu1403 Longest Common Substring的相关文章

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

传送门 求两个串的公共子串(注意,这个公共子串是连续的一段) 把两个串连在一起,中间再加上一个原字符串中不存在的字符,避免过度匹配. 求一遍height,再从height中找满足条件的最大值即可. 为什么只需要相邻两字典序的后缀呢?因为字典序相邻公共前缀一定最大. ——代码 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define N 200005 5 #define max(x,

Longest Common Substring(最长公共子序列)

Longest Common Substring Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 37 Accepted Submission(s): 28   Problem Description Given two strings, you have to tell the length of the Longest Common Su

[Algorithms] Longest Common Substring

The Longest Common Substring (LCS) problem is as follows: Given two strings s and t, find the length of the longest string r, which is a substring of both s and t. This problem is a classic application of Dynamic Programming. Let's define the sub-pro

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.简单的记忆就是“你排第几”

后缀自动机(SAM) :SPOJ LCS - Longest Common Substring

LCS - Longest Common Substring 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 consecutive sequence of characters occurrences at

lintcode 中等题:longest common substring 最长公共子串

题目 最长公共子串 给出两个字符串,找到最长公共子串,并返回其长度. 样例 给出A=“ABCD”,B=“CBCE”,返回 2 注意 子串的字符应该连续的出现在原字符串中,这与子序列有所不同. 解题 注意: 子序列:这个序列不是在原字符串中连续的位置,而是有间隔的,如:ABCDE  和AMBMCMDMEM 最长公共子序列是ADCDE 子串:子串一定在原来字符串中连续存在的.如:ABCDEF 和SSSABCDOOOO最长公共子串是ABCD 参考链接,讲解很详细 根据子串定义,暴力破解 public

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

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]匹配最长的一个. 所以. 利用后缀自动机可以求解一个串的子串