当然先虐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);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-11 17:10:06