LGP4199题解

因为没有简化题意一直没去做,直到今天讲这道题才口胡出来

要求对称,很明显这样一个“子序列”的对称中心只可能有一个,那么先枚举这个对称中心。

然后我们需要判断两个位置是否相同。看上去好像很困难。

考虑设计哈希函数 f(x,y),使得 f(Va,Vb)0f(Va,Va)=f(Vb,Vb)=0

首先等于 0,那么一定有一个 (xy)。其次,注意到字符集只有 2,为了方便,我们令 f(x,y)=f(y,x)。那么就包含了 (xy)2

所以 f(x,y)=(VxVy)2=Vx2+Vy22VxVy,这就够了。

我们需要计算的是 match[i]=j=0f(ij,i+j),这有点像卷积。

拆开得到:

j=0(Vij2+Vi+j2)2Vi+jVij

后面这玩意儿可以用前缀和搞定,前面这玩意儿做一个卷积就好啦。

这样做会算上连续的一段,使用 manacher 计算出来并且减掉就好啦。

复杂度 O(nlogn)

#include<cstring>
#include<cstdio>
typedef unsigned ui;
const ui M=1e5+5,G=3,mod=998244353,MOD=1e9+7;
ui n,V[M],S[M],pw2[M],f[M<<2];ui ans;char s[M];
ui p[M<<1];char c[M<<1];
inline ui min(const ui&a,const ui&b){
	return a>b?b:a;
}
inline ui pow(ui a,ui b=mod-2){
	ui ans(1);for(;b;b>>=1,a=1ull*a*a%mod)if(b&1)ans=1ull*ans*a%mod;return ans;
}
inline ui Add(const ui&a,const ui&b){
	return a+b>=mod?a+b-mod:a+b;
}
inline ui Del(const ui&a,const ui&b){
	return b>a?a-b+mod:a-b;
}
inline void swap(ui&a,ui&b){
	ui c=a;a=b;b=c;
}
inline void DFT(ui*f,const ui&n){
	for(ui len=n>>1;len>=1;len>>=1){
		const ui w1=pow(G,(mod-1>>1)/len);
		for(ui k=0;k<n;k+=len<<1){
			for(ui w(1),i=0;i<len;++i){
				const ui x=f[i|k],y=f[i|k|len];
				f[i|k]=Add(x,y);f[i|k|len]=1ull*w*Del(x,y)%mod;
				w=1ull*w*w1%mod;
			}
		}
	}
}
inline void IDFT(ui*f,const ui&n){
	for(ui len=1;len<n;len<<=1){
		const ui w1=pow(G,(mod-1>>1)/len);
		for(ui k=0;k<n;k+=len<<1){
			for(ui w(1),i=0;i<len;++i){
				const ui x=f[i|k],y=1ull*w*f[i|k|len]%mod;
				f[i|k]=Add(x,y);f[i|k|len]=Del(x,y);
				w=1ull*w*w1%mod;
			}
		}
	}
	const ui inv=pow(n);
	for(ui i=0;i<n;++i)f[i]=1ull*f[i]*inv%mod;
	for(ui i=1;(i<<1)<n;++i)swap(f[i],f[n-i]);
}
inline ui manacher(char*s){
	ui R(0),mid(0),ans(0);c[0]='^';c[1]='#';
	for(ui i=1;i<=n;++i)c[i<<1]=s[i],c[i<<1|1]='#';
	for(ui i=1;i<=(n<<1);++i){
		p[i]=i<=R?min(p[(mid<<1)-i],p[mid]+mid-i):1;
		while(c[i-p[i]]==c[i+p[i]])++p[i];
		if(i+p[i]-1>R)mid=i,R=i+p[i]-1;
		ans=(ans+(p[i]>>1))%MOD;
	}
	return ans;
}
signed main(){
	scanf("%s",s+1);n=strlen(s+1);pw2[0]=1;
	for(ui i=1;i<=n;++i){
		V[i]=s[i]=='a'?1:2;pw2[i]=pw2[i-1]*2%MOD;
		f[i]=V[i];S[i]=S[i-1]+V[i]*V[i];
	}
	ui len(1);
	while(len<n+n+1)len<<=1;
	DFT(f,len);
	for(ui i=0;i<len;++i)f[i]=1ull*f[i]*f[i]%mod;
	IDFT(f,len);
	for(ui i=1;i<=n;++i){
		ui len=min(n-i,i-1);
		ans=(ans+pw2[len+1-((S[i+len]-S[i-len-1])-f[i<<1])]-1)%MOD;
		if(len!=n-i)++len;
		ans=(ans+pw2[len-((S[i+len]-S[i-len])-f[i<<1|1])]-1)%MOD;
	}
	printf("%u",(MOD+ans-manacher(s))%MOD);
}

本文作者:Prean

本文链接:https://www.cnblogs.com/lmpp/p/15946994.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Prean  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
var canShowAdsense=function(){return !!0};
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起