luogu P4199 万径人踪灭

LINK:万径人踪灭

很妙的一道题 说明我NTT的意识还不够.

题目中的一个非常特殊的条件 字符串只有a,b两种。

考虑求出所有的方案 连续的一段回文串不算 间隔的才算 发现我们如果去枚举间隔 再统计回文串会非常麻烦。

显然我们求出这个字符串中所有的 不管有没有间隔的回文串都求出来 最后减掉一些没有间隔的回文串即可。

考虑后半部分 没有间隔 每个回文串 我们以回文中心为标记统计方案 显然manacher一下即可。

考虑前半部分 还是以回文中心来判断每一个方案 这样可以做到不重不漏。

对于某个回文中心i来说 如果存在 \(S_{i+j}==S_{i-j}\)那么所有这个j点可以被使用。要统计出来有多少个j.

暴力统计是\(n^2\)的。但是manacher也不行。

但是这类似于字符串的特殊匹配问题 一般考虑转换成多项式卷积问题。

判断卷积问题 一般要发现下标的特殊性.\(i+j+i-j=2\cdot i\) 至此 我们发现来一发卷积 如果能够匹配的话贡献为1 且对于i这个位置 所有的j的贡献 被统计在了2i的位置上。

考虑题目中的特殊条件 只有a,b两种 这样算贡献的时候先将a的位置赋值为1 再做b.即可。

值得注意的是 最后需要判断一下是否i为偶数位 因为其回文中心也被算进去了. 需要特判一下.这里可以使用NTT 因为答案绝对不会超过mod.

const int MAXN=300010,G=3;
int n,lim,cnt;ll ans;
int a[MAXN],b[MAXN],p[MAXN],rev[MAXN];
char ch[MAXN],c[MAXN];
inline int ksm(ll b,int p,int M)
{
	ll cnt=1;
	while(p)
	{
		if(p&1)cnt=cnt*b%M;
		b=b*b%M;p=p>>1;
	}
	return cnt;
}
inline void NTT(int *a,int op)
{
	rep(0,lim-1,i)if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int len=2;len<=lim;len=len<<1)
	{
		int mid=len>>1;
		ll wn=ksm(G,op==1?(mod-1)/len:mod-1-(mod-1)/len,mod);
		for(int j=0;j<lim;j+=len)
		{
			ll d=1;
			for(int i=0;i<mid;++i)
			{
				int x=a[i+j];int y=(ll)a[i+j+mid]*d%mod;
				a[i+j]=(x+y)%mod;a[i+j+mid]=(x-y+mod)%mod;
				d=d*wn%mod;
			}
		}
	}
	if(op==-1)
	{
		ll inv=ksm(lim,mod-2,mod);
		rep(0,lim-1,i)a[i]=a[i]*inv%mod;
	}
}
inline void manacher()
{
	int mx=0,mid=0;
	rep(1,cnt,i)
	{
		if(i<mx)p[i]=min(p[(mid<<1)-i],mx-i);
		else p[i]=1;
		while(c[i-p[i]]==c[i+p[i]])++p[i];
		if(p[i]+i>mx)mx=p[i]+i,mid=i;
		ans=(ans-(p[i]-1+((p[i]-1)&1))/2)%P;
	}
}
int main()
{
	freopen("1.in","r",stdin);
	scanf("%s",ch);n=strlen(ch);
	rep(0,n-1,i)if(ch[i]=='a')a[i]=1;else b[i]=1;
	lim=1;while(lim<n+n)lim=lim<<1;
	rep(0,lim-1,i)rev[i]=rev[i>>1]>>1|((i&1)?lim>>1:0);
	NTT(a,1);NTT(b,1);
	rep(0,lim-1,i)a[i]=(ll)a[i]*a[i]%mod,b[i]=(ll)b[i]*b[i]%mod;
	NTT(a,-1);NTT(b,-1);
	rep(0,lim-1,i)a[i]+=b[i];
	rep(0,lim-1,i)
	{
		if(!a[i])continue;
		if(!(i&1))
		{
			int ww=(a[i]+1)>>1;
			ans=(ans+ksm(2,ww,P)-1)%P;
		}
		else
		{
			int ww=a[i]>>1;
			ans=(ans+ksm(2,ww,P)-1)%P;
		}
	}
	c[0]='&';c[cnt=1]='#';
	rep(0,n-1,i)c[++cnt]=ch[i],c[++cnt]='#';
	manacher();putl((ans+P)%P);return 0;
}
posted @ 2020-04-07 21:22  chdy  阅读(152)  评论(0编辑  收藏  举报