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\n",sam.work(str2)); }
时间复杂的O(n)
原文地址:https://www.cnblogs.com/shuaihui520/p/10686862.html
时间: 2024-11-05 16:04:03