【BZOJ3160】万径人踪灭

题面

imgimgimgimg

题目分析

我们来看一看一个回文串满足什么:

对于回文串,如果中点一定,所有以它为中点的点对下标之和也一定。

我们设下标为\(i\),点对个数之和为\(f(i)\),则方案数为\(2^{f(i)}-1\)

显然有\(f(x)=((\sum\limits_{i=1}^{x-1}[s[i]=s[x-i]])+1)/2\)

其中\(\sum\limits_{i=1}^{x-1}[s[i]=s[x-i]]\)可以视作一个卷积的形式;

我们指定字符,如a,则把\(s[i]=\)a的位置赋初值为\(1\),然后进行卷积即可。

因此,\(f(x)\)的答案为指定字符分别为a,b的卷积结果之和\(+1/2\)

代码实现

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#include<complex>
#define MAXN 0x7fffffff
typedef long long LL;
const int N=400005,mod=1e9+7;
using namespace std;
inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}
typedef complex<double> Z;
const double Pi=M_PI;
void FFT(Z *a,int x,int K){
	static int rev[N],lst;
	int n=1<<x;
	if(n!=lst){
		for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<x-1);
		lst=n;	
	}
	for(int i=0;i<n;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int i=1;i<n;i<<=1){
		int tmp=i<<1;
		Z wn(cos(Pi/i),sin(Pi*K/i));
		for(int j=0;j<n;j+=tmp){
			Z w(1,0);
			for(int k=0;k<i;k++,w=w*wn){
				Z x=a[j+k],y=a[i+j+k]*w;
				a[j+k]=x+y,a[i+j+k]=x-y;
			}
		} 
	}
	if(K==-1)for(int i=0;i<n;i++)a[i]/=n;
}

Z a[N],b[N],c[N];
string sr;
int ksm(int x,int k){
	int ret=1;
	while(k){
		if(k&1)ret=(LL)ret*x%mod;
		x=(LL)x*x%mod,k>>=1;
	}
	return ret;
}
int ans;
char now[N];int p[N];
void Manacher(string s){
	int len=s.length();
	for(int i=1;i<=len;i++)now[2*i-1]='%',now[2*i]=s[i-1];
	now[len=len*2+1]='%';
	int pos=0,R=0;
	for (int i=1;i<=len;i++){
		if(i<R)p[i]=min(p[2*pos-i],R-i); else p[i]=1;
		while(1<=i-p[i]&&i+p[i]<=len&&now[i-p[i]]==now[i+p[i]]) p[i]++;
		if(i+p[i]>R)R=i+p[i],pos=i;
		ans=(ans-p[i]/2+mod)%mod;
	}
}

int main(){
	cin>>sr;
	int len=sr.length();
	int x=ceil(log2(len<<1|1));
	for(int i=0;i<len;i++)a[i].real()=(sr[i]=='a'),b[i].real()=(sr[i]=='a');
	
	FFT(a,x,1),FFT(b,x,1);
	for(int i=0;i<(1<<x);i++)c[i]=a[i]*b[i];
	fill(a,a+(1<<x),0),fill(b,b+(1<<x),0);
	for(int i=0;i<len;i++)a[i].real()=(sr[i]=='b'),b[i].real()=(sr[i]=='b');
	FFT(a,x,1),FFT(b,x,1);
	for(int i=0;i<(1<<x);i++)c[i]+=a[i]*b[i];
	
	FFT(c,x,-1);
	for(int i=0;i<(1<<x);i+=2)c[i].real()++;
	
	for(int i=0;i<(len<<1)-1;i++)ans=(ans+ksm(2,((int)(c[i].real()+0.5))/2)-1)%mod; 
	Manacher(sr);
	cout<<ans;
	return 0;
}
posted @ 2018-11-28 10:43  Emiya_2020  阅读(149)  评论(0编辑  收藏  举报