UvaL4513 - Stammering Aliens
题意:
给出n( n <= 100)个字符串, 只包含小写字母, 每个字符串长度不超过1000且不为空
求出最长的子串,满足在n个字符串当中出现在一半以上的字符串上, 如果有多个这样的子串,按字典序输出
题解:
先吐槽一波,好气哦,cmp函数+l写成了+1(follow me: yi),然后就找了一个小时的bug
这个题是要求构造一个串,跟一半的串有最长公共前缀,所以就将所有的串连起来当作母串处理
然后求出最长公共前缀,因为是要求字典序,所以求后缀数组
hight[]数组的含义就是i与i-1串的最长公共前缀的长度,如果hight[i]>=mid,那么就符合
二分搜索长度,然后判断是否符合条件
sa[]数组的含义是 第i大的串在原串中的起始位置为sa[i]
belong[]数组的含义是 第i个字符属于原串的第几组字符
vis[]数组用于判断是否已经加进记录数组pos[mid]
代码:
#include <stdio.h> #include <string.h> #include <iostream> #include <vector> using namespace std; const int maxn=110000; int s[maxn],r[maxn],sa[maxn]; int t1[maxn],t2[maxn],c[maxn]; int Rank[maxn],height[maxn],belong[maxn]; int n,len; vector<int> pos[1005]; bool vis[110]; bool cmp(int r[],int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int str[],int sa[],int n,int m) { // n++; int i,j,p,*x=t1,*y=t2; for(i=0; i<m; ++i) c[i]=0; for(i=0; i<n; ++i) c[x[i]=str[i]]++; for(i=0; i<m; ++i) c[i]+=c[i-1]; for(i=n-1; i>=0; --i) sa[--c[x[i]]]=i; for(j=1; j<=n; j<<=1) { p=0; for(i=n-j; i<n; ++i) y[p++]=i; for(i=0; i<n; ++i) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=1; i<m; ++i) c[i]=0; for(i=0; i<n; ++i) c[x[y[i]]]++; for(i=1; i<m; ++i) c[i]+=c[i-1]; for(i=n-1; i>=0; --i) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for(i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; if(p>=n) break; m=p; } int k=0; n--; for(i=0; i<=n; ++i) Rank[sa[i]]=i; for(i=0; i<n; ++i) { if(k) --k; j=sa[Rank[i]-1]; while(str[i+k]==str[j+k]) ++k; height[Rank[i]]=k; } } bool solve(int mid) { bool lp=false,fg=false; memset(vis,false,sizeof(vis)); int cnt=0; for(int i=1;i<len;++i) { if(height[i]<mid) { memset(vis,false,sizeof(vis)); vis[belong[sa[i]]]=true; cnt=1; fg=false; } else { if(!vis[belong[sa[i]]]) { cnt++; vis[belong[sa[i]]]=true; } if(cnt>(n/2)) { lp=true; if(!fg) { pos[mid].push_back(sa[i]); fg=true; } } } } return lp; } int main() { char ss[1005]; bool fg=false; while(scanf("%d",&n)&&n) { if(fg) puts(""); len=0; for(int i=0; i<n; ++i) { scanf("%s",ss); int d=strlen(ss); for(int j=0;j<d;++j) { s[len]=ss[j]-'a'+1; belong[len]=i; len++; } s[len++]=27+i; } s[len-1]=0; da(s,sa,len,130); for(int i=0;i<=1000;++i) pos[i].clear(); int l=0,r=1000,mid,ans=0; while(l<=r) { mid=(l+r)>>1; if(solve(mid)) { ans=mid; l=mid+1; } else r=mid-1; } if(ans==0) { puts("?"); continue; } /* printf("---%d\n",ans); for(int i=0;i<pos[ans].size();++i) printf("%d ",pos[ans][i]); printf("\n"); */ for(int i=0;i<pos[ans].size();++i) { for(int j=0;j<ans;++j) printf("%c",s[pos[ans][i]+j]+'a'-1); printf("\n"); } fg=true; } return 0; }