[SPOJ220 Relevant Phrases of Annihilation]

[关键字]:后缀数组 字符串

[题目大意]:给定n 个字符串,求在每个字符串中至少出现两次且不重叠的最长子串。

//======================================================================

[分析]:做法和POJ3294大同小异,也是先将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符(且小于它们)隔开,最后加上一个最小的数求后缀数组。然后二分答案,再将后缀分组。判断的时候,要看是否有一组后缀在每个原来的字符串中至少出现两次,并且在每个原来的字符串中,后缀的起始位置的最大值与最小值之差是否不小于当前答案(判断能否做到不重叠,如果题目中没有不重叠的要求,那么不用做此判断)。

[代码]:

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN=100100;
const int MAXL=10010;

int n,x,test,df,r,l;
int top[MAXN],sa[MAXN],rank[MAXN],temp[MAXN],height[MAXN];
int s[MAXN],belong[MAXN],v[15],Max[15],Min[15];
char s1[MAXL];

void Make()
{
int i,j,len,m;
m=n<256?256:n;
memset(top,0,m*sizeof(int));
for (i=0;i<n;++i) ++top[rank[i]=s[i]&0xff];
for (i=1;i<m;++i) top[i]+=top[i-1];
for (i=0;i<n;++i) sa[--top[rank[i]]]=i;
for (len=1;len<n;len<<=1)
{
for (i=0;i<n;++i)
{
j=sa[i]-len;
if (j<0) j+=n;
temp[top[rank[j]]++]=j;
}
sa[temp[top[0]=0]]=j=0;
for (i=1;i<n;++i)
{
if (rank[temp[i]]!=rank[temp[i-1]] ||
rank[temp[i]+len]!=rank[temp[i-1]+len])
top[++j]=i;
sa[temp[i]]=j;
}
memcpy(rank,sa,m*sizeof(int));
memcpy(sa,temp,m*sizeof(int));
if (j>=n-1) break;
}
}

void Lcp()
{
int i,j,k;
for (j=rank[height[i=k=0]=0];i<n-1;++i,++k)
while (k>=0 && s[i]!=s[sa[j-1]+k])
height[j]=(k--),j=rank[sa[j]+1];
}

bool Judge(int limit)
{
int i,j;
memset(v,0,sizeof(v));
memset(Min,100,sizeof(Min));
memset(Max,200,sizeof(Max));
for (i=1;i<=n;++i)
{
if (height[i]<limit)
{
for (j=1;j<=x;++j)
if (v[j]<2 || Max[j]-Min[j]<limit) break;
if (j==x+1) return 1;
memset(v,0,sizeof(v));
memset(Max,200,sizeof(Max));
memset(Min,100,sizeof(Min));
}
++v[belong[sa[i]]];
Max[belong[sa[i]]]=Max[belong[sa[i]]]>sa[i]?Max[belong[sa[i]]]:sa[i];
Min[belong[sa[i]]]=Min[belong[sa[i]]]<sa[i]?Min[belong[sa[i]]]:sa[i];
}
return 0;
}

void Solve()
{
int ans=0,mid,l=1,r=10100;
while (l<=r)
{
mid=(l+r)/2;
if (Judge(mid)) ans=mid,l=mid+1; else r=mid-1;
}
printf("%d\n",ans);
}

int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
scanf("%d",&test);
while (test--)
{
n=df=0;
scanf("%d",&x);
for (int i=1;i<=x;++i)
{
scanf("%s",s1);
int len=strlen(s1);
for (int j=0;j<len;++j) s[n+j]=(int)s1[j]+10,belong[n+j]=i;
s[n+len]=++df,belong[n+len]=0;
n+=len+1;
}
s[n-1]=0;
Make();
Lcp();
/*printf("%d\n",n);
for (int i=0;i<n;++i) printf("%d ",height[i]);
printf("\n");
for (int i=0;i<n;++i) printf("%d ",belong[i]);
printf("\n");
*/
height[n]=0;
Solve();
}
return 0;
}



你可能感兴趣的:(ant)