题意:

给定两个字符串 A 和 B,求最长公共子串。

分析:

字符串的任何一个子串都是这个字符串的某个后缀的前缀。

求 A 和 B 的最长公共子串等价于求 A 的后缀和 B 的后缀的最长公共前缀的最大值。如果枚举 A和 B 的所有的后缀,那么这样做显然效率低下。

由于要计算 A 的后缀和 B 的后缀的最长公共前缀,所以先将第二个字符串写在第一个字符串后面,中间用一个没有出现过的字符隔开,再求这个新的字符串的后缀数组。

观察一下,看看能不能从这个新的字符串的后缀数组中找到一些规律。以 A=“aaaba”,B=“abaa”为

那么是不是所有的 height 值中的最大值就是答案呢?不一定!有可能这两个 后 缀 是 在 同 一 个 字 符 串 中 的 , 所 以 实 际 上 只 有 当 suffix(sa[i-1]) 和suffix(sa[i])不是同一个字符串中的两个后缀时,height[i]才是满足条件的。

而这其中的最大值就是答案。

// File Name: 2774.cpp
// Author: Zlbing
// Created Time: 2013年09月07日 星期六 14时55分24秒 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,r,n) for(int i=r;i<=n;i++)
#define RREP(i,n,r) for(int i=n;i>=r;i--)
//rank从0开始
//sa从1开始,因为最后一个字符(最小的)排在第0位
//height从2开始,因为表示的是sa[i-1]和sa[i]
const int MAXN=;
int rank[MAXN],sa[MAXN],X[MAXN],Y[MAXN],height[MAXN];
char s[MAXN];
int buc[MAXN];
void calheight(int n) {
int i , j , k = ;
for(i = ; i <= n ; i++) rank[sa[i]] = i;
for(i = ; i < n ; height[rank[i++]] = k)
for(k?k--: , j = sa[rank[i]-] ; s[i+k] == s[j+k] ; k++);
}
bool cmp(int *r,int a,int b,int l) {
return (r[a] == r[b] && r[a+l] == r[b+l]);
}
void suffix(int n,int m = ) {
int i , l , p , *x = X , *y = Y;
for(i = ; i < m ; i ++) buc[i] = ;
for(i = ; i < n ; i ++) buc[ x[i] = s[i] ] ++;
for(i = ; i < m ; i ++) buc[i] += buc[i-];
for(i = n - ; i >= ; i --) sa[ --buc[ x[i] ]] = i;
for(l = ,p = ; p < n ; m = p , l *= ) {
p = ;
for(i = n-l ; i < n ; i ++) y[p++] = i;
for(i = ; i < n ; i ++) if(sa[i] >= l) y[p++] = sa[i] - l;
for(i = ; i < m ; i ++) buc[i] = ;
for(i = ; i < n ; i ++) buc[ x[y[i]] ] ++;
for(i = ; i < m ; i ++) buc[i] += buc[i-];
for(i = n - ; i >= ; i --) sa[ --buc[ x[y[i]] ] ] = y[i];
for(swap(x,y) , x[sa[]] = , i = , p = ; i < n ; i ++)
x[ sa[i] ] = cmp(y,sa[i-],sa[i],l) ? p- : p++;
}
calheight(n-);//后缀数组关键是求出height,所以求sa的时候顺便把rank和height求出来
}
//当需要反复询问两个后缀的最长公共前缀时用到RMAXNQ
int Log[MAXN];
int best[][MAXN];
void initRMQ(int n) {//初始化RMQ
for(int i = ; i <= n ; i ++) best[][i] = height[i];
for(int i = ; i <= Log[n] ; i ++) {
int limit = n - (<<i) + ;
for(int j = ; j <= limit ; j ++) {
best[i][j] = min(best[i-][j] , best[i-][j+(<<i>>)]);
}
}
}
int lcp(int a,int b) {//询问a,b后缀的最长公共前缀
a = rank[a]; b = rank[b];
if(a > b) swap(a,b);
a ++;
int t = Log[b - a + ];
return min(best[t][a] , best[t][b - (<<t) + ]);
}
int main() {
//预处理每个数字的Log值,常数优化,用于RMQ
Log[] = -;
for(int i = ; i < MAXN ; i ++) {
Log[i] = (i&(i-)) ? Log[i-] : Log[i-] + ;
}
//*******************************************
// n为数组长度,下标0开始
// 将初始数据,保存在s里,并且保证每个数字都比0大
// m = max{ s[i] } + 1
// 一般情况下大多是字符操作,所以128足够了
//*******************************************
char ch[MAXN];
while(~scanf("%s",s))
{
scanf("%s",ch);
int len1=strlen(s);
int len2=strlen(ch);
s[len1]=;
for(int i=len1+;i<len1+len2+;i++)
s[i]=ch[i-len1-];
int n=len1+len2+;
s[n]=;
suffix(n);
initRMQ(n);
int ans=;
for(int i=;i<=n;i++)
{
if((sa[i-]<len1&&sa[i]>len1)||(sa[i-]>len1&&sa[i]<len1))
{
ans=max(ans,height[i]);
}
}
printf("%d\n",ans);
} return ;
}


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 后缀数组模板题

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

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

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

  4. POJ 2217 (后缀数组+最长公共子串)

    题目链接: http://poj.org/problem?id=2217 题目大意: 求两个串的最长公共子串,注意子串是连续的,而子序列可以不连续. 解题思路: 后缀数组解法是这类问题的模板解法. 对 ...

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

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

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

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

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

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

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

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

  9. [poj 2274]后缀数组+最长公共子串

    题目链接:http://poj.org/problem?id=2774 后缀数组真的太强大了,原本dp是O(nm)的复杂度,在这里只需要O(n+m). 做法:将两个串中间夹一个未出现过的字符接起来,然 ...

