• POJ 2774 Long Long Message (后缀数组+二分)


    题目大意:求两个字符串的最长公共子串长度

    把两个串接在一起,中间放一个#,然后求出height

    接下来还是老套路,二分出一个答案ans,然后去验证,如果有连续几个位置的h[i]>=ans,且存在sa[i]的最大值在第二个串里,最小值在第一个串里,说明答案成立

    别再把后缀数组敲错了

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #define ll long long 
     6 #define ull unsigned long long 
     7 #define inf 0x3f3f3f3f
     8 #define N 205000
     9 using namespace std;
    10 //re
    11 int n,l1,l2,len;
    12 char s1[N],s2[N],str[N];
    13 int tr[N],rk[N],sa[N],hs[N],h[N];
    14 int gint()
    15 {
    16     int rett=0,fh=1;char c=getchar();
    17     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
    18     while(c>='0'&&c<='9'){rett=(rett<<3)+(rett<<1)+c-'0';c=getchar();}
    19     return rett*fh;
    20 }
    21 bool check(int k,int x,int y){
    22     if(x+k>len||y+k>len) return 0;
    23     else return (rk[x]==rk[y]&&rk[x+k]==rk[y+k])?1:0;
    24 }
    25 void get_sa()
    26 {
    27     int cnt=0,i;
    28     for(i=1;i<=len;i++) hs[str[i]]++;
    29     for(i=1;i<=127;i++) if(hs[i]) tr[i]=++cnt;
    30     for(i=1;i<=127;i++) hs[i]+=hs[i-1];
    31     for(i=1;i<=len;i++) rk[i]=tr[str[i]],sa[hs[str[i]]--]=i;
    32     for(int k=1;cnt<len;k<<=1)
    33     {
    34         for(i=1;i<=cnt;i++) hs[i]=0;
    35         for(i=1;i<=len;i++) hs[rk[i]]++;
    36         for(i=1;i<=cnt;i++) hs[i]+=hs[i-1];
    37         for(i=len;i>=1;i--) if(sa[i]>k) tr[sa[i]-k]=hs[rk[sa[i]-k]]--;
    38         for(i=1;i<=k;i++) tr[len-i+1]=hs[rk[len-i+1]]--;
    39         for(i=1;i<=len;i++) sa[tr[i]]=i;
    40         for(i=1,cnt=0;i<=len;i++) tr[sa[i]]=check(k,sa[i],sa[i-1])?cnt:++cnt;
    41         for(i=1;i<=len;i++) rk[i]=tr[i];
    42     }
    43 }
    44 void get_height()
    45 {
    46     for(int i=1;i<=len;i++){
    47         if(rk[i]==1) continue;
    48         for(int j=max(1,h[rk[i-1]]-1);;j++)
    49             if(str[i+j-1]==str[sa[rk[i]-1]+j-1]) h[rk[i]]=j;
    50             else break;
    51     }
    52 }
    53 int check(int ans)
    54 {
    55     for(int i=1;i<=len;){
    56         if(h[i]<ans){i++;continue;}
    57         int mi=sa[i-1],ma=sa[i-1];
    58         for(;i<=len&&h[i]>=ans;i++)
    59             mi=min(mi,sa[i]),ma=max(ma,sa[i]);
    60         if(mi<=l1&&ma>l1+1) return 1;
    61     }return 0;
    62 }
    63 
    64 int main()
    65 {
    66     scanf("%s",s1+1);
    67     scanf("%s",s2+1);
    68     l1=strlen(s1+1),l2=strlen(s2+1);
    69     for(int i=1;i<=l1;i++)
    70         str[i]=s1[i];
    71     str[l1+1]='#';
    72     for(int i=1;i<=l2;i++)
    73         str[i+l1+1]=s2[i];
    74     len=l1+l2+1;
    75     get_sa();
    76     get_height();
    77     int l=0,r=min(l1,l2),ans;
    78     while(l<=r){
    79         int mid=(l+r)>>1;
    80         if(check(mid)) ans=mid,l=mid+1;
    81         else r=mid-1;
    82     }
    83     printf("%d
    ",ans);
    84     return 0;
    85 }
  • 相关阅读:
    剑指offer-替换空格
    Python replace方法并不改变原字符串
    退出循环break,在while、for、do...while、循环中使用break语句退出当前循环,直接执行后面的代码。
    do{}while()
    while循环
    for循环
    switch用法
    Javascript获取select下拉框选中的的值
    js关于a++ 与++a
    onload属性使用方法
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9700256.html
Copyright © 2020-2023  润新知