SPOJ LCS2 1812

来源:互联网 发布:linux 开机自启动 编辑:程序博客网 时间:2024/05/22 21:33

题意:多个字符串的最长公共子串

解法:SAM

  • 将第一个串建立自动机
  • 后面的每个字符串就行匹配,维护每个位置的值,然后所有串中此位置取最小值
  • 拓扑序,对父节点进行更新
  1. /************************************************************************* 
  2.     > File Name: lcs2.cpp 
  3.     > Author: cy 
  4.     > Mail: 1002@qq.com  
  5.     > Created Time: 14/11/25 20:48:22 
  6.  ************************************************************************/ 
  7.  
  8. #include<iostream> 
  9. #include<cstring> 
  10. #include <algorithm> 
  11. #include<cstdlib> 
  12. #include<vector> 
  13. #include<cmath> 
  14. #include<stdlib.h> 
  15. #include<iomanip> 
  16. #include<list> 
  17. #include<deque> 
  18. #include<map> 
  19. #include <stdio.h> 
  20. #include <queue> 
  21.  
  22.  
  23. #define inf 0x3f3f3f3f 
  24.   #define INF 0x3FFFFFFFFFFFFFFFLL 
  25. #define rep(i,n) for(i=0;i<n;i++) 
  26.  #define reP(i,n) for(i=1;i<=n;i++) 
  27.  
  28. #define ull unsigned long long 
  29.  #define ll long long 
  30.  
  31. #define cle(a) memset(a,0,sizeof(a)) 
  32.  
  33. #define MAXN 500010+5 
  34. #define MAXC 26 
  35. using namespace std; 
  36. char ch[MAXN]; 
  37. int rk[MAXN],sz[MAXN],ans[MAXN]; 
  38.  
  39. struct Suffix_Automaton{ 
  40.     int child[MAXN][MAXC]; 
  41.  
  42.     int f[MAXN];//指向最近的接受态 
  43.     int l[MAXN];//此节点代表的最长串的长度 
  44.     int head,tail,tot;//头节点,最后的接受态,总节点 
  45.     void clear(){ 
  46.         memset(child,0,sizeof(child)); 
  47.         memset(f,0,sizeof(f)); 
  48.         memset(l,0,sizeof(l)); 
  49.         head=tail=tot=1
  50.     } 
  51.     void add(int c){ 
  52.         int p=tail,np=++tot;l[np]=l[p]+1;tail=np; 
  53.         for(;p&&!child[p][c];p=f[p]) child[p][c]=np; 
  54.         if(!p) f[np]=head; 
  55.         else if(l[child[p][c]]==l[p]+1) f[np]=child[p][c]; 
  56.         else
  57.             int q=child[p][c],r=++tot; 
  58.             memcpy(child[r],child[q],MAXC*sizeof(int)); 
  59.             f[r]=f[q];l[r]=l[p]+1;f[q]=f[np]=r; 
  60.             for(;p&&child[p][c]==q;p=f[p]) child[p][c]=r; 
  61.         } 
  62.     } 
  63.     void insert(char*ch){ 
  64.         int l=strlen(ch); 
  65.         for(int i=0;i<l;i++) add(ch[i]-'a')
  66.     } 
  67.     int ws[MAXN]; 
  68.     void tpu(){ 
  69.         int len=strlen(ch); 
  70.         for(int i=0;i<=len;i++)ws[i]=0
  71.         for(int i=1;i<=tot;i++)ws[l[i]]++; 
  72.         for(int i=1;i<=len;i++)ws[i]+=ws[i-1]; 
  73.         for(int i=tot;i>0;i--)rk[ws[l[i]]--]=i; 
  74.     } 
  75.     int ans[MAXN]; 
  76.     //为什么要沿着父节点更新? 
  77.     int now[MAXN]; 
  78.     void solve(){ 
  79.         for(int i=1;i<=tot;i++)//最长可能性 
  80.         { 
  81.             now[i]=l[i]; 
  82.         } 
  83.         while(scanf("%s",&ch)!=EOF){ 
  84.             cle(ans); 
  85.             int len=strlen(ch); 
  86.             int p=head; 
  87.             int temp=0
  88.             for(int i=0;i<len;i++) 
  89.             { 
  90.                 int tt=ch[i]-'a'; 
  91.                 if(child[p][tt])temp++,p=child[p][tt]; 
  92.                 else
  93.                     while(true){ 
  94.                         if(!p)break
  95.                         if(child[p][tt])break
  96.                         p=f[p]; 
  97.                     } 
  98.                     if(!p){ 
  99.                         temp=0
  100.                         p=head; 
  101.                     } 
  102.                     else
  103.                         temp=l[p]+1
  104.                         p=child[p][tt]; 
  105.                     } 
  106.                 } 
  107.                 ans[p]=max(temp,ans[p]); 
  108.             } 
  109.             for(int i=tot;i>0;i--) 
  110.             { 
  111.                 ans[f[rk[i]]]=max(ans[f[rk[i]]],ans[rk[i]]); 
  112.             } 
  113.             for(int i=1;i<=tot;i++) 
  114.             { 
  115.                 now[i]=min(now[i],ans[i]); 
  116.             } 
  117.         } 
  118.         int ret=0
  119.         for(int i=1;i<=tot;i++){ 
  120.             ret=max(now[i],ret); 
  121.         } 
  122.         printf("%d\\n",ret); 
  123.     } 
  124. }SAM; 
  125. int main() 
  126. #ifndef ONLINE_JUDGE 
  127.      freopen("in.txt","r",stdin); 
  128.      //freopen("out.txt","w",stdout); 
  129. #endif 
  130.     scanf("%s",&ch); 
  131.     SAM.clear(); 
  132.     SAM.insert(ch); 
  133.     SAM.tpu(); 
  134.     SAM.solve(); 
  135.     return 0
  136. }
0 0