[BZOJ3160] 万径人踪灭 - FFT快速傅里叶变换 - manacher

        大爷题解:BZOJ 3160 万径人踪灭

        讲道理的话思路我是想到了的……然后不会manacher就现学了一发。

        记得有些奇奇怪怪的地方要用long long!

#include "set"
#include "map"
#include "math.h"
#include "vector"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "iostream"
#include "algorithm"
#define rep(f,a,b) for(f=a;f<=b;f++)

using namespace std;
typedef long long ll;

const double PI = acos(-1.0);
const int MOD = 1000000007;
const int N = 300005;

struct Complex{
	double r,i; typedef Complex ttp;
	typedef const ttp ctp; Complex(){r=i=0.0;}
	Complex(double _r,double _i){ r=_r; i=_i;}
	ttp operator+(ctp&a){return ttp(r+a.r,i+a.i);}
	ttp operator-(ctp&a){return ttp(r-a.r,i-a.i);}
	ttp operator*(ctp&a){return ttp(r*a.r-i*a.i,r*a.i+i*a.r);}
} ;
typedef Complex V;

template <class __Type>
inline void Rader (__Type a[],int len){
	int i,j=len>>1,k;
	for (i=1;i<len-1;i++){
		if(i<j)swap(a[i],a[j]); k=len;
		while(j>=(k>>=1)) j-=k;
		if(j<k)j+=k;
	}
}

inline void FFT(V a[],int len,int ty){
	Rader(a,len); int l,i,j,k; V u,t;
	for(l=2;l<=len;l<<=1){ i=l>>1;
		V wn(cos(-2*PI*ty/l),sin(-2*PI*ty/l));
		for(j=0;j<len;j+=l){
			V w(1.0,0.0);
			for(k=j;k<i+j;k++){
				u=a[k]; t=w*a[i+k];
				a[k]=u+t; a[i+k]=u-t;
				w=w*wn;
			}
		}
	}
	if(ty==-1){
		for(i=0;i<len;i++){
			a[i].r/=len;
		}
	}
}

void Self_Convol_FFT(V a[],int len){
	FFT(a,len,1); int i;
	rep(i,0,len) a[i]=a[i]*a[i];
	FFT(a,len,-1);
}

char s[N];
int l,len,power[N];
V a[3*N],b[3*N];

char str[2*N];
int rl[2*N];
int manacher(char*s,int l){
	const int n=2*l+1;
	int pos=0,rpos=0,sum=0,i;
	str[0]='@'; str[n+1]='$';
	for(i=1;i<=n;i++){
		if(i%2) str[i]='#';
		else str[i]=s[i>>1];
	} for(i=1;i<=n;i++){
		if(rpos>i) rl[i]=min(rl[2*pos-i],rpos-i); else rl[i]=1;
		while(str[i-rl[i]]==str[i+rl[i]]) rl[i]++;
		if(rl[i]+i>rpos) rpos=rl[i]+i,pos=i;
	} for(i=1;i<=n;i++) sum=(sum+(rl[i]>>1))%MOD;
	return sum;
}

void work(){ power[0]=1;
	for(int i=1;i<=l;i++){
		if(s[i]=='a') a[i].r=1.0;
		else if(s[i]=='b') b[i].r=1.0;
	} len=1; int ans=0;
	while((len>>1)<=l)len<<=1;
	for(int i=1;i<=len;i++){
		power[i]=(power[i-1]<<1)%MOD;
	} Self_Convol_FFT(a,len);
	Self_Convol_FFT(b,len);
	for(int i=1;i<=len;i++){
		int t1=(int)(a[i].r+.5),t2=(int)(b[i].r+.5);
		ans=(ans+power[(t1+t2+1)>>1]-1)%MOD;
	} int extra=manacher(s,l);
	printf("%d\n",(ans-extra+MOD)%MOD);
}

int main(){
	scanf("%s",s+1);
	l=strlen(s+1);
	work();
	return 0; 
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值