题目链接:POJ - 2774

题目分析

题目要求求出两个字符串的最长公共子串,使用后缀数组求解会十分容易。

将两个字符串用特殊字符隔开再连接到一起,求出后缀数组。

可以看出,最长公共子串就是两个字符串分别的一个后缀的 LCP ,并且这两个后缀在 SA 中一定是相邻的。

那么他们的 LCP 就是 Height[i] ,当然,Height[i] 的最大值不一定就是 LCS ,因为可能 SA[i] 和 SA[i-1] 是在同一个字符串中。

那么判断一下,如果 SA[i] 与 SA[i - 1] 分别在两个字符串中,就用 Height[i] 更新 Ans 。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm> using namespace std; const int MaxL = 200000 + 15; int n, l1, l2, Ans;
int A[MaxL], Rank[MaxL], Height[MaxL], SA[MaxL];
int VA[MaxL], VB[MaxL], VC[MaxL], Sum[MaxL]; char S1[MaxL], S2[MaxL]; inline bool Cmp(int *a, int x, int y, int l) {
return (a[x] == a[y]) && (a[x + l] == a[y + l]);
} void DA(int *A, int n, int m) {
int *x, *y, *t;
x = VA; y = VB;
for (int i = 1; i <= m; ++i) Sum[i] = 0;
for (int i = 1; i <= n; ++i) ++Sum[x[i] = A[i]];
for (int i = 2; i <= m; ++i) Sum[i] += Sum[i - 1];
for (int i = n; i >= 1; --i) SA[Sum[x[i]]--] = i;
int p, q;
p = 0;
for (int j = 1; p < n; j <<= 1, m = p) {
q = 0;
for (int i = n - j + 1; i <= n; ++i) y[++q] = i;
for (int i = 1; i <= n; ++i) {
if (SA[i] <= j) continue;
y[++q] = SA[i] - j;
}
for (int i = 1; i <= n; ++i) VC[i] = x[y[i]];
for (int i = 1; i <= m; ++i) Sum[i] = 0;
for (int i = 1; i <= n; ++i) ++Sum[VC[i]];
for (int i = 2; i <= m; ++i) Sum[i] += Sum[i - 1];
for (int i = n; i >= 1; --i) SA[Sum[VC[i]]--] = y[i];
t = x; x = y; y = t;
x[SA[1]] = 1; p = 1;
for (int i = 2; i <= n; ++i)
x[SA[i]] = Cmp(y, SA[i], SA[i - 1], j) ? p : ++p;
}
for (int i = 1; i <= n; ++i) Rank[SA[i]] = i; //GetHeight
int h, o;
h = 0;
for (int i = 1; i <= n; ++i) {
if (Rank[i] == 1) continue;
o = SA[Rank[i] - 1];
while (A[i + h] == A[o + h]) ++h;
Height[Rank[i]] = h;
if (h > 0) --h;
}
} int main()
{
scanf("%s%s", S1 + 1, S2 + 1);
l1 = strlen(S1 + 1);
l2 = strlen(S2 + 1);
for (int i = 1; i <= l1; ++i)
A[i] = S1[i] - 'a' + 1;
A[l1 + 1] = 27;
for (int i = 1; i <= l2; ++i)
A[l1 + 1 + i] = S2[i] - 'a' + 1;
A[l1 + 1 + l2 + 1] = 28;
n = l1 + 1 + l2 + 1;
DA(A, n, 28);
Ans = 0;
for (int i = 2; i <= n - 1; ++i) {
if (Height[i] > Ans) {
if (SA[i] <= l1 && SA[i - 1] > l1 + 1) Ans = Height[i];
if (SA[i] > l1 + 1 && SA[i - 1] <= l1) Ans = Height[i];
}
}
printf("%d\n", Ans);
return 0;
}

  

