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

题意:

求两个串的最大\(LCS\)。

思路:

把第一个串建后缀自动机,第二个串跑后缀自动机,如果一个节点失配了,那么往父节点跑,期间更新答案即可。

代码:

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<bitset>
#include<string>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
const int maxn = 500000  + 10;
typedef long long ll;
const ll mod = 998244353;
typedef unsigned long long ull;

struct SAM{
    struct Node{
        int next[27];   //下一节点
        int fa, maxlen;//后缀链接,当前节点最长子串
        void init(){
            memset(next, 0, sizeof(next));
            fa = maxlen = 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].maxlen = node[p].maxlen + 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 t = node[p].next[k];
            if(node[t].maxlen == node[p].maxlen + 1){
                node[np].fa = t;
            }
            else{
                int nt = ++sz;
                node[nt] = node[t];
                node[nt].maxlen = node[p].maxlen + 1;
                node[np].fa = node[t].fa = nt;
                for(; p && node[p].next[k] == t; p = node[p].fa)
                    node[p].next[k] = nt;
            }
        }
    }

    void solve(char *s){
        int ans = 0, ret = 0;
        int len = strlen(s);
        int pos = 1;
        for(int i = 0; i < len; i++){
            int c = s[i] - 'a';
            while(pos && node[pos].next[c] == 0){
                pos = node[pos].fa;
                ret = node[pos].maxlen;
            }
            if(pos == 0){
                pos = 1;
                ret = 0;
            }
            else{
                pos = node[pos].next[c];
                ret++;
            }
            ans = max(ans, ret);
        }
        printf("%d\n", ans);
    }
}sam;
char s[maxn];
int main(){
    sam.init();
    scanf("%s", s);
    int len = strlen(s);
    for(int i = 0; i < len; i++) sam.insert(s[i] - 'a');
    scanf("%s", s);
    sam.solve(s);
    return 0;
}

原文地址:https://www.cnblogs.com/KirinSB/p/11667221.html

时间: 2024-11-07 08:48:29

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

后缀自动机(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】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 1811LCS Longest Common Substring

后缀自动机裸题.... Longest Common Substring Time Limit: 2000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu [Submit]   [Go Back]   [Status] Description A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is

【SPOJ】Longest Common Substring

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

【SPOJ】Longest Common Substring II

[SPOJ]Longest Common Substring II 多个字符串求最长公共子串 还是将一个子串建SAM,其他字符串全部跑一边,记录每个点的最大贡献 由于是所有串,要对每个点每个字符串跑完后去最小值才是每个点的最终贡献 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm

【刷题】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 LCS2 - Longest Common Substring II

题目描述 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 t