【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;
}sam[MAXN << 1];
int las = 1, cnt = 1;
inline void add(int c){
    int p = las; int np = las = ++cnt;
    sam[np].len = sam[p].len + 1;
    for(; p && !sam[p].ch[c]; p = sam[p].fa) sam[p].ch[c] = np;
    if(!p) sam[np].fa = 1;
    else{
        int q = sam[p].ch[c];
        if(sam[q].len == sam[p].len + 1) sam[np].fa = q;
        else{
            int nq = ++cnt; sam[nq] = sam[q];
            sam[nq].len = sam[p].len + 1;
            sam[q].fa = sam[np].fa = nq;
            for(; p && sam[p].ch[c] == q; p = sam[p].fa) sam[p].ch[c] = nq;
        }
    }
}
char a[MAXN], b[MAXN];
int ans;
int main(){
    scanf("%s", a + 1);
    scanf("%s", b + 1);
    int lena = strlen(a + 1), lenb = strlen(b + 1);
    for(int i = 1; i <= lena; ++i)
        add(a[i] - 'a');
    int p = 1, len = 0;
    for(int i = 1; i <= lenb; ++i){
        if(sam[p].ch[b[i] - 'a'])
            ++len, p = sam[p].ch[b[i] - 'a'];
        else{
            while(!sam[p].ch[b[i] - 'a'] && p) p = sam[p].fa;
            if(!p) p = 1, len = 0;
            else len = sam[p].len + 1, p = sam[p].ch[b[i] - 'a'];
        }
        ans = max(ans, len);
    }
    printf("%d\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/Qihoo360/p/10992569.html

时间: 2025-01-17 21:34:32

【SP1811】 LCS - Longest Common Substring(后缀自动机)的相关文章

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,它

SP1811 LCS - Longest Common Substring

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

后缀自动机(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

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

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

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

SP1811 【LCS - Longest Common Substring】

\(SAM\)上匹配 我们就是需要找到两个串的最长公共子串 先对其中一个串建出\(SAM\),之后我们把另一个串放到上面跑 如果当前在\(SAM\)的状态是\(now\),下一个字符是\(c\),匹配出的的长度为\(L\) 如果\(now\)有\(c\)这个转移,我们就转移过去,\(L\)++ 如果没有我们就跳\(link\),知道跳到有这个转移为止,同时把\(L\)搞成新状态的\(len\) 这样做就好了 代码 #include<iostream> #include<cstring&g

spoj 1812 LCS2 - Longest Common Substring II (后缀自动机)

spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 <= n <= 10 |A[i]| <= 1e5 思路: 和spoj 1811 LCS差不多的做法 把其中一个A建后缀自动机 考虑一个状态s, 如果A之外的其他串对它的匹配长度分别是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1]

spoj1811 Longest Common Substring,后缀自动机

spoj1811LCS 问两个字符串最长公共子串. 做法很简单.匹配成功,则tl++,失败,从父指针回退,tl=t[now].len. 从这题可以清楚了解后缀自动机fa指针的性质: 指向一个状态,这个状态的接受串s[x..x+i]是与当前状态的接受串后缀s[j-i..j]匹配是最长的一个. 这里是不是发现了一个和KMP很像的性质? KMP在失配时通过next数组回退,那么这个回退到的位置i是s[0..i]与当前串的后缀s[j-i..j]匹配最长的一个. 所以. 利用后缀自动机可以求解一个串的子串

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

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