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. 建造(Builder)模式

    建造模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象. 摘自EffectiveJava:当构造方法参数过多时使用建造者模式. 产品的内部表象 ...

  2. 核与线程 CPU 4核8线程 的解释

    1.物理CPU: 物理CPU就是计算机上实际配置的CPU个数.在linux上可以打开cat /proc/cpuinfo 来查看,其中的physical id就是每个物理CPU的ID,能找到几个phys ...

  3. DRF的APIView、GenericAPIView、GenericViewSet的原理分析

    一.层次结构 GenericViewSet(ViewSetMixin, generics.GenericAPIView) ---DRF GenericAPIView(views.APIView) -- ...

  4. Excel导出,添加有效性

    #region  添加有效性 DataTable dt = LAbll.LogisticsAccounts(DeptId); //查数据 if (dt.Rows.Count < 20) //有效 ...

  5. WPF解决WindowsFormsHost背景透明

    项目案例:WPF使用WindowsFormsHost播放视频,视频上显示边框.字幕等特效: 难点问题 1.WindowsFormsHost不支持背景透明: 2.WPF Panel.ZIndex无效,W ...

  6. 前端开发常用 JS 方法

    1,获取文件本地url,在上传之前预览 /** * 获取图片嗯滴url,在上传之前预览 * @param file 选择的图片文件 * @returns {*} url */ getFileLocat ...

  7. io详解

    1.io类

  8. java 8大happen-before原则

    1.单线程happen-before原则:在同一个线程中,书写在前面的操作happen-before后面的操作. 2.锁的happen-before原则:同一个锁的unlock操作happen-bef ...

  9. pycharm动态设置字体放大缩小

    放大设置 File —> settings—> Keymap —>在搜寻框中输入:increase —> Increase Font Size(双击) —> 在弹出的对话 ...

  10. rest framework 之视图

    一.APIView APIView 直接继承 View(Django 内置的 View),也就是说 APIView 是最贴近原生 Django 的 View 的. 因此可定制程度高,根据请求方法不同执 ...