[NOI2016]优秀的拆分

这题的$O(n^2)$暴力可以拿到$95$分,用哈希预处理出$f_i$表示以$i$结尾的AA串数量,再用哈希和$f_i$统计答案即可

然后考虑正解,设$f_i$表示以$i$开头的AA串数量,$g_i$表示以$i$结尾的AA串数量,那么答案就是$\sum\limits_{i=1}^{n-1}g_if_{i+1}$,现在的问题就是预处理$f$和$g$

枚举AA串中A的长度$L$,把整个字符串中的$i,i+L,\cdots$称为“关键点”,那么一个AA串必定跨越两个关键点

对于每两个相邻的关键点$u,v(v=u+L)$,我们求出$x=\text{lcp}(S_{u\cdots n},S_{v\cdots n}),y=\text{lcs}(S_{1\cdots u},S_{1\cdots v})$(这里的lcs是最长公共 后缀),那么$S_{u-y+1\cdots u+x-1}=S_{v-y+1\cdots v+x-1}$,这时如果$x+y-1\geq L$,说明我们找到了一些合法的AA,它可以起始于$[u-y+1,u+x-L]$并终止于$[v+x-L,v+x-1]$,区间$+1$直接差分即可(注意同样长度的AA不能在同一个位置出现多次,特判一下即可)

为了偷懒,对字符串的处理我用了二分+哈希,总时间复杂度$O(n\log_2^2n)$,可是这毒瘤数据居然卡自然溢出哈希...不过大概也是我的姿势水平不太够

#include<stdio.h>
#include<string.h>
typedef long long ll;
const int mod=998244353;
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
char s[30010];
ll h[30010],bs[30010];
int f[30010],g[30010],n;
int get(int l,int r){return((h[r]-h[l-1]*bs[r-l+1])%mod+mod)%mod;}
int lcp(int x,int y){
	int l,r,mid,ans;
	l=1;
	r=min(n-x+1,n-y+1);
	ans=0;
	while(l<=r){
		mid=(l+r)>>1;
		if(get(x,x+mid-1)==get(y,y+mid-1)){
			ans=mid;
			l=mid+1;
		}else
			r=mid-1;
	}
	return ans;
}
int lcs(int x,int y){
	int l,r,mid,ans;
	l=1;
	r=min(x,y);
	ans=0;
	while(l<=r){
		mid=(l+r)>>1;
		if(get(x-mid+1,x)==get(y-mid+1,y)){
			ans=mid;
			l=mid+1;
		}else
			r=mid-1;
	}
	return ans;
}
void add(int*a,int l,int r){
	if(l>r)return;
	a[l]++;
	a[r+1]--;
}
ll work(){
	int L,i,a,b,enf,eng;
	ll ans;
	scanf("%s",s+1);
	n=strlen(s+1);
	bs[0]=1;
	for(i=1;i<=n;i++){
		h[i]=(h[i-1]*379ll+s[i]-'a')%mod;
		bs[i]=bs[i-1]*379ll%mod;
	}
	memset(f,0,sizeof(f));
	memset(g,0,sizeof(g));
	for(L=1;L<=n>>1;L++){
		enf=eng=0;
		for(i=1;i+L<=n;i+=L){
			a=lcp(i,i+L);
			b=lcs(i,i+L);
			if(a+b-1>=L){
				add(f,max(i-b+1,enf+1),i+a-L);
				enf=max(enf,i+a-L);
				add(g,max(i+L-b+L,eng+1),i+L+a-1);
				eng=max(eng,i+L+a-1);
			}
		}
	}
	for(i=1;i<=n;i++){
		f[i]+=f[i-1];
		g[i]+=g[i-1];
	}
	ans=0;
	for(i=1;i<n;i++)ans+=(ll)g[i]*f[i+1];
	return ans;
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--)printf("%lld\n",work());
}

猜你喜欢

转载自www.cnblogs.com/jefflyy/p/9095103.html