您的位置:首页 > Web前端

POJ 3294 Life Forms(后缀数组)

2012-10-03 19:59 381 查看
题目链接:http://poj.org/problem?id=3294

题意:给定n个字符串,求出一个尽可能长的子串,使得该子串至少出现在n/2+1个给定的串中。

思路:将n个字符串连起来,二分答案,将后缀分成若干组,判断每组的后缀是否出现在不小于n/2+1个原串中。

int r
,sa
,wa
,wb
,wd
,rank
,h
;

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;
FOR0(i,m) wd[i]=0;
FOR0(i,n) wd[x[i]=r[i]]++;
FOR1(i,m-1) wd[i]+=wd[i-1];
FORL0(i,n-1) sa[--wd[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p)
{
p=0;
FOR(i,n-j,n-1) y[p++]=i;
FOR0(i,n) if(sa[i]>=j) y[p++]=sa[i]-j;
FOR0(i,m) wd[i]=0;
FOR0(i,n) wd[x[i]]++;
FOR1(i,m-1) wd[i]+=wd[i-1];
FORL0(i,n-1) sa[--wd[x[y[i]]]]=y[i];
t=x;x=y;y=t;p=1;x[sa[0]]=0;
FOR1(i,n-1) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}

void calHeight(int *r,int *sa,int n)
{
int i,j,k=0;
FOR1(i,n) rank[sa[i]]=i;
FOR0(i,n)
{
if(k) k--;
j=sa[rank[i]-1];
while(i+k<n&&j+k<n&&r[i+k]==r[j+k]) k++;
h[rank[i]]=k;
}
}

char s
;
int n,b
,M;
int ans
,ansNum;

int OK(int mid)
{
ansNum=0;
int i,j,k,t,x,hash[105],L,R;
FOR1(i,M)
{
L=i;
while(L<=M&&h[L]<mid) L++;
R=L;
while(R<=M&&h[R]>=mid) R++;
x=0; clr(hash,0);
for(k=L-1;k<R;k++)
{
t=b[sa[k]];
if(t&&!hash[t]) hash[t]=1,x++;
}
if(x>=n/2+1) ans[ansNum++]=sa[L-1];
i=R;
}
return ansNum;
}

void deal()
{
int low=1,high=1000,mid,L;
while(low<=high)
{
mid=(low+high)>>1;
if(OK(mid)) low=mid+1;
else high=mid-1;
}
if(OK(low)) L=low;
else OK(high),L=high;
if(!L)
{
puts("?");
return;
}
int i,j,k;
FOR0(i,ansNum)
{
k=ans[i];
FOR0(j,L) putchar(r[k+j]-100);
puts("");
}
}

int main()
{
bool tag=false;
while(scanf("%d",&n),n)
{
if(!tag) tag=true;
else puts("");
int i,j,k,len=0;
len=0;
for(i=1;i<=n;i++)
{
scanf("%s",s);
k=strlen(s);
for(j=0;j<k;j++) r[len]=s[j]+100,b[len++]=i;
if(i<n) r[len]=i,b[len++]=0;
}
r[len]=0;
da(r,sa,len+1,250);
calHeight(r,sa,len);
M=len;
deal();
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: