1. 程式人生 > >【BZOJ2946】公共串 [SAM]

【BZOJ2946】公共串 [SAM]

接下來 要求 構建 splay mil 至少 ast discus 最小值

公共串

Time Limit: 3 Sec Memory Limit: 128 MB
[Submit][Status][Discuss]

Description

  給出幾個由小寫字母構成的單詞,求它們最長的公共子串的長度。
  任務:
  l  讀入單詞
  l  計算最長公共子串的長度
  l  輸出結果

Input

  文件的第一行是整數 n ,表示單詞的數量。接下來n行每行一個單詞,只由小寫字母組成,單詞的長度至少為1,最大為2000。

Output

  僅一行,一個整數,最長公共子串的長度。

Sample Input

  3
  abcb
  bca
  acbc

Sample Output

  2

HINT

  2 <= n <= 5

Solution

  因為要求所有串的最長公共子串,所以我們運用SAM先對第一個串(基本串)構建一個SAM,然後用後面的串匹配即可。

  記錄 L[i] 表示當前串和基本串在 i 這個狀態匹配的最長長度。顯然,一個狀態對答案的貢獻是所有串和基本串匹配時 L[i] 的最小值

  然後取一個最大值即可。

Code

技術分享
  1 #include<iostream>    
  2 #include<string>    
  3 #include<algorithm>    
  4
#include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cmath> 8 using namespace std; 9 10 const int ONE=4005; 11 const int INF=2147483640; 12 13 int T,n; 14 char str[ONE]; 15 int ans[ONE], q[ONE], L[ONE]; 16 int len[ONE], a[ONE][27
], fa[ONE], v[ONE]; 17 int last, cnt; 18 int Ans; 19 20 int get() 21 { 22 int res=1,Q=1;char c; 23 while( (c=getchar())<48 || c>57 ) 24 if(c==-)Q=-1; 25 res=c-48; 26 while( (c=getchar())>=48 && c<=57 ) 27 res=res*10+c-48; 28 return res*Q; 29 } 30 31 struct SAM 32 { 33 SAM() {last = cnt = 1;} 34 void Add(int c) 35 { 36 int x = last, New = last = ++cnt; 37 len[New] = len[x] + 1; v[New] = 1; 38 while(x && !a[x][c]) a[x][c] = New, x = fa[x]; 39 if(!x) {fa[New] = 1; return;} 40 41 int q = a[x][c]; 42 if(len[x] + 1 == len[q]) fa[New] = q; 43 else 44 { 45 int Nq = ++cnt; len[Nq] = len[x] + 1; 46 memcpy(a[Nq], a[q], sizeof(a[q])); 47 fa[Nq] = fa[q]; 48 fa[New] = fa[q] = Nq; 49 while(a[x][c] == q) a[x][c] = Nq, x = fa[x]; 50 } 51 } 52 53 void Pre() 54 { 55 for(int i=1; i<=cnt; i++) v[len[i]]++; 56 for(int i=1; i<=cnt; i++) ans[i] = len[i]; 57 for(int i=1; i<=n; i++) v[i] += v[i-1]; 58 for(int i=cnt; i>=1; i--) q[v[len[i]]--] = i; 59 } 60 }; 61 SAM S; 62 63 void Check() 64 { 65 memset(L, 0, sizeof(L)); 66 n = strlen(str+1); 67 int x = 1, record = 0; 68 for(int i=1; i<=n; i++) 69 { 70 int c = str[i]-a+1; 71 while(x && !a[x][c]) x = fa[x]; 72 if(!x) {x = 1; record = 0; continue;} 73 record = min(record, len[x]) + 1; 74 x = a[x][c]; 75 L[x] = max(L[x], record); 76 } 77 78 for(int i=cnt; i>=1; i--) 79 L[fa[q[i]]] = max(L[fa[q[i]]], L[q[i]]); 80 for(int i=1; i<=cnt; i++) 81 ans[i] = min(ans[i], L[i]); 82 } 83 84 int main() 85 { 86 T = get(); T --; 87 scanf("%s", str+1); n = strlen(str+1); 88 for(int i=1; i<=n; i++) S.Add(str[i]-a+1); 89 S.Pre(); 90 91 while(T--) 92 { 93 scanf("%s", str+1); 94 Check(); 95 } 96 97 for(int i=1; i<=cnt; i++) 98 Ans = max(Ans, ans[i]); 99 100 printf("%d",Ans); 101 }
View Code

【BZOJ2946】公共串 [SAM]