<span>POJ - 1226 Substrings (后缀数组)</span>

传送门:POJ - 1226

这个题跟POJ - 3294  和POJ - 3450 都是一样的思路,一种题型。

POJ - 3294的题解可以见:https://www.cnblogs.com/lilibuxiangtle/p/12649853.html

题意:给你n个字符串,求最长子串的长度,要求子串或子串的翻转串在n个字符串中都出现。

题解:把每个字符串和字符串的翻转串连接起来,中间用不同且没出现过的字符隔开,然后再把n个字符串和翻转的串连到一起。然后后缀数组求出sa数组和height数组,用be数组标记每个位置的字符在哪个串中。二分长度,vis数组标记符合条件的串,cnt记录个数,如果cnt>=n则说明该长度可以,反之则不行。(重点!!vis及时标记 我憨憨的wa了好几发,找了快三个小时

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<queue>
  4 #include<iostream>
  5 #include<cmath>
  6 #include<cstring>
  7 using namespace std;
  8 
  9 //sa:字典序中排第i位的起始位置在str中第sa[i]  sa[1~n]为有效值
 10 
 11 //rnk:就是str第i个位置的后缀是在字典序排第几 rnk[0~n-1]为有效值
 12 
 13 //height:字典序排i和i-1的后缀的最长公共前缀  height[2~n]为有效值,第二个到最后一个
 14 
 15 const int INF=0x3f3f3f3f;
 16 const int maxn = 1e5+10;
 17 int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn];
 18 int rnk[maxn],height[maxn];
 19 char s[maxn];
 20 int r[maxn],n,L;
 21 int be[maxn],vis[110];
 22 
 23 int cmp(int *r,int a,int b,int k)
 24 {
 25     return r[a]==r[b]&&r[a+k]==r[b+k];
 26 }
 27 
 28 void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长
 29 {
 30     int i,j,p,*x=wa,*y=wb,*t;
 31     for(i=0; i<m; i++)  wsf[i]=0;
 32     for(i=0; i<=n; i++)  wsf[x[i]=r[i]]++;
 33     for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
 34     for(i=n; i>=0; i--)  sa[--wsf[x[i]]]=i;
 35     p=1;
 36     j=1;
 37     for(; p<=n; j*=2,m=p){
 38         for(p=0,i=n+1-j; i<=n; i++)  y[p++]=i;
 39         for(i=0; i<=n; i++)  if(sa[i]>=j)  y[p++]=sa[i]-j;
 40         for(i=0; i<=n; i++)  wv[i]=x[y[i]];
 41         for(i=0; i<m; i++)  wsf[i]=0;
 42         for(i=0; i<=n; i++)  wsf[wv[i]]++;
 43         for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
 44         for(i=n; i>=0; i--)  sa[--wsf[wv[i]]]=y[i];
 45         swap(x,y);
 46         x[sa[0]]=0;
 47         for(p=1,i=1; i<=n; i++)
 48             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
 49     }
 50 }
 51 
 52 void getheight(int *r,int n)//n为添加0后的总长
 53 {
 54     int i,j,k=0;
 55     for(i=1; i<=n; i++)  rnk[sa[i]]=i;
 56     for(i=0; i<n; i++){
 57         if(k)
 58             k--;
 59         else
 60             k=0;
 61         j=sa[rnk[i]-1];
 62         while(r[i+k]==r[j+k])
 63             k++;
 64         height[rnk[i]]=k;
 65     }
 66 }
 67 
 68 bool check(int k)
 69 {
 70     memset(vis,0,sizeof(vis));
 71     int cnt=0;
 72     for(int i=2;i<=L;i++){
 73         if(height[i]>=k){
 74             if(!vis[be[sa[i]]]) cnt++;
 75             vis[be[sa[i]]]=1;               //就是这个地方卡了我快3个小时!!!
 76             if(!vis[be[sa[i-1]]]) cnt++;
 77             vis[be[sa[i-1]]]=1;
 78         }
 79         else {
 80             memset(vis,0,sizeof(vis));
 81             cnt=0;
 82         }
 83         if(cnt>=n) return 1;
 84     }
 85     return 0;
 86 }
 87 
 88 int main()
 89 {
 90     ios::sync_with_stdio(false);
 91     cin.tie(0);
 92     cout.tie(0);
 93     int t;
 94     cin>>t;
 95     while(t--){
 96         cin>>n;
 97         L=0;
 98         for(int i=0;i<n;i++){
 99             cin>>s;
100             int len=strlen(s);
101             for(int j=0;j<len;j++){
102                 r[L]=s[j];
103                 be[L++]=i;
104             }
105             r[L]=i+200;
106             be[L++]=i;
107             for(int j=len-1;j>=0;j--){
108                 r[L]=s[j];
109                 be[L++]=i;
110             }
111             if(i!=n-1) r[L]=i+n+200,be[L++]=i;
112         }
113         if(n==1) {
114             cout<<strlen(s)<<endl;
115             continue;
116         }
117         r[L]=0;
118         getsa(r,sa,L,500);
119         getheight(r,L);
120         int l=0,r=105,ans=0;
121         while(l<=r){
122             int mid=l+r>>1;
123             if(check(mid)) ans=mid,l=mid+1;
124             else r=mid-1;
125         }
126         cout<<ans<<endl;
127     }
128     return 0;
129 }

 

全部评论

相关推荐

我已成为0offer的糕手:别惯着,胆子都是练出来的,这里认怂了,那以后被裁应届被拖工资还敢抗争?
点赞 评论 收藏
分享
昨天 12:43
已编辑
门头沟学院 C++
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务