zoukankan      html  css  js  c++  java
  • 后缀数组练习4:Life Forms

    有一个细节不是特别懂,然后的话细节有点多,就是挺难发现的那一种,感谢大佬的博客

    1470: 后缀数组4:Life Forms

    poj3294

    时间限制: 1 Sec  内存限制: 128 MB
    提交: 112  解决: 35
    [提交] [状态] [讨论版] [命题人:admin]

    题目描述

    【问题描述】

    求n个字符串(长度1000)的最长的一个子串,满足该子串在一半以上(不包括一半)的字符串中出现过,并输出该子串,如果有多个子串满足要求,则按字典序输出所有的子串;(全部都是小写字母)

    【输入格式】

    输入N(1<=N<=100,还真有为1的数据哟)(每个测试点中数据组数不超过100)

    【输出格式】

    对于每个测试样例,输出答案。如果有很多,则按字典序输出。如果没有解决方案,至少有一个字母,输出“?”在测试用例之间留下一条空行。

    接下来是N个字符串

    (有多组数据,N为0时结束)

    【样例】
    输入:

    3

    abcdefg

    bcdefgh

    cdefghi

    3

    xxx

    yyy

    zzz

    0
    输出:

    bcdefg

    cdefgh

     然后的话,我就引用一下罗穗骞大佬和zjw大佬的分析
    • 我们把他合并起来了,和上一题的处理方法很相似,但是的话我们的ASCII只有127,所以我们要用一个a数组来保存,才可以跑get_sa
    • 因为合并了,所以一定要保证他们不是在同一个串里面,其次的话,这道题有一个比较神奇的概念,就是后缀分组,我们把后缀分成好几组,看看哪一组是满足条件的,记录答案,取最大值

    (引自罗穗骞)

    • 因为我们要后缀分组,所以的话要开一个bool型的v数组判断他有没有出现过,然后用一个belong数组来记录在哪一串
    • 然后的话,不知道有一个就是说get_he里面如果Rank[i]==1,就要直接continue,我也不知道为什么,不然会被卡住
    • 大概就是这些了,剩下的就

    代码的实现

    (注释版,就是解释了一下数组的意思)

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<cstdlib>
      4 #include<algorithm>
      5 #include<cmath>
      6 #include<iostream>
      7 using namespace std;
      8 int sa[110000],Rank[110000],rsort[110000];
      9 int cnt[110000],pos[110000],height[110000];
     10 int a[110000],belong[110000],v[110];/*因为我们中间有空格,所以的话要开到至少101000*/
     11 /*belong数组记录属于哪一串,v数组是用来判断两个子串是否分别属于未出现过的子串*/
     12 bool cmp(int x,int y,int k){return cnt[x]==cnt[y] && cnt[x+k]==cnt[y+k];}
     13 char s[1010];
     14 void get_sa(int n,int m) 
     15 {
     16     int k=1,p=0,len;
     17     for(int i=1;i<=n;i++) Rank[i]=a[i];
     18     memset(rsort,0,sizeof(rsort));
     19     for(int i=1;i<=n;i++) rsort[Rank[i]]++;
     20     for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
     21     for(int i=n;i>=1;i--) sa[rsort[Rank[i]]--]=i;
     22     for(int k=1;k<n;k<<=1)
     23     {
     24         len=0;
     25         for(int i=n-k+1;i<=n;i++) pos[++len]=i;
     26         for(int i=1;i<=n;i++) if(sa[i]>k) pos[++len]=sa[i]-k;
     27         for(int i=1;i<=n;i++) cnt[i]=Rank[pos[i]];
     28         memset(rsort,0,sizeof(rsort));
     29         for(int i=1;i<=n;i++) rsort[cnt[i]]++;
     30         for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
     31         for(int i=n;i>=1;i--) sa[rsort[cnt[i]]--]=pos[i];
     32         for(int i=1;i<=n;i++) cnt[i]=Rank[i];
     33         p=1; Rank[sa[1]]=1;
     34         for(int i=2;i<=n;i++)
     35         {
     36             if(!cmp(sa[i],sa[i-1],k)) p++;
     37             Rank[sa[i]]=p;
     38         }
     39         if(p==n) break; m=p;
     40     }
     41     a[0]=0; sa[0]=0;
     42 }
     43 void get_he(int n)
     44 {
     45     int j,k=0;
     46     for(int i=1;i<=n;i++)
     47     {
     48         if(Rank[i]==1) continue;/*一定要这样,但是我也不知道为什么没有这个会错*/
     49         j=sa[Rank[i]-1];
     50         if(k) k--;
     51         while(a[j+k]==a[i+k]) k++;
     52         height[Rank[i]]=k;
     53     }
     54 }
     55 bool check(int mid,int k,int n)/*二分搜索答案*/
     56 {
     57     int ans=0;
     58     memset(v,0,sizeof(v)); v[0]=1;
     59     if(!v[belong[sa[1]]]) ans++;/*没出现过*/
     60     v[belong[sa[1]]]=1;
     61     for(int i=2;i<=n;i++)
     62     {
     63         /*分开两边来判断,只要满足条件就是好的,其实就是分组后缀,看一下哪一组满足条件*/
     64         if(height[i]<mid)/*在左边*/
     65         {
     66             memset(v,0,sizeof(v)); v[0]=1;
     67             ans=0;/*初始化一下*/
     68             if(!v[belong[sa[i]]]) ans++;
     69             v[belong[sa[i]]]=1;/*判断*/
     70         }
     71         else/*在右边*/
     72         {
     73             if(!v[belong[sa[i]]]) ans++;
     74             v[belong[sa[i]]]=1;/*判断*/
     75         }
     76         if(ans>=k)return true;/*满足条件*/
     77     }
     78     return false;
     79 }
     80 void putt(int x,int k,int n)/*输出答案*/
     81 {
     82     int ans=0; 
     83     memset(v,0,sizeof(v)); v[0]=1;
     84     if(!v[belong[sa[1]]]) ans++;/*没出现过*/
     85     v[belong[sa[1]]]=1;
     86     for(int i=2;i<=n;i++)
     87     {
     88         if(height[i]<x)/*在左边*/
     89         {
     90             if(ans>=k)
     91             {
     92                 for(int j=sa[i-1];j<=sa[i-1]+x-1;j++) printf("%c",a[j]+'a');
     93                 printf("
    ");
     94             }/*已经满足条件了就可以直接输出*/
     95             memset(v,0,sizeof(v)); v[0]=1;
     96             ans=0;
     97             if(!v[belong[sa[i]]]) ans++;
     98             v[belong[sa[i]]]=1;/*判断*/
     99         }
    100         else/*在右边*/
    101         {
    102             if(!v[belong[sa[i]]]) ans++;
    103             v[belong[sa[i]]]=1;
    104         }
    105     }
    106     if(ans>=k)/*符合条件就输出*/
    107     {
    108         for(int i=sa[n];i<=sa[n]+x-1;i++) printf("%c",a[i]+'a');
    109         printf("
    ");
    110     }
    111 }
    112 int main()
    113 {
    114     int t; 
    115     while(scanf("%d",&t)!=EOF && t)
    116     {
    117         int n=0,tp=26,tt=t/2+1;
    118         for(int i=1;i<=t;i++)
    119         {
    120             scanf("%s",s+1);
    121             for(int j=1;j<=strlen(s+1);j++)
    122             {
    123                 a[++n]=s[j]-'a';
    124                 belong[n]=i;/*属于哪一串*/
    125             }
    126             a[++n]=tp; tp++;/*把二十六个字母保存到A数组里面,ascii只有127位,所以不可以直接保存*/
    127         }
    128         if(t==1)/*只有一个的话直接输出就好了*/
    129         {
    130             for(int i=1;i<n;i++) printf("%c",a[i]+'a');
    131             printf("
    
    "); continue;
    132         }
    133         get_sa(n,256); get_he(n); 
    134         int l=1,r=n,ans=0;
    135         while(l<=r)/*二分找答案*/
    136         {
    137             int mid=(l+r)/2;
    138             if(check(mid,tt,n))
    139             {
    140                 ans=mid;
    141                 l=mid+1;
    142             }
    143             else r=mid-1;
    144         }
    145         if(!ans) {printf("?
    
    "); continue;} 
    146         putt(ans,tt,n); printf("
    ");
    147         /*ans是我们最后记录的成立的那个边界范围,就是左右的边界范围*/
    148     }
    149     return 0;
    150 }
    Tristan Code 注释版

    (非注释版,挺好理解的,思路清楚了就是细节的探索咯)

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<cstdlib>
      4 #include<algorithm>
      5 #include<cmath>
      6 #include<iostream>
      7 using namespace std;
      8 int sa[110000],Rank[110000],rsort[110000];
      9 int cnt[110000],pos[110000],height[110000];
     10 int a[110000],belong[110000],v[110];
     11 bool cmp(int x,int y,int k){return cnt[x]==cnt[y] && cnt[x+k]==cnt[y+k];}
     12 char s[1010];
     13 void get_sa(int n,int m) 
     14 {
     15     int k=1,p=0,len;
     16     for(int i=1;i<=n;i++) Rank[i]=a[i];
     17     memset(rsort,0,sizeof(rsort));
     18     for(int i=1;i<=n;i++) rsort[Rank[i]]++;
     19     for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
     20     for(int i=n;i>=1;i--) sa[rsort[Rank[i]]--]=i;
     21     for(int k=1;k<n;k<<=1)
     22     {
     23         len=0;
     24         for(int i=n-k+1;i<=n;i++) pos[++len]=i;
     25         for(int i=1;i<=n;i++) if(sa[i]>k) pos[++len]=sa[i]-k;
     26         for(int i=1;i<=n;i++) cnt[i]=Rank[pos[i]];
     27         memset(rsort,0,sizeof(rsort));
     28         for(int i=1;i<=n;i++) rsort[cnt[i]]++;
     29         for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
     30         for(int i=n;i>=1;i--) sa[rsort[cnt[i]]--]=pos[i];
     31         for(int i=1;i<=n;i++) cnt[i]=Rank[i];
     32         p=1; Rank[sa[1]]=1;
     33         for(int i=2;i<=n;i++)
     34         {
     35             if(!cmp(sa[i],sa[i-1],k)) p++;
     36             Rank[sa[i]]=p;
     37         }
     38         if(p==n) break; m=p;
     39     }
     40     a[0]=0; sa[0]=0;
     41 }
     42 void get_he(int n)
     43 {
     44     int j,k=0;
     45     for(int i=1;i<=n;i++)
     46     {
     47         if(Rank[i]==1) continue;
     48         j=sa[Rank[i]-1];
     49         if(k) k--;
     50         while(a[j+k]==a[i+k]) k++;
     51         height[Rank[i]]=k;
     52     }
     53 }
     54 bool check(int mid,int k,int n)
     55 {
     56     int ans=0;
     57     memset(v,0,sizeof(v)); v[0]=1;
     58     if(!v[belong[sa[1]]]) ans++;
     59     v[belong[sa[1]]]=1;
     60     for(int i=2;i<=n;i++)
     61     {
     62         if(height[i]<mid)
     63         {
     64             memset(v,0,sizeof(v)); v[0]=1;
     65             ans=0; 
     66             if(!v[belong[sa[i]]]) ans++;
     67             v[belong[sa[i]]]=1;
     68         }
     69         else
     70         {
     71             if(!v[belong[sa[i]]]) ans++;
     72             v[belong[sa[i]]]=1;
     73         }
     74         if(ans>=k)return true;
     75     }
     76     return false;
     77 }
     78 void putt(int x,int k,int n)
     79 {
     80     int ans=0; 
     81     memset(v,0,sizeof(v)); v[0]=1;
     82     if(!v[belong[sa[1]]]) ans++;
     83     v[belong[sa[1]]]=1;
     84     for(int i=2;i<=n;i++)
     85     {
     86         if(height[i]<x)
     87         {
     88             if(ans>=k)
     89             {
     90                 for(int j=sa[i-1];j<=sa[i-1]+x-1;j++) printf("%c",a[j]+'a');
     91                 printf("
    ");
     92             }
     93             memset(v,0,sizeof(v)); v[0]=1;
     94             ans=0;
     95             if(!v[belong[sa[i]]]) ans++;
     96             v[belong[sa[i]]]=1;
     97         }
     98         else
     99         {
    100             if(!v[belong[sa[i]]]) ans++;
    101             v[belong[sa[i]]]=1;
    102         }
    103     }
    104     if(ans>=k)
    105     {
    106         for(int i=sa[n];i<=sa[n]+x-1;i++) printf("%c",a[i]+'a');
    107         printf("
    ");
    108     }
    109 }
    110 int main()
    111 {
    112     int t; 
    113     while(scanf("%d",&t)!=EOF && t)
    114     {
    115         int n=0,tp=26,tt=t/2+1;
    116         for(int i=1;i<=t;i++)
    117         {
    118             scanf("%s",s+1);
    119             for(int j=1;j<=strlen(s+1);j++)
    120             {
    121                 a[++n]=s[j]-'a';
    122                 belong[n]=i;
    123             }
    124             a[++n]=tp; tp++;
    125         }
    126         if(t==1)
    127         {
    128             for(int i=1;i<n;i++) printf("%c",a[i]+'a');
    129             printf("
    
    "); continue;
    130         }
    131         get_sa(n,256); get_he(n); 
    132         int l=1,r=n,ans=0;
    133         while(l<=r)
    134         {
    135             int mid=(l+r)/2;
    136             if(check(mid,tt,n))
    137             {
    138                 ans=mid;
    139                 l=mid+1;
    140             }
    141             else r=mid-1;
    142         }
    143         if(!ans) {printf("?
    
    "); continue;}
    144         putt(ans,tt,n); printf("
    ");
    145     }
    146     return 0;
    147 }
    Tristan Code 非注释版
      1 /*二分搜索的时候直接记录答案*/
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<iostream>
      8 using namespace std;
      9 int sa[110000],Rank[110000],rsort[110000];
     10 int cnt[110000],pos[110000],h[110000],ans[110000],anslen;
     11 int a[110000],belong[110000],v[110];
     12 bool cmp(int x,int y,int k){return cnt[x]==cnt[y] && cnt[x+k]==cnt[y+k];}
     13 char s[1010];
     14 void get_sa(int n,int m) 
     15 {
     16     int k=1,p=0,len;
     17     for(int i=1;i<=n;i++) Rank[i]=a[i];
     18     memset(rsort,0,sizeof(rsort));
     19     for(int i=1;i<=n;i++) rsort[Rank[i]]++;
     20     for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
     21     for(int i=n;i>=1;i--) sa[rsort[Rank[i]]--]=i;
     22     for(int k=1;k<n;k<<=1)
     23     {
     24         len=0;
     25         for(int i=n-k+1;i<=n;i++) pos[++len]=i;
     26         for(int i=1;i<=n;i++) if(sa[i]>k) pos[++len]=sa[i]-k;
     27         for(int i=1;i<=n;i++) cnt[i]=Rank[pos[i]];
     28         memset(rsort,0,sizeof(rsort));
     29         for(int i=1;i<=n;i++) rsort[cnt[i]]++;
     30         for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
     31         for(int i=n;i>=1;i--) sa[rsort[cnt[i]]--]=pos[i];
     32         for(int i=1;i<=n;i++) cnt[i]=Rank[i];
     33         p=1; Rank[sa[1]]=1;
     34         for(int i=2;i<=n;i++)
     35         {
     36             if(!cmp(sa[i],sa[i-1],k)) p++;
     37             Rank[sa[i]]=p;
     38         }
     39         if(p==n) break; m=p;
     40     }
     41     a[0]=0; sa[0]=0;
     42 }
     43 void get_he(int n)
     44 {
     45     int j,k=0;
     46     for(int i=1;i<=n;i++)
     47     {
     48         if(Rank[i]==1) continue;
     49         j=sa[Rank[i]-1];
     50         if(k) k--;
     51         while(a[j+k]==a[i+k]) k++;
     52         h[Rank[i]]=k;
     53     }
     54 }
     55 bool check(int mid,int k,int n)
     56 {
     57     int sum=0; bool bk=0;
     58     memset(v,0,sizeof(v)); v[0]=1;
     59     if(!v[belong[sa[1]]]) v[belong[sa[1]]]=1,sum++;
     60     for(int i=2;i<=n;i++)
     61     {
     62         if(h[i]<mid)
     63         {
     64             if(sum>=k)
     65             {
     66                 if(!bk) anslen=0;
     67                 ans[++anslen]=sa[i-1];bk=1;
     68             }
     69             memset(v,0,sizeof(v)); v[0]=1; sum=0;
     70             if(!v[belong[sa[i]]]) v[belong[sa[i]]]=1,sum++;
     71         }
     72         else if(!v[belong[sa[i]]]) v[belong[sa[i]]]=1,sum++;
     73     }
     74     if(sum>=k)
     75     {
     76         if(!bk) anslen=0;
     77         ans[++anslen]=sa[n],bk=1;
     78     }
     79     return bk;
     80 }
     81 void write(int x)
     82 {
     83     if(!x){printf("?
    
    "); return ;}
     84     for(int i=1;i<=anslen;i++)
     85     {
     86         for(int j=ans[i];j<=ans[i]+x-1;j++) printf("%c",a[j]+'a');
     87         printf("
    ");
     88     }
     89     printf("
    ");
     90 }
     91 int main()
     92 {
     93     int t; 
     94     while(scanf("%d",&t)!=EOF && t)
     95     {
     96         int n=0,tp=26,tt=t/2+1;
     97         for(int i=1;i<=t;i++)
     98         {
     99             scanf("%s",s+1);
    100             for(int j=1;j<=strlen(s+1);j++)
    101             {
    102                 a[++n]=s[j]-'a';
    103                 belong[n]=i;
    104             }
    105             a[++n]=tp; tp++;
    106         }
    107         if(t==1)
    108         {
    109             for(int i=1;i<n;i++) printf("%c",a[i]+'a');
    110             printf("
    
    "); continue;
    111         }
    112         get_sa(n,256); get_he(n); 
    113         int l=1,r=n,ans=0;
    114         while(l<=r)
    115         {
    116             int mid=(l+r)/2;
    117             if(check(mid,tt,n))
    118             {
    119                 ans=mid;
    120                 l=mid+1;
    121             }
    122             else r=mid-1;
    123         }
    124         write(ans);
    125     }
    126     return 0;
    127 }
    常数较小,较快 Code
  • 相关阅读:
    NOIP2014D2T2寻找道路(Spfa)
    【割点】【割边】tarjan
    NOIP2013D1T3货车运输(最大生成树+倍增lca)
    lca最近公共祖先(模板)
    人生第一次hash
    【模板】Tarjan求强连通分量
    【模板】链式前向星+spfa
    二叉树的三种遍历
    hdu 3549 最大流
    hdu 1532&&poj1273 基础最大流
  • 原文地址:https://www.cnblogs.com/Tristanjiang/p/11387732.html
Copyright © 2011-2022 走看看