题目链接:http://poj.org/problem?id=3294
题意:给定m个串,要求你求在在大于一半的串中出现串的最长长度,并输出该串,如果有多组同时输出(按照字典序)。
其实这个题目还是后缀数组的经典做法,枚举长度,最后的字典序输出其实没必要考虑,因为在后缀数组的处理过程中
本来就是按照后缀排好序的,所以求出来的结果一定是有序的,所以我们只要专注于程序的核心实现就好了
后缀数组处理多个字符串问题肯定是拼接,然后中间插入一个没有见过的字符,但是这里有个问题,如果单纯就用字符来
处理的话哪有那么多不同的字符呢,m最大为1000呢,所以在处理的时候转换成整形,这样就基本上无限了,接下来就是
二分枚举答案,按照height值排序分组,看看每个分组中出现在不同串中的个数,且height>=mid的大于m/2的就符合题目条件
找出来即可!
用belong数组还记录每个位置属于哪一个串,然后用is_visit标记这个串中是否出现过,为了防止不同分组中的出现冲突问题,
对于每个分组is_visit给一个不同的整形数来标记是否出现appear!
所以说这个题目只要掌握了后缀数组处理问题的基本方法写程序时细心一点基本上就是1A的节奏了!
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <string.h>
using namespace std;
#define MAX(a,b) (a>b?a:b)
#define maxn 110000
#define ws ws1
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m){
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p){
for(p=0,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=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n){
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;//在计算height的时候顺便就把rank计算出来了,反正也要用
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
char str[maxn];
int rec[maxn];
int sa[maxn],belong[maxn],n,num,m,pos,now,ans[1500],length;
int is_visit[1500];
int find_ans(int mid){
memset(is_visit,0,sizeof(is_visit));
int i,j,k,temp=1,appear=1;
now=0;
is_visit[belong[sa[1]]]=appear;
for(i=2;i<=n;i++){
if(height[i]>=mid){
if(is_visit[belong[sa[i]]]!=appear)
k=sa[i],temp++,is_visit[belong[sa[i]]]=appear;
}
else{
if(temp > m/2) ans[now++]=k,length=mid;
temp=1;
appear++;
is_visit[belong[sa[i]]]=appear;
}
}
if(now > 0){pos=now;return 1;}
return 0;
}
int solve(){
int l=1,r=1001,mid,i,j,k;
while(l<=r){
mid=(l+r)>>1;
if(find_ans(mid)) l=mid+1;
else r=mid-1;
}
if(pos==0){ printf("\?\n\n");return 0;}
for(i=0;i<pos;i++){
for(j=0;j<length;j++)
printf("%c",char((rec+ans[i])[j]));
printf("\n");
}
printf("\n");
return 0;
}
int main(){
int i,j,k,big;
while(scanf("%d",&m),m){
big=129,n=0;
for(i=1;i<=m;i++){
scanf("%s",str);
if(i!=0) belong[n]=i,rec[n++]=big++;
for(j=0;str[j];j++)
belong[n]=i,rec[n++]=str[j];
}
rec[n]=0;
da(rec,sa,n+1,2000);//这里是n+1 因为看这个函数里面是 < n 的
calheight(rec,sa,n);//注意这里面是 n 了因为看函数里面是 <=n 的,所以这里要注意
pos=length=0;
solve();
}
return 0;
}