zoukankan      html  css  js  c++  java
  • 【BZOJ3160】【2013湖北互测week1】—万径人踪灭(FFT+Manacher)

    传送门

    题意:给定一个串,问有多少个满足位置对称的不连续回文子序列

    考虑计算出出所有位置对称的回文子序列和所有连续回文子串
    后者可以直接用ManacherManacher求出

    考虑前一部分怎么求

    对于每个对称轴的位置ii单独考虑
    发现和a,ba,b没有关系,只需要看s[ik]s[i-k]s[i+k]s[i+k]相等的个数就可以了
    k[s[i+k]==s[ik]]sum_{k}[s[i+k]==s[i-k]]
    考虑对于a,ba,b分别求出相等的个数再求和
    比如aa,令所有为aa的位置为11,否则为00
    那是ks[ik]s[i+k]sum_{k}s[i-k]*s[i+k]
    fftfft一下就可以了

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define re register
    inline int read(){
        char ch=getchar();
        int res=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
        return res*f;
    }
    const int N=100005;
    const int mod=1e9+7;
    const double pi=acos(-1);
    struct plx{
        double x,y;
        plx(double _x=0,double _y=0):x(_x),y(_y){}
        friend inline plx operator +(const plx &a,const plx &b){
            return plx(a.x+b.x,a.y+b.y);
        }
        friend inline plx operator -(const plx &a,const plx &b){
            return plx(a.x-b.x,a.y-b.y);
        }
        friend inline plx operator *(const plx &a,const plx &b){
            return plx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
        }
    }a[N<<2],b[N<<2];
    int rev[N<<2],lim=1,tim;
    inline void fft(plx *f,int kd){
        for(re int i=0;i<lim;i++)if(i<rev[i])swap(f[i],f[rev[i]]);
        for(re int mid=1;mid<lim;mid<<=1){
            plx now=plx(cos(pi/mid),kd*sin(pi/mid));
            for(re int i=0;i<lim;i+=(mid<<1)){
                plx w=plx(1,0);
                for(re int j=0;j<mid;j++,w=w*now){
                    plx a0=f[i+j],a1=w*f[i+j+mid];
                    f[i+j]=a0+a1,f[i+j+mid]=a0-a1;
                }
            }
        }
        if(kd==-1)for(re int i=0;i<lim;i++)f[i].x/=lim;
    }
    char now[N<<2],s[N];
    int n;
    ll pw[N],ans;
    int mx,mid,p[N<<2];
    inline void add(ll &a,int b){
        a=(a+b>=mod)?a+b-mod:a+b;
    }
    inline ll manacher(){
        int len=strlen(s);ll res=0;
        now[0]='!',now[1]='$',n=1;
        for(re int i=0;i<len;i++){
            now[++n]=s[i],now[++n]='$';
        }
        now[n+1]='@';
        mx=mid=1;
        for(re int i=1;i<=n;i++){
            if(i<mx)p[i]=min(mx-i,p[2*mid-i]);
            else p[i]=1;
            while(now[i-p[i]]==now[i+p[i]])p[i]++;
            if(mx<i+p[i])mx=i+p[i],mid=i;
            add(res,(p[i])/2);
        }return res;
    }
    int main(){
        scanf("%s",s);
        int len=strlen(s);
        for(re int i=0;i<len;i++){
            if(s[i]=='a')a[i].x=1;
            else b[i].x=1;
        }
        while(lim<=len*2)lim<<=1,tim++;
        for(re int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(tim-1));
        fft(a,1);
        fft(b,1);for(re int i=0;i<lim;i++) a[i]=a[i]*a[i],a[i]=a[i]+b[i]*b[i];
        fft(a,-1);
        pw[0]=1;for(re int i=1;i<=len;i++)pw[i]=pw[i-1]*2%mod;
        for(re int i=0;i<=2*len+2;i++){
            int k=(a[i].x+0.5);
            k=(k+1)/2;add(ans,pw[k]-1);
        }
        cout<<(ans-manacher()+mod)%mod<<'
    ';
    }
    
  • 相关阅读:
    原创frame-relay配置
    iptables详解和练习
    nfs-rpcbind-portmap挂载nfs-network file system
    linux-user-group添加与删除
    cgi-fastcgi-fpm
    lamp介绍
    子签CA以及给别人发CA
    正则表达式
    字符集和字符编码
    C++11新特性
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145600.html
Copyright © 2011-2022 走看看