SPOJ 1811 Longest Common Substring(求两个串的最长公共子串)

Posted shuaihui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ 1811 Longest Common Substring(求两个串的最长公共子串)相关的知识,希望对你有一定的参考价值。

http://www.spoj.com/problems/LCS/

题目:求两个串的最长公共子串

分析:

以A建立SAM 让B在SAM上匹配
可以类比于kmp思想,我们知道在Parent树上,fa是当前节点的子集,也就是说满足最大前缀,利用这个就可以做题了

技术图片
#include <bits/stdc++.h>
#define LL long long
#define P pair<int, int>
#define lowbit(x) (x & -x)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, a, n) for (int i = a; i <= n; ++i)
const int maxn =1000005;
#define mid ((l + r) >> 1)
#define lc rt<<1
#define rc rt<<1|1
using namespace std;
string str1,str2;
struct SAM{

    int trans[maxn<<1][26], slink[maxn<<1], maxlen[maxn<<1];
    int last, now, root, len;
    inline void newnode (int v) {
        maxlen[++now] = v;
    }

    inline void extend(int c) {
        newnode(maxlen[last] + 1);
        int p = last, np = now;
        // 更新trans
        while (p && !trans[p][c]) {
            trans[p][c] = np;
            p = slink[p];
        }
        if (!p) slink[np] = root;
        else {
            int q = trans[p][c];
            if (maxlen[p] + 1 != maxlen[q]) {
                // 将q点拆出nq,使得maxlen[p] + 1 == maxlen[q]
                newnode(maxlen[p] + 1);
                int nq = now;
                memcpy(trans[nq], trans[q], sizeof(trans[q]));
                slink[nq] = slink[q];
                slink[q] = slink[np] = nq;
                while (p!=-1 && trans[p][c] == q) {
                    trans[p][c] = nq;
                    p = slink[p];
                }
            }else slink[np] = q;
        }
        last = np;
        // 初始状态为可接受状态

    }
   inline void init()
   {
       memset(trans,0,sizeof(trans));
       memset(slink,0,sizeof(slink));
       memset(maxlen,0,sizeof(maxlen));
       root = last=now=1;
   }
   inline void build(string s)
   {
       len=s.size();
       for(int i=0 ; i<len ; i++)
       extend(s[i]-a);
   }
   inline int work(string s)
   {
       int Len=s.size();
       int t1=0;
       int ret=0;
       int now=root;
       for(int i=0 ; i<Len ; i++)
       {
           int ind=s[i]-a;
           while(now!=0 && trans[now][ind]==0)
           {
               now=slink[now];
               if(now!=0) t1=maxlen[now];
           }
           if(now==0)
           {
               now=root ; t1=0;
           }
           else
           {
               now=trans[now][ind];
               t1++;
               ret=max(ret,t1);
           }
       }
       return ret;
   }

}sam;

int main()
{
    sam.init();
   cin>>str1>>str2;
   sam.build(str1);
   printf("%d
",sam.work(str2));
}
View Code

时间复杂的O(n)

 

以上是关于SPOJ 1811 Longest Common Substring(求两个串的最长公共子串)的主要内容,如果未能解决你的问题,请参考以下文章

SPOJ 1811 Longest Common Substring

●SPOJ 1811 Longest Common Substring

SPOJ 1811 Longest Common Substring(求两个串的最长公共子串)

spoj 1812 LCS2 - Longest Common Substring II (后缀自己主动机)

[SPOJ1812]Longest Common Substring II

SPOJ1812 Longest Common Substring II