Longest Common Substring

\[Time Limit: 294ms \quad Memory Limit: 1572864 kB
\]

题意

给出两个串,求两个串的最长公共连续子序列的长度,两个串的长度小于等于250000。

思路

先对第一个串构建后缀自动机,根据后缀自动机的性质,从 \(root\) 的所有路径都是原串中的子串,又因为构建的时候,我们用 \(node[i].len\) 表示与节点 \(i\) 的 \(endpos\) 相同的所有子串集合的最长长度,那么我们就可以在后缀自动机上一次添加一个字符的去查询 \(res\) ,然后最大的 \(res\) 就是最后的答案。

在后缀自动机上查询的时候,我们用两个变量来更新答案,\(p\) 表示现在在后缀自动机上的状态,\(res\) 表示目前的最长公共连续长度。

  • 如果对于下一个字符 \(k\) ,现在的 \(p\) 有这样的一条边,那么直接更新 \(p\),并且 \(res\)++。
  • 如果没有这样的一条边,那么就从 \(p\) 跳到 \(node[i].fa\) 的位置,一直跳到有 \(k\) 的一条边为止停下或者走完整个后缀自动机。
  • 如果跳到结束也没有找到 \(k\) 边,那么就让 \(p\) 变回 \(root\),\(res=0\)。
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pii pair<int, int>
#define INOPEN freopen("in.txt", "r", stdin)
#define OUTOPEN freopen("out.txt", "w", stdout) typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 3e5 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std; int n, m;
int cas, tol, T; struct SAM {
struct Node{
int next[27];
int fa, len;
void init() {
mes(next, 0);
fa = len = 0;
}
} node[maxn<<1];
int sz, last;
void init() {
sz = last = 1;
node[sz].init();
}
void insert(int k) {
int p = last, np = last = ++sz;
node[np].init();
node[np].len = node[p].len+1;
for(; p && !node[p].next[k]; p=node[p].fa)
node[p].next[k] = np;
if(p==0) {
node[np].fa = 1;
} else {
int q = node[p].next[k];
if(node[q].len == node[p].len + 1) {
node[np].fa = q;
} else {
int nq = ++sz;
node[nq] = node[q];
node[nq].len = node[p].len+1;
node[np].fa = node[q].fa = nq;
for(; p&&node[p].next[k]==q; p=node[p].fa)
node[p].next[k] = nq;
}
}
}
int solve(char *s) {
int len = strlen(s+1);
int res = 0, p = 1, ans = 0;
for(int i=1; i<=len; i++) {
int k = s[i]-'a'+1;
while(p && !node[p].next[k]) {
p = node[p].fa;
res = node[p].len;
}
if(!p) {
p = 1;
res = 0;
} else {
p = node[p].next[k];
res++;
}
ans = max(ans, res);
}
return ans;
}
} sam;
char s[maxn], t[maxn]; int main() {
scanf("%s%s", s+1, t+1);
sam.init();
int len = strlen(s+1);
for(int i=1; i<=len; i++) {
sam.insert(s[i]-'a'+1);
}
int ans = sam.solve(t);
printf("%d\n", ans);
return 0;
}

Longest Common Substring SPOJ - LCS (后缀自动机)的更多相关文章

  1. 【SPOJ】Longest Common Substring II (后缀自动机)

    [SPOJ]Longest Common Substring II (后缀自动机) 题面 Vjudge 题意:求若干个串的最长公共子串 题解 对于某一个串构建\(SAM\) 每个串依次进行匹配 同时记 ...

  2. SPOJ 1812 Longest Common Substring II(后缀自动机)(LCS2)

    A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the s ...

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

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

  4. 【SPOJ】1812. Longest Common Substring II(后缀自动机)

    http://www.spoj.com/problems/LCS2/ 发现了我原来对sam的理解的一个坑233 本题容易看出就是将所有匹配长度记录在状态上然后取min后再对所有状态取max. 但是不要 ...

  5. SPOJ 1812 Longest Common Substring II(后缀自动机)

    [题目链接] http://www.spoj.com/problems/LCS2/ [题目大意] 求n个串的最长公共子串 [题解] 对一个串建立后缀自动机,剩余的串在上面跑,保存匹配每个状态的最小值, ...

  6. SPOJ - LCS2 Longest Common Substring II(后缀自动机)题解

    题意: 求\(n\)个串的最大\(LCS\). 思路: 把第一个串建后缀自动机,然后枚举所有串.对于每个串,求出这个串在\(i\)节点的最大匹配为\(temp[i]\)(当前串在这个节点最多取多少), ...

  7. 2018.12.15 spoj Longest Common Substring II(后缀自动机)

    传送门 后缀自动机基础题. 给出10个串求最长公共子串. 我们对其中一个建一个samsamsam,然后用剩下九个去更新范围即可. 代码: #include<bits/stdc++.h> # ...

  8. SPOJ 1811. Longest Common Substring (LCS,两个字符串的最长公共子串, 后缀自动机SAM)

    1811. Longest Common Substring Problem code: LCS A string is finite sequence of characters over a no ...

  9. SPOJ - LCS 后缀自动机入门

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

随机推荐

  1. Lua table的remove函数

    [1]remove函数简介 table.remove(table, pos): 返回table数组中位于pos位置的元素,其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元 ...

  2. 如何用Python制作优美且功能强大的数据可视化图像

    第一个案例 首先开始来绘制你的第一个图表 from pyecharts import Bar '''遇到不懂的问题?Python学习交流群:1004391443满足你的需求,资料都已经上传群文件,可以 ...

  3. TestNG系列(四)TestNG监听器

    前言 监听器实际上是一些预定义的java接口,用户创建这些接口的实现类(即implements某监听接口,并实现里面的方法),并加入到testng中,testng便会在运行的不同时刻调用这些类中你自定 ...

  4. JavaWeb学习路线图(2020年最新版)

    Java基础 做java开发,java基础是最需要下功夫的一项.在校招时最注重的就是基础,拿不出像样的项目没关系,但是基础万万不可不牢固. 想要基础扎实,看书沉淀是必须的,有一些编程基础的同学推荐阅读 ...

  5. java变量的声明和数据类型

    一.关键字 java程序语言的关键字只有53个.具体如下: 访问控制:private.protected.public 修饰类.方法.属性和变量:abstract.class.extends.fina ...

  6. jq 简单实现 table 显示和隐藏

    在做table显示和隐藏的时候,需要用到节点的问题.不要用id.循环的时候id都是一样的. 这样一个简单的tr显示和隐藏就实现了.也可以将click 换成别的事件.

  7. Bootstrap-treeView 实际操作总结

    由于功能性需求:需要展示一个树状结构的导航界面 1.进行资源引用 <!-- Required Stylesheets --> <link href="bootstrap.c ...

  8. 使用docker部署titpetric/netdata

    netdata 是常用的Linux系统性能实时监控面板 官方docker netdata/netdata部署 docker run -d --name=netdata \ -p 19999:19999 ...

  9. RabbitMQ的简单模式快速入门与超时异常的处理方法

    本文适合JAVA新人,想了解RabbitMQ又不想去看官网文档的人(英语水看的头疼(◎﹏◎),但建议有能力还是去看官网文档). 消息队列MQ(一) MQ全称为Message Queue,消息队列是应用 ...

  10. 7.JavaScript-Promise的并行和串行

    Promise 并行 Promise.all是所有的Promise执行完毕后(reject|resolve)返回一个Promise对象. 最近在开发一个项目中,需要等接口拿到全部数据后刷新页面,取消l ...