【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]=\text {'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;
}

猜你喜欢

转载自www.cnblogs.com/Emiya-wjk/p/10030767.html