模板来源:http://www.neroysq.com/?p=76
思路:http://blog.sina.com.cn/s/blog_7812e98601012dfv.html
题意就是求两个字符串的最长公共子串,串长最大250000。
以串A构建一个后缀自动机,用串B来匹配。枚举串B的每一位B[i]即考虑串B中所有以B[i]为结尾的子串,维护的值为以B[i]为末尾能匹配的最大长度tmpL。
假设走到B[i]时已经匹配好的串为str,如果当前节点有B[i]这个儿子,直接向下走,++tmpL。
如果没有,沿着fail指针向前回退,直到找到一个有B[i]儿子的节点。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std; const int MAXN = ;
const int SigmaSize = ; struct sanode
{
sanode *f, *ch[SigmaSize];
int l;
}; struct Suffix_Automaton
{
sanode pool[ ( MAXN << ) + ];
sanode *init;
sanode *tail;
int tot; void Clear()
{
tot = ;
init = pool;
tail = init;
return;
} void Insert( int c )
{
sanode *q = pool + ( ++tot ), *p = tail;
q->l = p->l + ;
for ( ; p && !p->ch[c]; p = p->f ) p->ch[c] = q;
tail = q;
if ( !p ) q->f = init;
else
{
if ( p->ch[c]->l == p->l + ) q->f = p->ch[c];
else
{
sanode *r = pool + ( ++tot ), *u = p->ch[c];
*r = *u;
r->l = p->l + ;
u->f = q->f = r;
for ( ; p && p->ch[c] == u; p = p->f ) p->ch[c] = r;
}
}
}
}; char str[MAXN + ];
Suffix_Automaton SAM; int main()
{
int len;
scanf( "%s", str + ); SAM.Clear();
len = strlen( str + );
for ( int i = ; i <= len; ++i )
SAM.Insert( str[i] - 'a' );
sanode *p = SAM.init;
scanf( "%s", str + );
len = strlen( str + );
int tmpL = , ans = ;
for ( int i = ; i <= len; ++i )
{
if ( p->ch[ str[i] - 'a' ] ) //可以向下匹配的时候就继续向下匹配
p = p->ch[ str[i] - 'a' ], ++tmpL;
else //如果当前p没有str[i]这个孩子
{
while ( p && !p->ch[ str[i] - 'a' ] )
p = p->f; //沿着fail指针向前找,直到找到有str[i]儿子的结点,或者到根节点
if( p ) //如果能找到一个有str[i]儿子的节点
{
tmpL = p->l + ;
p = p->ch[ str[i] - 'a' ];
}
else //直到回到根也没有找到
{
p = SAM.init;
tmpL = ;
}
}
ans = max( ans, tmpL );
} printf( "%d\n", ans );
return ;
}