2018.11.30 spoj220 Relevant Phrases of Annihilation(后缀数组+二分答案)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/84666492

传送门
代码:
先用特殊字符把所有字符串连接在一起。
然后二分答案将 s a sa 数组分组。
讨论是否存在一个组满足组内对于每一个字符串都存在两段不相交字串满足条件。

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=2e5+5;
int n,m,rk[N],ht[N],sa[N],sa2[N],len[N],st[N][18],Log[N],T_T,tt,mx[N],mn[N],idx[N];
char s[N],t[10005];
inline void Sort(){
	static int cnt[N];
	for(ri i=1;i<=m;++i)cnt[i]=0;
	for(ri i=1;i<=n;++i)++cnt[rk[i]];
	for(ri i=2;i<=m;++i)cnt[i]+=cnt[i-1];
	for(ri i=n;i;--i)sa[cnt[rk[sa2[i]]]--]=sa2[i];
}
inline void getsa(){
	for(ri i=1;i<=n;++i)rk[i]=(int)s[i],sa2[i]=i;
	m=122,Sort();
	for(ri w=1,p=0;m^n;w<<=1,p=0){
		for(ri i=n-w+1;i<=n;++i)sa2[++p]=i;
		for(ri i=1;i<=n;++i)if(sa[i]>w)sa2[++p]=sa[i]-w;
		Sort(),swap(sa2,rk),rk[sa[1]]=p=1;
		for(ri i=2;i<=n;++i)rk[sa[i]]=(sa2[sa[i]]==sa2[sa[i-1]]&&sa2[sa[i]+w]==sa2[sa[i-1]+w])?p:++p;
		m=p;
	}
	for(ri i=1,j,k=0;i<=n;ht[rk[i++]]=k)for(k?--k:k,j=sa[rk[i]-1];s[i+k]==s[j+k];++k);
	for(ri i=1;i<=n;++i)st[i][0]=ht[i];
	for(ri j=1;j<=17;++j)for(ri i=1;i+(1<<j)<=n;++i)st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
inline int rmq(int l,int r){return min(st[l][Log[r-l+1]],st[r-(1<<Log[r-l+1])+1][Log[r-l+1]]);}
inline bool solve(int l,int r,int mid){
	for(ri i=1;i<=tt;++i)mx[i]=-0x3f3f3f3f,mn[i]=0x3f3f3f3f;
	for(ri i=l;i<=r;++i)mx[idx[sa[i]]]=max(mx[idx[sa[i]]],len[idx[sa[i]]]-sa[i]+1),mn[idx[sa[i]]]=min(mn[idx[sa[i]]],len[idx[sa[i]]]-sa[i]+1);
	for(ri i=1;i<=tt;++i)if(mx[i]-mn[i]<mid)return 0;
	return 1;
}
inline bool check(int mid){
	for(ri l=1,r=1;l<=n;l=r+1){
		while(ht[l]<mid&&l<=n)++l;
		if(l>n)break;
		r=l;
		while(ht[r+1]>=mid&&r<n)++r;
		if(solve(l-1,r,mid))return 1;
	}
	return 0;
}
int main(){
	freopen("lx.in","r",stdin);
	Log[0]=-1;
	for(ri i=1;i<=200000;++i)Log[i]=Log[i>>1]+1;
	scanf("%d",&T_T);
	while(T_T--){
		scanf("%d",&tt),n=0;
		for(ri i=1;i<=tt;++i){
			scanf("%s",t+1),s[++n]=(char)i,len[i]=strlen(t+1);
			for(ri j=1;j<=len[i];++j)s[++n]=t[j];
			len[i]+=len[i-1]+1;
		}
		for(ri i=1;i<=tt;++i)for(ri j=len[i-1]+1;j<=len[i];++j)idx[j]=i;
		getsa();
		int l=1,r=len[1],ans=0;
		while(l<=r){
			int mid=l+r>>1;
			if(check(mid))ans=mid,l=mid+1;
			else r=mid-1;
		}
		cout<<ans<<'\n';
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/84666492