题解思路:入门后缀自动机题目,只要把一个串建成后缀自动机,然后另一个串在上面跑就行了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 3e5 + 10;
char str[mx],Ts[mx];
struct state
{
int fa,len;//fa为包含该转态的最相近节点,len是从根节点走到该转态的最长长度
int id[26];
}Tr[2*mx];
int tot,last,ans;
//后缀自动机定义,从根节点出发到达任意一个节点形成的串都是唯一的,且一定是母串的子串
void suf_auto(int ch)
{
int np = ++tot,p = last;
//其实last就是原来的一条直串扩展到的前一个位置
//比如abccbdab这个串,自动机上肯定存在最长的一个路径就是这个串,那么last就是一直在这上面的
Tr[np].len = Tr[last].len + 1;
last = np;
//for(;p&&!Tr[p].id[ch];p=Tr[p].fa) Tr[p].id[ch] = np;
while(p&&!Tr[p].id[ch]) Tr[p].id[ch] = np, p = Tr[p].fa;
//找到包含p转态的节点,那么它也可以转移到新转态np
//可以看出是短串包含长串
if(!p) Tr[np].fa = 1;//如果都没有包含p状态的节点有可以扩展出ch这个转态,那么新状态被根节点包含
else{
int q = Tr[p].id[ch];
//如果if成立,不存在另一个点t使得Tr[t].len + 1==Tr[q].len证明也很简单
if(Tr[p].len+1==Tr[q].len) Tr[np].fa = q;//说明q状态可以包含新状态np
else{
int nq = ++tot;
Tr[nq] = Tr[q];//分裂出q转态,就是分裂出if判断那个节点
Tr[nq].len = Tr[p].len + 1;
Tr[q].fa = Tr[np].fa = nq;//分裂出的nq肯定可以包含原来的点q和np
while(p&&Tr[p].id[ch]==q) Tr[p].id[ch] = nq,p = Tr[p].fa;
//将后面包含p的点的儿子是q的也变成分裂的那个,因为他们就是跟着p走的,分裂出来的nq自然是p直接扩展状态
}
}
}
void init()//初始化根节点为1号
{
last = tot = 1;
Tr[1].len = Tr[1].fa = 0;
//memset(Tr[1].id,0,sizeof(Tr[1].id));
//这里注意多个数据id数组要初始化
}
void find(int len)
{
int ret=0,p = 1;
for(int i=0;i<len;i++){
int ch = Ts[i] - 'a';
if(Tr[p].id[ch]) ret++,p = Tr[p].id[ch];
else{
while(p&&!Tr[p].id[ch]) p = Tr[p].fa;
if(p) ret = Tr[p].len + 1, p = Tr[p].id[ch];
else p = 1,ret = 0;
}
ans = max(ret,ans);
}
}
int main()
{
init();
scanf("%s%s",str,Ts);
int len = strlen(str);
for(int i=0;i<len;i++) suf_auto(str[i]-'a');
len = strlen(Ts);
find(len);
printf("%d\n",ans);
return 0;
}