UVA 11017 Life Forms 后缀数组+二分

UVA 11017

题意:给了n个字符串,如果有超过n/2的字符串有公共子串,求最长的公共子串,如果有多组解,按字典序输出

思路:可以把这n个字符串连接起来,中间用特殊字符连接,然后构造后缀数组,然后先用二分求出公共子串的最长长度,用height数组和sa数组(sa数组用于判断这部分后缀串包含的字符串数量是否多于n/2)去判定该长度的公共子串是否存在,最后再用height数组把符合条件的公共子串按字典序输出。(刘汝佳的模板竟然照搬都搬错.....)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1e5+1000;
struct S_array
{
	int s[maxn],sa[maxn],t[maxn],t2[maxn],c[maxn],n;
	void build_sa(int m)
	{
		int i,*x=t,*y=t2;
		for(i=0;i<m;i++)c[i]=0;
		for(i=0;i<n;i++)c[x[i]=s[i]]++;
		for(i=1;i<m;i++)c[i]+=c[i-1];
		for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
		for(int k=1;k<=n;k<<=1){
			int p=0;
			for(i=n-k;i<n;i++)y[p++]=i;
			for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
			for(i=0;i<m;i++)c[i]=0;
			for(i=0;i<n;i++)c[x[y[i]]]++;
			for(i=0;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]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
			if(p>=n)break;
			m=p;
		}
	}
	int rank[maxn],height[maxn];
	void getHeight()
	{
		int i,j,k=0;
		for(i=0;i<n;i++)rank[sa[i]]=i;
		for(i=0;i<n;i++){
			if(k)k--;
			if(rank[i]-1<0)
			continue;
			int j=sa[rank[i]-1];
			while(s[i+k]==s[j+k])k++;
			height[rank[i]]=k;
		}
	}
	void clear()
	{
		n=0;
	}
}sa;
int n,idx[maxn];
char s[1005];
int ok(int L,int R)
{
	int flag[205]={0};
	int cnt=0;
	for(int i=L;i<R;i++)
	if(!flag[idx[sa.sa[i]]])
	{
		flag[idx[sa.sa[i]]]=1;
		cnt++;
	}
	if(cnt>n/2)
	return 1;
	return 0;
}
int judge(int len)
{
	int L=0,R=1;
	for(;R<=sa.n;R++)
	{
		if(sa.height[R]<len||R==sa.n)
		{
			if(ok(L,R))
			return 1;
			L=R;
		}
	}
	return 0;
}
void print_sub(int k,int len)
{
	for(int i=k;i<len;i++)
	printf("%c",sa.s[i]+'a');
	printf("\n");
}
void print(int len)
{
	int L=0,R=1;
	for(;R<=sa.n;R++)
	{
		if(sa.height[R]<len||R==sa.n)
		{
			if(ok(L,R))
			print_sub(sa.sa[L],sa.sa[L]+len);
			L=R;
		}
	}
}
void work(int L,int R)
{
	int m=(L+R)/2;
	if(!judge(1))
	{
		printf("?\n");
		return;	
	}
	while(L<R)
	{
		if(judge(m))
		{
			if(L==m)
			break;
			L=m;
		}
		else
		R=m;
		m=(L+R)/2;
	}
	if(judge(m+1))
	m++;
	print(m);
}
void add(int c,int k)
{
	idx[sa.n]=k;
	sa.s[sa.n++]=c;
}
int main()
{
	int kase=0;
	while(~scanf("%d",&n)&&n)
	{
		int i,maxlen=0;
		sa.clear();
		if(kase++>0)
		printf("\n");
		for(i=0;i<n;i++)
		{
			scanf("%s",s);
			int len=strlen(s);
			maxlen=max(maxlen,len);
			for(int j=0;j<len;j++)
			add(s[j]-'a',i);
			add(100+i,n);
		}
		sa.build_sa(100+n);
		sa.getHeight();
		work(0,maxlen);
	}
}

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/80573161
今日推荐