[SPOJ1812-LCS2]Longest Common Substring II
壹、题目描述 ¶
贰、题解 ¶
曾经研究过这个问题,然而记不起来了......今天对着一个点想了很久。
为什么每次匹配一个字符串的时候要用一个 tmp[]
存下最大值而不能直接更新 mn[]
?因为匹配一个串的时候,在某些情况下我们不可避免地会走到同一个点,这个时候就应该从两次中取较大的一次。
另,每次匹配完之后需要更新父亲,因为儿子(更长的)都能被匹配到,那么父亲为什么不能被匹配呢?
不能在最后上传,留作思考。
叁、参考代码 ¶
const int maxn=200000; // twice
const int sigma=26;
const int inf=0x3f3f3f3f;
int trie[maxn+5][sigma], fa[maxn+5];
int len[maxn+5], mn[maxn+5], tmp[maxn+5];
int ncnt=1, lst=1;
inline void add(int c){
int p=lst, u=lst=++ncnt;
len[u]=len[p]+1;
for(; p && !trie[p][c]; p=fa[p])
trie[p][c]=u;
if(!p) fa[u]=1;
else{
int q=trie[p][c];
if(len[q]==len[p]+1) fa[u]=q;
else{
int nq=++ncnt;
mmcpy(trie[nq], trie[q]);
fa[nq]=fa[q], len[nq]=len[p]+1;
fa[q]=fa[u]=nq;
for(; p && trie[p][c]==q; p=fa[p])
trie[p][c]=nq;
}
}
}
char s[maxn+5];
int n;
vector<int>g[maxn+5];
inline void buildTre(){
rep(i, 2, ncnt) g[fa[i]].push_back(i);
}
/** @brief update @p mn[] */
void dfs(int u){
for(int v: g[u])
dfs(v), mn[u]=max(mn[u], mn[v]);
}
inline void buildSAM(){
rep(i, 1, n) add(s[i]-'a');
rep(i, 1, ncnt) mn[i]=inf;
buildTre();
}
inline void compare(){
int u=1, cur_len=0;
rep(i, 0, ncnt) tmp[i]=0;
rep(i, 1, n){
int to=s[i]-'a';
while(u && !trie[u][to])
u=fa[u], cur_len=min(cur_len, len[u]);
if(!u) u=1, cur_len=0;
else u=trie[u][to], ++cur_len;
tmp[u]=max(tmp[u], cur_len);
}
rep(i, 2, ncnt)
mn[i]=min(mn[i], tmp[i]);
dfs(1); // update @p mn[]
}
signed main(){
int fir=1;
while(~scanf("%s", s+1)){
n=strlen(s+1);
if(fir) buildSAM(), fir=0;
else compare();
}
// dfs(1);
int ans=0;
rep(i, 2, ncnt) if(mn[i]<inf)
ans=max(ans, mn[i]);
writc(ans);
return 0;
}