[bzoj3160]万径人踪灭

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/FZHvampire/article/details/51718924

3160: 万径人踪灭

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 856 Solved: 487
[Submit][Status][Discuss]
Description

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

最后的答案可以表示成所有的回文子串的个数减去连续的回文串的个数。
后面的那个显然可以用 manacher 。前面的那个东西可以这样求:
f[i] 表示以 i 这个字符为中心的回文子串的个数。
那么 f[i]=2ij=1(s[j]==s[2ij])
a,b 分别等于 0 1 ,式子就可以变成 f[i]=2ij=1s[j]s[2ij]
很明显这是一个卷积的形式,做两遍 FFT 就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define Mod 1000000007
const int M=400000;
char s[M],ch[M];
int n,rev[M],dig[M],N,L,f[M],Pow[M],ans,p[M];
struct S{
    double x,y;
    S operator + (const S &xx){return (S){x+xx.x,y+xx.y};}
    S operator - (const S &xx){return (S){x-xx.x,y-xx.y};}
    S operator * (const S &xx){return (S){x*xx.x-y*xx.y,x*xx.y+y*xx.x};}
}a[M],c[M],d[M];
inline void FFT(S *a,int f){
    int i,j,k;
    S w,wn,x,y;
    for(i=0;i<N;++i) d[i]=a[rev[i]];
    for(i=0;i<N;++i) a[i]=d[i];
    for(i=2;i<=N;i<<=1){
        wn=(S){cos(2*M_PI/i),f*sin(2*M_PI/i)};
        for(j=0;j<N;j+=i){
            w=(S){1,0};
            for(k=j;k<j+i/2;++k){
                x=a[k];
                y=w*a[k+i/2];
                a[k]=x+y;
                a[k+i/2]=x-y;
                w=w*wn;
            }
        }
    }
    if(f==-1) for(i=0;i<N;++i) a[i].x/=(double)N;
}
inline int manacher(){
    int maxn=1,id=1,sum=0,i;
    for(ch[0]='$',ch[1]='#',i=1;i<=n;++i)
        ch[i<<1]=s[i-1],ch[i<<1|1]='#';
    for(i=1;i<=(n<<1|1);++i){
        p[i]=min(maxn-i,p[id*2-i]);
        while(ch[i+p[i]]==ch[i-p[i]]) ++p[i];
        if(p[i]+i>maxn) maxn=p[i]+i,id=i;
        sum=(sum+p[i]/2)%Mod;
    }
    return sum;
}
int main(){
    int i,len,j;
    scanf("%s",s);
    n=strlen(s);
    for(L=0,N=1;N<n;N<<=1,L+=1); N<<=1;L+=1;
    for(i=0;i<N;++i){
        for(j=i,len=0;j;j>>=1) dig[len++]=j&1;
        for(j=0;j<L;++j) rev[i]=rev[i]*2+dig[j];
    }
    for(i=0;i<n;++i)
        if(s[i]=='a') a[i]=(S){1.,0.};
    FFT(a,1);
    for(i=0;i<N;++i) c[i]=a[i]*a[i];
    memset(a,0,sizeof(a));
    for(i=0;i<n;++i)
        if(s[i]=='b') a[i]=(S){1.,0.};
    FFT(a,1);
    for(i=0;i<N;++i) c[i]=c[i]+a[i]*a[i];
    FFT(c,-1);
    ans=Mod-manacher();
    for(Pow[0]=1,i=1;i<N;++i) Pow[i]=Pow[i-1]*2%Mod;
    for(i=0;i<N;++i){
        f[i]=(c[i].x+0.5);
        ans=(ans+Pow[(f[i]+1)>>1]-1)%Mod;
    }
    printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/FZHvampire/article/details/51718924