[POJ 2774] Long Long Message 【后缀数组】的更多相关文章

  1. POJ 2774 Long Long Message 后缀数组

    Long Long Message   Description The little cat is majoring in physics in the capital of Byterland. A ...

  2. poj 2774 Long Long Message 后缀数组基础题

    Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 24756   Accepted: 10130 Case Time Limi ...

  3. poj 2774 Long Long Message 后缀数组LCP理解

    题目链接 题意:给两个长度不超过1e5的字符串,问两个字符串的连续公共子串最大长度为多少? 思路:两个字符串连接之后直接后缀数组+LCP,在height中找出max同时满足一左一右即可: #inclu ...

  4. POJ 2774 Long Long Message 后缀数组模板题

    题意 给定字符串A.B,求其最长公共子串 后缀数组模板题,求出height数组,判断sa[i]与sa[i-1]是否分属字符串A.B,统计答案即可. #include <cstdio> #i ...

  5. POJ 2774 Long Long Message (后缀数组+二分)

    题目大意:求两个字符串的最长公共子串长度 把两个串接在一起,中间放一个#,然后求出height 接下来还是老套路,二分出一个答案ans,然后去验证,如果有连续几个位置的h[i]>=ans,且存在 ...

  6. POJ - 2774 Long Long Message (后缀数组/后缀自动机模板题)

    后缀数组: #include<cstdio> #include<algorithm> #include<cstring> #include<vector> ...

  7. POJ 2774 Long Long Message ——后缀数组

    [题目分析] 用height数组RMQ的性质去求最长的公共子串. 要求sa[i]和sa[i-1]必须在两个串中,然后取height的MAX. 利用中间的字符来连接两个字符串的思想很巧妙,记得最后还需要 ...

  8. PKU 2774 Long Long Message (后缀数组练习模板题)

    题意:给你两个字符串.求最长公共字串的长度. by:罗穗骞模板 #include <iostream> #include <stdio.h> #include <stri ...

  9. 后缀数组(模板题) - 求最长公共子串 - poj 2774 Long Long Message

    Language: Default Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 21 ...

随机推荐

  1. JDK安装目录下的src

    学Java这么久,JDK目录下的包有哪些都不知道,今天偶然解压到src明白了许多道理 1.进入JDK安装目录,我的安装路径为:E:\JDK\jdk1.8.0,可以看到这里有个src压缩文件 2.直接解 ...

  2. 【转】Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式

    http://www.cnblogs.com/wanqieddy/archive/2013/09/06/3305482.html android线程池的理解,晚上在家无事 预习了一下android异步 ...

  3. NDK Dev

    1.cdt下载(http://www.eclipse.org/cdt/downloads.php) cdt-8.8.0.zip http://mirrors.opencas.cn/eclipse//t ...

  4. Android中悬浮窗口的实现原理和示例代码

    用了我一个周末的时间,个中愤懑就不说了,就这个问题,我翻遍全球网络没有一篇像样的资料,现在将实现原理简单叙述如下: 调用WindowManager,并设置WindowManager.LayoutPar ...

  5. 判断IMEI或MEID是否合法

    /*----------------------------------------------- * 判断此字串所代表的IMEI或MEID是否合法 * @param imei * @author H ...

  6. 4 - SQL Server 2008 之 使用SQL语句删除表格

    使用删除表格的SQL命令与删除数据的命令一样,只是删除的是表格这个对象, 语法如下:DROP TABLE 表名 一般在删除表格之前,需判断这个表格存不存在,存在则删除,不存在则不进行执行任何代码. 代 ...

  7. 第二篇:python高级之装饰器

    python高级之装饰器   python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函 ...

  8. Java-Android 之电话拨号源码

    file:///F:/workspace3/Android_ver2.4/src/cn/szy/com/MainActivity.java package cn.szy.com; import and ...

  9. WCF 生产json对外的接口

    调用wcf public ActionResult Index() { ViewBag.Message = "修改此模板以快速启动你的 ASP.NET MVC 应用程序."; WC ...

  10. br与p标签区别

    首先,相同之处是br和p都是有换行的属性及意思其次,区别<br />是只需一个单独使用,而<p>和</p>是一对使用再次,br标签是小换行提行,p标签是大换行(分段 ...