随机推荐

  1. Block之变量作用域

    在使用block的过程中经常会调用不同类型.不同作用域的变量,如果对这些变量作用域的理解稍有偏差,就会出现问题.故此特意整理出block中会经常使用到的几种变量,如有补充,欢迎指出. 1. 局部变量 ...

  2. python - 操作RabbitMQ

    python - 操作RabbitMQ     介绍 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议.MQ全称为Mess ...

  3. 10.3 noip模拟试题

    希望[题目描述]网页浏览器者有后退与前进按钮,一种实现这两个功能的方式是用两个栈,“前进栈”.“后退栈”.这里你需要实现以下几个功能:BACK: 如果“后退栈”为空则忽略此命令. 否则将当前两面压入“ ...

  4. CakePHP之控制器

    控制器 控制器是MVC中的“C”. 如果你的网站使用Cake框架制作,一般根据url地址和通过路由,就会找到正确的控制器,然后控制器的动作就会被调用. 一个控制器需要解释请求数据.确保使用正确的模型. ...

  5. WPF FindName()没找到指定名称的元素

    1.FindName()说明,可以用来获取已经注册名称的元素或标签 // // 摘要: // 查找具有提供的标识符名的元素. // // 参数: // name: // 所请求元素的名称. // // ...

  6. maven发布的资源文件到tomcat项目下

    问题:项目中有hibernate的资源文件,src/main/java和src/main/resources都有这些文件,当启动项目时发现出错.但是src/main/java已经修改好了, 经查tom ...

  7. C# var

    VAR 是3.5新出的一个定义变量的类型其实也就是弱化类型的定义VAR可代替任何类型编译器会根据上下文来判断你到底是想用什么类型的 至于什么情况下用到VAR 我想就是你无法确定自己将用的是什么类型就可 ...

  8. 【模板】【网络流】Dinic

    /* 唐代杜荀鹤 <小松> 自小刺头深草里,而今渐觉出蓬蒿. 时人不识凌云木,直待凌云始道高. */ #include <iostream> #include <cstd ...

  9. Bootstrap_Javascript_按钮插件

    一 . 加载状态按钮 HTML: <button class="btnbtn-primary" data-loading-text="正在加载中,请稍等...&qu ...

  10. iOS · 安装RVM cocoaPods 及问题解决

    一.安装RVM 1.RVM:ruby版本管理器,命令行工具 管理Ruby 开始安装吧~ 对!!就是这样换成taobao ⬇️ $ gem sources -l $ gem sources --remo ...