cogs 2605 寒假ing

题目链接
题解:
其实这道题是poj3693的弱化版,不用考虑字符串的字典序。
博客链接
还是先枚举循环节长度T,再枚举i,保证iT,(i+1)T下标合法。对于这两个下标求a=LCP(iT,(i+1)T)。因为不用考虑字符串是谁,只需要知道循环节个数最大值即可,因此是有更简单的做法的,即不需要求iT,(i+1)T的LCS。
简单地说,如果(T|a),此时iT前面即使还能匹配上也不可能再多一个循环节,否则这个子串就是由(i-1)T,iT访问的了。所以直接用(lfloorfrac{a}{T} floor+1)更新答案即可。如果不整除,那么可能在前面多匹配些,会多一个循环节,那就再求一下(b=LCP(iT-l+amod l,(i+1)T-l+amod l)),用(lfloorfrac{b}{T} floor+1)更新一下答案,复杂度(O(nln n))

code

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define fcl fclose(stdin); fclose(stdout); return 0
int n;
char str[100010];
int C[100010],Ws[100010],Rank[100010],Sa[100010],Height[100010],ST[50010][19];
int Table[50010];
void Da(){
	int i,j,c,k,m=200,p;
	memset(Ws,0,(m+1)<<2);
	for(i=0;i<n;++i) Ws[Rank[i]=str[i]]++;
	for(i=1;i<=m;++i) Ws[i]+=Ws[i-1];
	for(i=0;i<n;++i) Sa[--Ws[Rank[i]]]=i;
	for(c=1;c<=n;c<<=1,m=p){
		for(j=0,i=n-c;i<n;++i) C[j++]=i;
		for(i=0;i<n;++i) if(Sa[i]>=c) C[j++]=Sa[i]-c;
		memset(Ws,0,(m+1)<<2);
		for(i=0;i<n;++i) Ws[Rank[i]]++;
		for(i=1;i<=m;++i) Ws[i]+=Ws[i-1];
		for(i=n-1;i>=0;--i) Sa[--Ws[Rank[C[i]]]]=C[i];
		for(C[Sa[0]]=0,i=1,p=0;i<n;++i)
			C[Sa[i]]=(Rank[Sa[i]]==Rank[Sa[i-1]]&&Rank[Sa[i]+c]==Rank[Sa[i-1]+c]?p:++p);
		memcpy(Rank,C,n<<2);
	}
	for(i=0,j=0,k=0;i<n;++i){
		if(Rank[i]==0) continue;
		for(k=(k?k-1:0),j=Sa[Rank[i]-1];str[i+k]==str[j+k];++k);
		Height[Rank[i]]=k;
	}
	for(i=n-1;i>=0;--i){
		ST[i][0]=Height[i];
		for(j=0;j<17;++j){
			if(i+(1<<j)<n) ST[i][j+1]=min(ST[i][j],ST[i+(1<<j)][j]);
			else ST[i][j+1]=ST[i][j];
		}
	}
}
inline int Lcp(int a,int b){
	a=Rank[a]; b=Rank[b];
	if(a>b) swap(a,b);
	a++;
	return min(ST[a][Table[b-a+1]],ST[b-(1<<Table[b-a+1])+1][Table[b-a+1]]);
}
int main(){
	freopen("broken.in","r",stdin);
	freopen("broken.out","w",stdout);
	
	int T;
	for(int i=1,k=0;i<=50000;i<<=1,++k){
		for(int j=i;j<(i<<1)&&j<=50000;++j) Table[j]=k;
	}
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		scanf("%s",str);
		str[n++]='$'; str[n]=0;
		Da();
		int l,i,x,y,ans=1;
		for(l=1;(l<<1)<=n;++l){
			for(i=0;i+l<n;i+=l*(y/l+1)){
				x=i+l;
				y=Lcp(i,x);
				ans=max(ans,y/l+1);
				if(y%l) ans=max(ans,1+Lcp(i-l+y%l,x-l+y%l)/l);
			}
		}
		printf("%d
",ans);
	}
	fcl;
}
原文地址:https://www.cnblogs.com/kito/p/7111437.html