【Codevs3160】最长公共子串

本文深入探讨并解决SAM裸题中的最长公共子串问题,通过构建SAM结构,有效匹配两个由小写字母组成的字符串,最终输出最长公共子串的长度。文章详细阐述了解决方案的实现步骤,包括SAM结构的构建与应用,以及关键的循环终止条件优化,为读者提供了一种高效的方法来解决此类问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当然先虐SAM裸题QwQ
3160 最长公共子串

时间限制: 2 s
空间限制: 128000 KB
题目等级 : 大师 Master

题目描述 Description

给出两个由小写字母组成的字符串,求它们的最长公共子串的长度。
输入描述 Input Description

读入两个字符串
输出描述 Output Description

输出最长公共子串的长度
样例输入 Sample Input

yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother

样例输出 Sample Output

27
数据范围及提示 Data Size & Hint

单个字符串的长度不超过100000

对第一个串建好SAM把第二个串放进SAM运行就好了.随时记录一下当前匹配子串的长度最后取max.
在build函数和solve函数里循环终止条件一开始没用l竟然跑了3000msQAQ
用l取代之后只有89ms_(:зゝ∠)_
注意给SAM的变量多开点,因为状态数和转移数并不是只有n个的…有一些多余的.一开始脑残了只开了105RE不止.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 200010
#define MAXINT 0x7fffffff
using namespace std;
int ans;
char ch[MAXN];
struct sam
{
    int last,cnt,p,q,np,nq;
    int a[MAXN][26],len[MAXN],fa[MAXN];
    sam()
    {
        last = ++cnt;
    }
    void insert(int c)
    {
        p = last;np = last = ++cnt;len[np] = len[p] + 1;
        while (!a[p][c] && p)   a[p][c] = np,p = fa[p];
        if (!p) fa[np] = 1;
        else
        {
            q = a[p][c];
            if (len[p] + 1 == len[q])   fa[np] = q;
            else
            {
                nq = ++cnt;len[nq] = len[p] + 1;
                memcpy(a[nq],a[q],sizeof(a[q]));
                fa[nq] = fa[q];
                fa[np] = fa[q] = nq;
                while (a[p][c] == q)    a[p][c] = nq,p = fa[p];
            }
        }
    }
    void build()
    {
        scanf("%s",ch+1);
        int l=strlen(ch+1);
        for (int i = 1;i <= l;i++)  insert(ch[i] - 'a');
    }
    void solve()
    {
        scanf("%s",ch+1);
        int tmp = 0,l=strlen(ch+1);
        for (int i = 1;i <= l;i++)
        {
            int c = ch[i] - 'a';
            if (a[p][c])    p = a[p][c],tmp++;
            else
            {
                while (p && !a[p][c])   p = fa[p];
                if (!p) p = 1,tmp = 0;
                else    tmp = len[p] + 1,p = a[p][c];
            }
            ans = max(ans,tmp);
        }
    }
}sam;
int main()
{
    sam.build();
    sam.solve();
    printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值