SP1811 【LCS - Longest Common Substring】

\(SAM\)上匹配

我们就是需要找到两个串的最长公共子串

先对其中一个串建出\(SAM\),之后我们把另一个串放到上面跑

如果当前在\(SAM\)的状态是\(now\),下一个字符是\(c\),匹配出的的长度为\(L\)

  • 如果\(now\)有\(c\)这个转移,我们就转移过去,\(L\)++
  • 如果没有我们就跳\(link\),知道跳到有这个转移为止,同时把\(L\)搞成新状态的\(len\)

这样做就好了

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define LL long long
#define maxn 500005
#define max(a,b) ((a)>(b)?(a):(b))
char S[maxn>>1],T[maxn>>1];
int lst=1,n,m,len[maxn],pre[maxn],son[maxn][26];
int now=1,L,ans,cnt=1;
inline void ins(int c)
{
    int f=lst,p=++cnt; lst=p;
    len[p]=len[f]+1;
    while(f&&!son[f][c]) {son[f][c]=p;f=pre[f];}
    if(!f) {pre[p]=1;return;}
    int x=son[f][c];
    if(len[f]+1==len[x]) {pre[p]=x;return;}
    int y=++cnt;
    len[y]=len[f]+1;pre[y]=pre[x];pre[x]=pre[p]=y;
    for(int i=0;i<26;i++) son[y][i]=son[x][i];
    while(f&&son[f][c]==x) {son[f][c]=y;f=pre[f];}
}
inline void q(int c)
{
    if(son[now][c]) {now=son[now][c];L++;ans=max(ans,L);return;}
    while(now&&!son[now][c]) now=pre[now];
    if(!now) {now=1,L=0;return;}
    L=len[now]+1;now=son[now][c];ans=max(ans,L);
}
int main()
{
    scanf("%s",S+1);n=strlen(S+1);
    for(int i=1;i<=n;i++) ins((int)(S[i]-‘a‘));
    scanf("%s",T+1);n=strlen(T+1);
    for(int i=1;i<=n;i++) q((int)(T[i]-‘a‘));
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/asuldb/p/10217082.html

时间: 2024-11-08 01:38:05

SP1811 【LCS - Longest Common Substring】的相关文章

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

LCS - Longest Common Substring no tags A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor, is a consecutive sequence of characters occurrences at

spoj 1811 LCS - Longest Common Substring (后缀自动机)

spoj 1811 LCS - Longest Common Substring 题意: 给出两个串S, T, 求最长公共子串. 限制: |S|, |T| <= 1e5 思路: dp O(n^2) 铁定超时 后缀数组 O(nlog(n)) 在spoj上没试过,感觉也会被卡掉 后缀自动机 O(n) 我们考虑用SAM读入字符串B; 令当前状态为s,同时最大匹配长度为len; 我们读入字符x.如果s有标号为x的边,那么s=trans(s,x),len = len+1; 否则我们找到s的第一个祖先a,它

【刷题】SPOJ 1811 LCS - Longest Common Substring

A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string. Now your task i

【SP1811】 LCS - Longest Common Substring(后缀自动机)

题目链接 对第一个串建出\(SAM\),然后用第二个串去匹配. 如果能往下走就往下走,不能的话就跳parent tree的父亲,直到能走为止.如果跳到\(0\)了还是不能走,重新匹配. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 1000010; struct SAM{ int ch[26]; int len, fa; }s

SP1811 LCS - Longest Common Substring

\(\color{#0066ff}{ 题目描述 }\) 输入2 个长度不大于250000的字符串,输出这2 个字符串的最长公共子串.如果没有公共子串则输出0 . \(\color{#0066ff}{输入格式}\) 两个字符串 \(\color{#0066ff}{输出格式}\) 一个整数,为 所求答案 \(\color{#0066ff}{输入样例}\) alsdfkjfjkdsal fdjskalajfkdsla \(\color{#0066ff}{输出样例}\) 3 \(\color{#0066

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

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

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

[SPOJ]Longest Common Substring II (后缀自动机) 题面 Vjudge 题意:求若干个串的最长公共子串 题解 对于某一个串构建\(SAM\) 每个串依次进行匹配 同时记录\(f[i]\)表示走到了\(i\)节点 能够匹配上的最长公共子串的长度 当然,每个串的\(f[i]\)可以更新\(f[i.parent]\) 所以需要拓扑排序 对于每个串求出每个节点的最长匹配 然后对他们取\(min\),表示某个节点大家都能匹配的最长长度 最后对于所有点的值都取个\(max\)

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

[SPOJ]Longest Common Substring(后缀自动机) 题面 Vjudge 题意:求两个串的最长公共子串 题解 \(SA\)的做法很简单 不再赘述 对于一个串构建\(SAM\) 另外一个串在\(SAM\)上不断匹配 最后计算答案就好了 匹配方法: 如果\(trans(s,c)\)存在 直接沿着\(trans\)走就行,同时\(cnt++\) 否则沿着\(parent\)往上跳 如果存在\(trans(now,c),cnt=now.longest+1\) 否则,如果不存在可行的

【SPOJ】Longest Common Substring

[SPOJ]Longest Common Substring 求两个字符串的最长公共子串 对一个串建好后缀自动机然后暴力跑一下 废话 讲一下怎么跑吧 从第一个字符开始遍历,遍历不到了再沿着\(parents\)走看能否找到出路,走到某个点时,统计一下走过了多少点然后更新答案 来说说这样做的正确性: 遍历是肯定的, PAM 从根节点出发的任意路径都表示一个子串 沿着\(parents\)边往后走,保证贪心情况下维护最长公共子串寻找出路 注意这里是统计走过了多少点更新答案,不能直接通过\(len\)