标签:min tomato memset span 数组 def ast 最长公共子串 公共子串
题意:
求N(N<=10)个串的最长公共子串。
分析:
poj2774上那道题,对一个串建立后缀自动机,另一个在上面匹配。
这道题是对多个串求。那么同样,让每个串在后缀自动机上匹配,然后记录在后缀自动机的每个节点上记录,当前串在这个位置的最大匹配数,h数组。
然后mn数组,每次对于这所有的节点的h取小,为从第2个串到现在所有的串,都能在这个节点上匹配的长度。
因为一旦某个节点匹配上了,那么它的父节点(parent树)的父节点都会匹配上(因为父节点是当前点的后缀),所以按拓扑倒序,更新父节点的h,为父节点的len,(即最大长度)。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 inline int read() { 6 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1; 7 for (;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘;return x*f; 8 } 9 10 const int N = 100010; 11 12 struct Suffix_Automaton{ 13 int fa[N<<1], trans[N<<1][26], len[N<<1], Last, Index; 14 int v[N], sa[N<<1], mn[N<<1], h[N<<1]; 15 char s[N]; 16 17 void extend(int c) { 18 int P = Last,NP = ++Index; 19 len[NP] = len[P] + 1; 20 for (; P&&!trans[P][c]; P=fa[P]) trans[P][c] = NP; 21 if (!P) fa[NP] = 1; //- 22 else { 23 int Q = trans[P][c]; 24 if (len[P] + 1 == len[Q]) fa[NP] = Q; 25 else { 26 int NQ = ++Index; 27 fa[NQ] = fa[Q]; 28 len[NQ] = len[P] + 1; 29 memcpy(trans[NQ], trans[Q], sizeof trans[Q]); 30 fa[Q] = NQ; 31 fa[NP] = NQ; 32 for (; P&&trans[P][c]==Q; P=fa[P]) trans[P][c] = NQ; 33 } 34 } 35 Last = NP; 36 } 37 void build() { 38 Last = Index = 1; 39 scanf("%s",s+1); 40 int n = strlen(s+1); 41 for (int i=1; i<=n; ++i) extend(s[i] - ‘a‘); 42 for (int i=1; i<=Index; ++i) v[len[i]] ++; 43 for (int i=1; i<=n; ++i) v[i] += v[i-1]; 44 for (int i=1; i<=Index; ++i) sa[ v[len[i]]-- ] = i; // sa[i] 排名为i的节点。按深度排名(拓扑用) 45 } 46 void calcc() { 47 int n = strlen(s+1), now = 0, p = 1; 48 memset(h, 0, sizeof(h)); 49 for (int i=1; i<=n; ++i) { 50 int c = s[i] - ‘a‘; 51 if (trans[p][c]) p = trans[p][c], now ++; 52 else { 53 for (; p&&!trans[p][c]; p=fa[p]); 54 if (!p) now = 0, p = 1; 55 else now = len[p] + 1, p = trans[p][c]; 56 } 57 h[p] = max(h[p], now); 58 } 59 for (int i=Index; i>=1; --i) { // 拓扑倒序,parent树中从深度深的到浅的 60 int t = sa[i]; 61 mn[t] = min(mn[t], h[t]); 62 if (h[t] && fa[t]) h[fa[t]] = len[fa[t]]; 63 } 64 } 65 void solve() { 66 build(); 67 memset(mn, 0x3f, sizeof(mn)); 68 while (scanf("%s",s+1) != EOF) calcc(); 69 int ans = 0; 70 for (int i=1; i<=Index; ++i) ans = max(ans, mn[i]); 71 printf("%d",ans); 72 } 73 }sam; 74 75 int main() { 76 sam.solve(); 77 return 0; 78 }
标签:min tomato memset span 数组 def ast 最长公共子串 公共子串
原文地址:https://www.cnblogs.com/mjtcn/p/9335863.html