zoukankan      html  css  js  c++  java
  • POJ 2774 Long Long Message

    POJ 2774 Long Long Message

    链接

    题意

      求两个串最长公共子串。

    思路

      后缀数组:把两个串接在一起,求后缀数组和height,扫一遍即可。

      height是后缀数组排序后的排名相邻的两个串的公共前缀,那么两个串的最长公共子串一定是:两个排名相邻的串的公共前缀,(不能是不相邻的,不相邻的一定不会更优)。那么就是在height中扫一遍了。在判断一下是否来自两个串。

      

      后缀自动机:对A建立SAM,B在A上匹配。如果失配,跳到fa节点,fa节点保存的是当前点的一个后缀,在fa节点继续判断。其中每次更新ans。

    代码

    后缀数组

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<iostream>
     5 
     6 using namespace std;
     7 
     8 const int N = 200100; 
     9 char s[N];
    10 int c[N],t1[N],t2[N],sa[N],height[N],rnk[N];
    11 //sa[i]  排名为i的是谁 -下标 
    12 //rnk[i] i的排名 -名次 
    13 //height[i]  排名为i的后缀与排名为i-1的后缀的最长公共前缀长度 
    14 int m = 130,n;
    15 
    16 void get_sa() {
    17     int *x = t1,*y = t2,p,i;
    18     for (i=0; i<m; ++i) c[i] = 0; 
    19     for (i=0; i<n; ++i) x[i] = s[i],c[x[i]]++;
    20     for (i=1; i<m; ++i) c[i] += c[i-1];
    21     for (i=n-1; i>=0; --i) sa[--c[x[i]]] = i;
    22     for (int k=1; k<=n; k<<=1) {
    23         p = 0;
    24         for (i=n-k; i<n; ++i) y[p++] = i;
    25         for (i=0; i<n; ++i) if (sa[i]>=k) y[p++] = sa[i]-k;
    26         for (i=1; i<m; ++i) c[i] = 0;
    27         for (i=0; i<n; ++i) c[ x[y[i]] ]++;
    28         for (i=1; i<m; ++i) c[i] += c[i-1];
    29         for (i=n-1; i>=0; --i) sa[--c[ x[y[i]] ]] = y[i];
    30         swap(x,y);
    31         p = 1;
    32         x[sa[0]] = 0;
    33         for (i=0; i<n; ++i) 
    34             x[sa[i]] = (y[sa[i-1]]==y[sa[i]] && sa[i-1]+k<n && sa[i]+k<n &&    
    35             y[sa[i-1]+k]==y[sa[i]+k]) ? p-1 : p++;
    36         if (p >= n) break;
    37         m = p;
    38     }
    39 }
    40 void get_height() {
    41     for (int i=0; i<n; ++i) rnk[sa[i]] = i;
    42     int k = 0;
    43     height[0] = 0;
    44     for (int i=0; i<n; ++i) {
    45         if (!rnk[i]) continue;
    46         if (k) k--;
    47         int j = sa[rnk[i]-1];
    48         while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++;
    49         height[rnk[i]] = k;
    50     }
    51 }
    52 
    53 int main() {
    54     scanf("%s",s);
    55     int n1 = strlen(s);
    56     scanf("%s",s+n1);
    57     int n2 = strlen(s+n1);
    58     n = n1 + n2;
    59     get_sa();
    60     get_height();
    61     int ans = 0;
    62     for (int i=1; i<n; ++i) {
    63         int mn = min(sa[i],sa[i-1]);
    64         int mx = max(sa[i],sa[i-1]);
    65         if (mn < n1 && mx >= n1) ans = max(ans,height[i]);
    66     }
    67     printf("%d",ans);
    68     return 0;
    69 }
    View Code

    后缀自动机 upd: 2018-07-19

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cctype>
     5 
     6 using namespace std;
     7 
     8 inline int read() {
     9     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    10     for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    11 }
    12 
    13 const int N = 100010;
    14 
    15 struct Suffix_Automaton{
    16     int Index, Last, trans[N<<1][26], fa[N<<1], len[N<<1]; 
    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(char *s) {
    38         Index = 0;
    39         Last = ++Index;
    40         int n = strlen(s);
    41         for (int i=0; i<n; ++i) extend(s[i]-'a');
    42     }
    43     int query(char *s) {
    44         int n = strlen(s);
    45         int Ans = 0,P = 1,now = 0;
    46         for (int i=0; i<n; ++i) {
    47             int c = s[i] - 'a';
    48             if (trans[P][c]) P = trans[P][c], now++;
    49             else {
    50                 for (; P&&!trans[P][c]; P=fa[P]);
    51                 if (!P) now = 0, P = 1;
    52                 else now = len[P] + 1, P = trans[P][c];
    53             }
    54             Ans = max(Ans, now);
    55         }
    56         return Ans;
    57     }
    58 }SAM;
    59 
    60 char s[N];
    61 
    62 int main() {
    63     scanf("%s",s);
    64     SAM.build(s);
    65     scanf("%s",s);
    66     printf("%d",SAM.query(s));    
    67     return 0;
    68 }
    View Code
  • 相关阅读:
    焦点事件中的Validating处理方法
    推荐一个快速反射调用的类
    VB.NET自我总结语法
    WinForm应用程序实现虚拟键盘
    将图片保存到XML文件的方法
    分享TextBoxLineEx控件
    自定义CancelEventArgs类,封装事件参数信息,实现e.Cancle=true取消机制。
    从sql server 中读取二进制图片
    Oracle数据库自我总结
    Android DroidDraw UI设计工具下载地址
  • 原文地址:https://www.cnblogs.com/mjtcn/p/8988840.html
Copyright © 2011-2022 走看看