您的位置:首页 > Web前端

POJ 3294 Life Forms <后缀数组+二分>

2017-05-01 12:48 387 查看
题目:传送门

分析:求重复出现大于n/2次的最长子串,有多个时按字典序输出。对长度进行二分。RE了几次,注意满足条件的子串有可能有超过1000个。

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;

const int MAXN=110;
const int MAXL=1010;
int wm[MAXN*MAXL],wa[MAXN*MAXL],wb[MAXN*MAXL],height[MAXN*MAXL],sa[MAXN*MAXL];
int *rank;

bool cmp(int *r,int a,int b,int len){
return r[a]==r[b]&&r[a+len]==r[b+len];
}

void da(int *data,int *sa,int n,int m){
int *x=wa,*y=wb,*t,i,j,p;
for(i=0;i<m;++i) wm[i]=0;
for(i=0;i<n;++i) ++wm[x[i]=data[i]];
for(i=1;i<m;++i) wm[i]+=wm[i-1];
for(i=n-1;i>=0;--i) sa[--wm[x[i]]]=i;
for(j=p=1;p<n;j<<=1,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<m;++i) wm[i]=0;
for(i=0;i<n;++i) ++wm[x[y[i]]];
for(i=1;i<m;++i) wm[i]+=wm[i-1];
for(i=n-1;i>=0;--i) sa[--wm[x[y[i]]]]=y[i];
for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
rank=x;
}

void calHeight(int *data,int *sa,int n){
for(int i=0,j,k=0;i<n;height[rank[i++]]=k)
for(k?--k:k,j=sa[rank[i]-1];data[i+k]==data[j+k];++k);
}

int len[MAXN],data[MAXL*MAXN];
int n,a[MAXL],t,cas=0;
char str[MAXL];
int nn;
bool vis[MAXN];

bool judge(int _len,int x){
t=0;
int flag,counte=0;
for(int i=1;i<=_len;++i){
if(height[i]>=x){
int posi1=sa[i-1],posi2=sa[i];
if(!(flag++)) memset(vis,false,sizeof vis);
for(int j=1;j<=n;++j){
if(posi1>=len[j-1]&&posi1<len[j]) counte+=vis[j-1]?0:1,vis[j-1]=true;
if(posi2>=len[j-1]&&posi2<len[j]) counte+=vis[j-1]?0:1,vis[j-1]=true;
if(counte>n/2) break;
}
}
else{
if(counte>n/2) a[t++]=i-1;
flag=counte=0;
}
}
if(counte>n/2) a[t++]=_len;
if(t){
nn=t;
return true;
}
else return false;
}

void solve(int _len){
int l=0,r=MAXL;
while(l<r){
int mid=l+(r-l+1)/2;
if(judge(_len,mid)) l=mid;
else r=mid-1;
}
if(!l) cout<<"?\n";
else{
for(int i=0;i<nn;++i){
int star=sa[a[i]];
for(int j=star;j<star+l;++j){
printf("%c",data[j]);
}
printf("\n");
}
}
}

int main(){
int p;
while(cin>>n,n){
p=len[0]=0;
for(int i=0;i<n;++i){
scanf("%s",str);
int temp_len=strlen(str);
len[i+1]=len[i]+temp_len+1;
for(int j=0;j<temp_len;++j){
data[p++]=str[j];
}
data[p++]=130+i;
}
if(cas++) cout<<endl;
if(n==1){
printf("%s\n",str);
continue;
}
data[p-1]=0;
da(data,sa,p,300);
calHeight(data,sa,p-1);
solve(p-1);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: