牛客挑战赛48 F 小丑生产值

有一个很显然的结论,一个周期串一定是一个本原平方串,否则字典序不优。所以先进行一次Lyndon分解,求出以每个字符开头的最短本原平方串,最后求前缀最小串即可。中途求字符串LCS、LCP以及比大小都可以用二分哈希来实现。
时间复杂度 O ( n log ⁡ 2 n + m ) O(n \log_2n +m) O(nlog2n+m),空间复杂度 O ( n ) O(n) O(n)

#include<stdio.h>
#include<string.h>
#define R register int
#define C const int
#define I inline
#define N 500002
#define P 1000000009
I void Min(int&x,C y){
	if(x>y){
		x=y;
	}
}
char s[N];
int h[N],pw[N],rt[N],len[N],ansl[N],ansr[N],st[N],lazy[2000000];
I int GetHash(int l,int r){
	int t=h[r]-(long long)h[l-1]*pw[r-l+1]%P;
	return t<0?t+P:t;
}
I int GetLCP(int x,int y,int&n){
	if(s[x]!=s[y]){
		return 0;
	}
	int l=0,ans=0,mid,r=n-(x>y?x:y);
	while(l<=r){
		mid=l+r>>1;
		if(GetHash(x,x+mid)==GetHash(y,y+mid)){
			ans=mid;
			l=mid+1;
		}else{
			r=mid-1;
		}
	}
	return ans+1;
}
I int GetLCS(int x,int y){
	if(s[x]!=s[y]){
		return 0;
	}
	int l=0,ans=0,mid,r=(x<y?x:y)-1;
	while(l<=r){
		mid=l+r>>1;
		if(GetHash(x-mid,x)==GetHash(y-mid,y)){
			ans=mid;
			l=mid+1;
		}else{
			r=mid-1;
		}
	}
	return ans+1;
}
I bool Compare(int l1,int r1,int l2,int r2,int&n){
	int len=GetLCP(l1,l2,n);
	if(len>r1-l1||len>r2-l2){
		return r1-l1<r2-l2;
	}
	return s[l1+len]<s[l2+len];
}
I void Init(int p,int lf,int rt){
	lazy[p]=N;
	if(lf!=rt){
		Init(p<<1,lf,lf+rt>>1);
		Init(p<<1|1,lf+rt+2>>1,rt);
	}
}
I void Modify(int p,int lf,int rt,C l,C r,C d){
	if(l<=lf&&rt<=r){
		Min(lazy[p],d);
	}else{
		int mid=lf+rt>>1;
		if(l<=mid){
			Modify(p<<1,lf,mid,l,r,d);
		}
		if(r>mid){
			Modify(p<<1|1,mid+1,rt,l,r,d);
		}
	}
}
I void Release(int p,int lf,int rt,int pre){
	Min(pre,lazy[p]);
	if(lf==rt){
		len[lf]=pre;
	}else{
		Release(p<<1,lf,lf+rt>>1,pre);
		Release(p<<1|1,lf+rt+2>>1,rt,pre);
	}
}
I void GetRuns(int&n){
	int Top=0,r,p,cl,cr;
	st[Top]=n+1;
	for(R i=n;i!=0;i--){
		while(Top!=0&&Compare(i,st[Top]-1,st[Top],st[Top-1]-1,n)==true){
			Top--;
		}
		r=st[Top]-1;
		p=r-i+1;
		cl=i-GetLCS(i-1,r);
		cr=r+GetLCP(i,r+1,n);
		if(cr-cl+1>=p<<1){
			Modify(1,1,n,cl,cr-(p<<1)+1,p);
		}
		Top++;
		st[Top]=i;
	}
}
int main(){
	pw[0]=1;
	scanf("%s",s+1);
	int n=strlen(s+1);
	Init(1,1,n);
	for(R i=1;i<=n;i++){
		pw[i]=29ll*pw[i-1]%P;
		h[i]=(29ll*h[i-1]+s[i]-'a')%P;
	}
	GetRuns(n);
	for(R i=1;i<=n;i++){
		s[i]='a'+'z'-s[i];
	}
	GetRuns(n);
	for(R i=1;i<=n;i++){
		s[i]='a'+'z'-s[i];
	}
	Release(1,1,n,N);
	for(R i=1;i<=n;i++){
		if(len[i]==N){
			ansl[i]=ansl[i-1];
			ansr[i]=ansr[i-1];
		}else{
			ansl[i]=i;
			ansr[i]=i+(len[i]<<1)-1;
			if(ansl[i-1]!=0&&Compare(i,ansr[i],ansl[i-1],ansr[i-1],n)==false){
				ansl[i]=ansl[i-1];
				ansr[i]=ansr[i-1];
			}
		}
	}
	scanf("%d",&n);
	for(R i=n;i!=0;i--){
		scanf("%d",&n);
		if(ansl[n]==0){
			puts("-1");
		}else{
			printf("%d %d\n",ansl[n],ansr[n]);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值