记录编号 215518 评测结果 AAAAAAAAAA
题目名称 [SPOJ 687] 重复的字符串 最终得分 100
用户昵称 Gravatarzys 是否通过 通过
代码语言 C++ 运行时间 30.707 s
提交时间 2015-12-22 11:44:45 内存使用 5.49 MiB
显示代码纯文本
#define Max(a,b)((a)>(b)?(a):(b))
#define Min(a,b)((a)<(b)?(a):(b))

#include<cstdio>
#include<cstring>

using namespace std;

char s[50010],c[100];
int rmq[50010][20],ws[50010],wv[50010],L,R,tmp,wb[50010];
int q,n,m,wa[50010],rank[50010],sa[50010],h[50010],Mid,Ans,tMin,tMax;

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

void Get_sa()
{
	int i,j,p=0,*x=wa,*y=wb,*t;
	for(i=0;i<=m;i++)ws[i]=0;
	for(i=1;i<=n;i++)ws[x[i]=s[i]]++;
	for(i=1;i<=m;i++)ws[i]+=ws[i-1];
	for(i=n;i>=1;i--)sa[ws[x[i]]--]=i;
	for(j=1;p<n;j<<=1,m=p){
		for(p=0,i=n-j+1;i<=n;i++)y[++p]=i;
		for(i=1;i<=n;i++)if(sa[i]>j)y[++p]=sa[i]-j;
		for(i=0;i<=m;i++)ws[i]=0;
		for(i=1;i<=n;i++)wv[i]=x[y[i]];
		for(i=1;i<=n;i++)ws[wv[i]]++;
		for(i=1;i<=m;i++)ws[i]+=ws[i-1];
		for(i=n;i>=1;i--)sa[ws[wv[i]]--]=y[i];
		for(t=x,x=y,y=t,x[sa[1]]=1,p=1,i=2;i<=n;i++)
		    x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p:(++p);
	}
}

void Get_height()
{
	int i,j,k=0;
	for(i=1;i<=n;i++)rank[sa[i]]=i;
	for(i=1;i<=n;h[rank[i++]]=k)
	for(k?k--:k=0,j=sa[rank[i]-1];s[i+k]==s[j+k];k++);
}

int Query(int l,int r)
{
	int k=0;L=r-l+1;while((1<<k)<=L)k++;k--;
	return Min(rmq[l][k],rmq[r-(1<<k)+1][k]);
}

int main()
{
	freopen("repeats.in","r",stdin);
	freopen("repeats.out","w",stdout);
	scanf("%d",&q);
	while(q--){
		scanf("%d",&n);Ans=1;memset(rmq,0,sizeof(rmq));
		memset(h,0,sizeof(h));memset(sa,0,sizeof(sa));
		memset(wa,0,sizeof(wa));memset(wb,0,sizeof(wb));
		memset(rank,0,sizeof(rank));memset(s,0,sizeof(s));
		memset(c,0,sizeof(c));memset(wv,0,sizeof(wv));
		for(int i=1;i<=n;i++){scanf("%s",c);s[i]=c[0];}
		m='b';Get_sa();Get_height();
		for(int i=1;i<=n;i++)rmq[i][0]=h[i];
		for(int k=1,l=1;l<=n;k++,l<<=1)for(int i=1;i<=n-l+1;i++)
		    rmq[i][k]=Min(rmq[i][k-1],rmq[i+l][k-1]);
		for(int l=1;l<=n;l++){
			for(int k=0;(k+1)*l+1<=n;k++){
				L=1;R=k*l+1;tmp=0;
				while(L<=R){
					Mid=(L+R)>>1;
					tMin=Min(rank[Mid],rank[Mid+l]);
					tMax=Max(rank[Mid],rank[Mid+l]);
					if(Query(tMin+1,tMax)>tmp)
						R=Mid-1,tmp=Query(tMin+1,tMax);
					else L=Mid+1;
				}
				tmp=tmp/l+1;
				if(tmp>Ans)Ans=tmp;
			}
		}
		printf("%d\n",Ans);
	}
}