題目描述
A string is finite sequence of characters over a non-empty finite set Σ.
In this problem, Σ is the set of lowercase letters.
Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string.
Now your task is simple, for two given strings, find the length of the longest common substring of them.
Here common substring means a substring of two or more strings.
輸入格式
The input contains exactly two lines, each line consists of no more than 250000 lowercase letters, representing a string.
輸出格式
The length of the longest common substring. If such string doesn’t exist, print “0” instead.
題意翻譯
輸入2 個長度不大於250000的字符串,輸出這2 個字符串的最長公共子串。如果沒有公共子串則輸出0 。
Translated by @xyz32768
輸入輸出樣例
輸入
alsdfkjfjkdsal
fdjskalajfkdsla
輸出
3
有兩個字符串和,我們要求它們的最長公共連續子串。
首先,我們對建立一個。
定義:爲當前的前個字符組成的子串與的最長公共子序列,爲當前狀態,初始化爲0(初始狀態)。爲在狀態節點處往道路走的下一狀態。
匹配:
然後我們從開始,在的上走,一個一個匹配,若:
- 當前狀態朝着往下走有路,說明可以繼續往下匹配,就接着走,即。
- 如果沒有路了,就跳到當前狀態在後綴連接樹上的父節點,如果父節點還是沒有的路,就一直往上跳(即),直到遇到能往下走的邊。此時就令,。
- 如果跳到頭了都沒有能走的路的話,就說明要從B[i]開始重新匹配,令。
原理:如果在當前位置下失配(無路可走),那麼說明當前狀態下的所有子串都失配了,但是它的後綴連接樹上的父節點不一定失配,就繼續往上找,即相當於當前已經匹配的的子串的左邊界往右移,然後繼續找路。如果一直沒路,就一直往上找,直到達到 初始狀態 ,如果此時仍沒有路的話,說名在當前長度下已經是開始的最長公共子串了,無法在加長了。那就讓,讓後以爲新的開頭從初始狀態重新開始匹配。即整個過程就是再找的所有前綴的後綴最長能和匹配多少。
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
const int MAXN = 250005;
int n;
char
A[MAXN],
B[MAXN];
struct SAM {
int size, last;
struct Node {
int len = 0, link = 0;
int next[26];
void clear() {
len = link = 0;
memset(next, 0, sizeof(next));
}
} node[MAXN * 2];
void init() {
for (int i = 0; i < size; i++) {
node[i].clear();
}
node[0].link = -1;
size = 1;
last = 0;
}
void insert(char x) {
int ch = x - 'a';
int cur = size++;
node[cur].len = node[last].len + 1;
int p = last;
while (p != -1 && !node[p].next[ch]) {
node[p].next[ch] = cur;
p = node[p].link;
}
if (p == -1) {
node[cur].link = 0;
}
else {
int q = node[p].next[ch];
if (node[p].len + 1 == node[q].len) {
node[cur].link = q;
}
else {
int clone = size++;
node[clone] = node[q];
node[clone].len = node[p].len + 1;
while (p != -1 && node[p].next[ch] == q) {
node[p].next[ch] = clone;
p = node[p].link;
}
node[q].link = node[cur].link = clone;
}
}
last = cur;
}
}sam;
int getNextState(const int& CurState,int Loc) {
return sam.node[CurState].next[Loc - 'a'];
}
int Compute(int n) {
int
&& Ans = 0,
&& CurState = 0,
&& Len = 0;
for (int i = 0; i < n; ++i) {
//如果有路可走,就走噻
if (getNextState(CurState, B[i])) {
CurState = getNextState(CurState, B[i]);
++Len;
}
//否則
else {
//跳link
for (CurState = sam.node[CurState].link;; CurState = sam.node[CurState].link) {
//如果跳到了
if (CurState > 0 && getNextState(CurState, B[i])) {
Len = sam.node[CurState].len + 1;
CurState = getNextState(CurState, B[i]);
break;
}
//如果跳到初始狀態。
else if (CurState <= 0) {
Len = 0;
CurState = 0;
break;
}
}
}
Ans = max(Ans, Len);
}
return Ans;
}
int main() {
scanf("%s%s", &A, &B);
int Len_A = strlen(A);
sam.init();
for (int i = 0; i < Len_A; ++i) {
sam.insert(A[i]);
}
printf("%d", Compute(strlen(B)));
return 0;
}