题意:
求两个长串的最长公共子串。
做法:
将两个串拼接起来,中间用一个没有出现过的字符连接。
于是两个字符串的最长公共子串就是这个长串两个后缀的lcp,其中这两个后缀的起点分别在两个串里。
所以跑这个长串的SA就可以了。
代码:
/*************************************************************
Problem: poj 2774 Long Long Message
User: bestFy
Language: C++
Result: Accepted
Time: 610MS
Memory: 4096K
Submit_Time: 2018-01-13 17:29:05
*************************************************************/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
using namespace std;
const int N = 200010;
int n, m, all;
char s[N], s1[N];
int SA[N], rk[N], tp[N], tong[N], h[N];
inline void ssort()
{
for(int i = 0; i <= all; i ++) tong[i] = 0;
for(int i = 1; i <= n; i ++) tong[rk[tp[i]]] ++;
for(int i = 1; i <= all; i ++) tong[i] += tong[i-1];
for(int i = n; i >= 1; i --) SA[tong[rk[tp[i]]] --] = tp[i];
}
inline void getSA()
{
for(int i = 1; i <= n; i ++) { rk[i] = s[i]; tp[i] = i; }
all = 200; ssort(); int w = 1; all = 1;
while(all < n) {
int t = 0;
for(int i = n-w+1; i <= n; i ++) tp[++ t] = i;
for(int i = 1; i <= n; i ++) if(SA[i] > w) tp[++ t] = SA[i] - w;
ssort(); for(int i = 1; i <= n; i ++) tp[i] = rk[i];
rk[SA[1]] = all = 1;
for(int i = 2; i <= n; i ++)
rk[SA[i]] = (tp[SA[i]] == tp[SA[i-1]] && tp[SA[i]+w] == tp[SA[i-1]+w])?all:++ all;
w <<= 1;
}
int k = 0;
for(int i = 1; i <= n; i ++) {
if(k) k --; int j = SA[rk[i]-1];
for(; i+k <= n && j+k <= n && s[i+k] == s[j+k]; k ++);
h[rk[i]] = k;
}
}
inline bool ok(int x, int y)
{
if(x > y) swap(x, y);
return x >= 1 && x <= m && y >= m+2 && y <= n;
}
int main()
{
scanf("%s%s", s+1, s1+1); m = n = strlen(s+1); int l = strlen(s1+1);
s[n+1] = '*';
for(int i = 1; i <= l; i ++) s[n+i+1] = s1[i];
n += l+1;
getSA(); int ans = 0;
for(int i = 2; i <= n; i ++)
if(ok(SA[i], SA[i-1])) ans = max(ans, h[i]);
printf("%d\n", ans);
return 0;
}