Loading...

后缀数组练习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("\n");
 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("\n");
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("\n\n"); 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("?\n\n"); continue;} 
146         putt(ans,tt,n); printf("\n");
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("\n");
 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("\n");
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("\n\n"); 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("?\n\n"); continue;}
144         putt(ans,tt,n); printf("\n");
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("?\n\n"); 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("\n");
 88     }
 89     printf("\n");
 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("\n\n"); 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
posted @ 2019-08-21 11:26  TJ0929  阅读(1234)  评论(0编辑  收藏  举报