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;
}