原文链接http://www.cnblogs.com/zhouzhendong/p/8982392.html

题目传送门 - SPOJ LCS

题意

  求两个字符串的最长公共连续子串长度。

  字符串长$\leq 250000$

题解

  首先对于第一个字符串建一个$SAM$。

  然后拿第二个串在$SAM$上面走一遍就好了。

  具体地:

  将第二个串的字符一个一个地按照顺序加入。

  设当前状态为$now$,要加入字符$c$,当前匹配的字符串长度为$len$(答案自然是各种情况下$len$的最大值)。

  如果在$SAM$上面,状态$now$有标号为$c$的转移,那么,$len=len+1$,$now$更新为转移后的结果。

  否则,我们跳$now$的$fa$,直到得到一个新的$now$使得$now$有标号为$c$的转移,并使$len=Max(now)+1$,$now$更新为新的$now$再走$c$转移之后的状态。

  关于上述做法的正确性的叙述:

  对于第一种情况,相当于在原结果的末尾再加上一个匹配的字符。

  对于第二种情况,略微复杂一些。首先,跳$fa$的效果其实就是从当前子串中删除前缀,直到匹配串$SAM$的当前状态再一次和被匹配串的当前子串相匹配。注意,由于状态$now$没有标号为$c$的转移,所以被匹配串的之前成功匹配的子串中,有一段前缀现在不能匹配了。所以你找到的第一个有标号为$c$的转移的$now$的祖先的$Max$值必然小于原来的$len$,所以在本次操作之后,新的$len$的值必然不大于原来的$len$。

  UPD(2018-05-07): 这个第二种情况也可以通过分析后缀自动机性质来理解。这里不展开介绍。

  首先,很显然这个匹配是成功的。又由于我们每次跳$fa$时候,保留的串长又是尽量长的,所以满足了最大化的要求。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=500005;
int n,last=1,size=1;
char s[N];
struct SAM{
int Next[26],fa,Max;
}t[N];
void expend(int c){
int p=last,np=++size,q,nq;
t[np].Max=t[p].Max+1;
for (;!t[p].Next[c];p=t[p].fa)
t[p].Next[c]=np;
q=t[p].Next[c];
if (t[q].Max==t[p].Max+1)
t[np].fa=q;
else {
nq=++size;
t[nq]=t[q],t[nq].Max=t[p].Max+1;
t[q].fa=t[np].fa=nq;
for (;t[p].Next[c]==q;p=t[p].fa)
t[p].Next[c]=nq;
}
last=np;
}
int main(){
t[0].Max=-1;
for (int i=0;i<26;i++)
t[0].Next[i]=1;
scanf("%s",s);
n=strlen(s);
for (int i=0;i<n;i++)
expend(s[i]-'a');
int ans=0;
scanf("%s",s);
n=strlen(s);
for (int i=0,now=1,len=0;i<n;i++){
int c=s[i]-'a';
if (t[now].Next[c]){
now=t[now].Next[c];
ans=max(ans,++len);
continue;
}
while (!t[now].Next[c])
now=t[now].fa;
ans=max(ans,len=t[now].Max+1);
now=t[now].Next[c];
}
printf("%d",ans);
return 0;
}

  

SPOJ LCS - Longest Common Substring 字符串 SAM的更多相关文章

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

    LCS - Longest Common Substring no tags  A string is finite sequence of characters over a non-empty f ...

  2. LCS - Longest Common Substring(spoj1811) (sam(后缀自动机)+LCS)

    A string is finite sequence of characters over a non-empty finite set \(\sum\). In this problem, \(\ ...

  3. SPOJ LCS Longest Common Substring 和 LG3804 【模板】后缀自动机

    Longest Common Substring 给两个串A和B,求这两个串的最长公共子串. no more than 250000 分析 参照OI wiki. 给定两个字符串 S 和 T ,求出最长 ...

  4. spoj LCS2 - Longest Common Substring II && LCS - Longest Common Substring【SAM】

    多串LCS很适合SA但是我要学SAM 对第一个串求SAM,然后把剩下的串在SAM上跑,也就是维护p和len,到一个点,如果有ch[p][c],就p=ch[p][c],len++,否则向fa找最下的有c ...

  5. SPOJ LCS Longest Common Substring(后缀自动机)题解

    题意: 求两个串的最大\(LCS\). 思路: 把第一个串建后缀自动机,第二个串跑后缀自动机,如果一个节点失配了,那么往父节点跑,期间更新答案即可. 代码: #include<set> # ...

  6. 【SP1811】 LCS - Longest Common Substring(SAM)

    传送门 洛谷 Solution 考虑他要求的是最长公共子串对吧,那么我们对于一个串建后缀自动机,另一个串在后缀自动机上面跑就是了. 复杂度\(O(n+m)\)的,很棒! 代码实现 代码戳这里

  7. spoj 1811 LCS - Longest Common Substring (后缀自己主动机)

    spoj 1811 LCS - Longest Common Substring 题意: 给出两个串S, T, 求最长公共子串. 限制: |S|, |T| <= 1e5 思路: dp O(n^2 ...

  8. spoj1811 LCS - Longest Common Substring

    地址:http://www.spoj.com/problems/LCS/ 题面: LCS - Longest Common Substring no tags  A string is finite ...

  9. 【SPOJ】Longest Common Substring II

    [SPOJ]Longest Common Substring II 多个字符串求最长公共子串 还是将一个子串建SAM,其他字符串全部跑一边,记录每个点的最大贡献 由于是所有串,要对每个点每个字符串跑完 ...

随机推荐

  1. mybatis:在springboot中的配置

    ## Mybatis 配置 mybatis.type-aliases-package=com.xfind.core.entity.xianyu mybatis.mapper-locations=cla ...

  2. 在eclipse中安装svn插件

    1.下载SVN插件 下载地址:https://github.com/subclipse/subclipse 点击"Files" 2.安装 在eclipse 中点击菜单"w ...

  3. 让NotePad++添加到右键快捷方式

    添加后的效果图: 操作方式: 第一步:在桌面上新建一个txt文本文档,然后将写入如下内容 Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT ...

  4. log4net 全局配置

    public class LogHelper { private static readonly log4net.ILog ILogInfo = log4net.LogManager.GetLogge ...

  5. linux进程内存布局

      一个程序本质上都是由 BSS 段.data段.text段三个组成的.这样的概念在当前的计算机程序设计中是很重要的一个基本概念,而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分 ...

  6. Java代码自动部署

    注:本文来源于<it小熊> [ ①Java代码自动部署-总结简介] 代码部署是每一个软件开发项目组都会有的一个流程,也是从开发环节到发布功能必不可少的环节.对于Java开发者来说,Java ...

  7. Confluence 6 数据库结构图

    结构图细节 下面的 SVG 图片(可缩放矢量图)包括了 Confluence 数据库中使用的所有表.单击下面的连接在你的浏览器中打开图片连接,你也可以随后将图片下载到本地.你可以使用浏览器的缩放快捷键 ...

  8. mac 端口占用问题

    查看端口号 终端输入:sudo lsof -i tcp:port 将port换成被占用的端口(如:8086.9998) 将会出现占用端口的进程信息. 杀死占用端口的PID进程 找到进程的PID,使用k ...

  9. usrp-B210

    sudo add-apt-repository ppa:ettusresearch/uhd sudo apt-get update sudo apt-get install libuhd-dev li ...

  10. linux下命令窗口中$和#的区别

    $表示现在的用户是普通用户#表示现在的用户是root用户 # 代表你能做任何事$ 代表你能做一些/下和/home目录的所有事