zoukankan      html  css  js  c++  java
  • BZOJ 3160 万径人踪灭

    Em 很长很长很啰嗦的题目

    大意就是给定一个字符串,求有多少子序列关于某条对称轴对称,且子序列不连续

    首先我们不考虑不连续这个限制

    那么对于任意对称轴我们只需要求出关于该对称轴对称的字符有多少个

    设其为C[i]个,那么这条对称轴产生的贡献是2^C[i]-1

    容易发现对称的实质是对于任意点i 存在A[i-n]=A[i+n] (这样说并不严谨,意会。。

    注意到i-n+i+n=2*i,是个卷积形式

    那么我们设‘b'=1,’a'=0,做一遍FFT

    之后再设‘b'=0,’a'=1,再做一遍FFT

    那么C[i]就计算出来了

    至于不连续的这个限制,我们只需要用总方案-连续的即可

    连续的就是求有多少个回文子串了

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    typedef long long LL;
    const int maxn=400010;
    const int mod=1000000007;
    const double pi=acos(-1.0);
    int n;
    int Num[32],cur,N,L;
    int ch[maxn],tot,len,la;
    int C[maxn],end[maxn];
    int rev[maxn];
    char s[maxn];
    LL ans;
    struct Node{
        int len,fa,next[2];
    }t[maxn];
    struct cpx{
        double r,i;
        cpx(double r=0,double i=0):r(r),i(i){}
    }A[maxn],tmp[maxn],x,y;
    cpx operator +(const cpx &a,const cpx &b){return cpx(a.r+b.r,a.i+b.i);}
    cpx operator -(const cpx &a,const cpx &b){return cpx(a.r-b.r,a.i-b.i);}
    cpx operator *(const cpx &a,const cpx &b){return cpx(a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r);}
    void init(){
        ch[0]=-1;len=la=0;tot=1;
        t[0].fa=t[1].fa=1;
        t[0].len=0;t[1].len=-1;
        for(N=1;N<n;N<<=1,L++);N<<=1,L++;
        for(int i=0;i<N;++i){
            cur=0;
            for(int t=i;t;t>>=1)Num[++cur]=(t&1);
            for(int j=1;j<=L;++j)rev[i]=(rev[i]<<1)+Num[j];
        }return;
    }
    int Get_fa(int x){
        while(ch[len-t[x].len-1]!=ch[len])x=t[x].fa;
        return x;
    }
    void add(int c){
        ch[++len]=c;
        int tmp=Get_fa(la);
        if(!t[tmp].next[c]){
            ++tot;
            t[tot].len=t[tmp].len+2;
            t[tot].fa=t[Get_fa(t[tmp].fa)].next[c];
            t[tmp].next[c]=tot;
            //cout<<tot<<' '<<t[tot].fa<<endl;
            //system("pause");
        }la=t[tmp].next[c];end[la]++;
    }
    void Get_PAM(){
        for(int i=0;i<n;++i)add(s[i]-'a');
        for(int i=tot;i>=1;--i){
            end[t[i].fa]+=end[i];
            ans=ans-end[i];
        }ans%=mod;return;
    }
    LL pow_mod(LL v,LL p){
        LL tmp=1;
        while(p){
            if(p&1)tmp=tmp*v%mod;
            v=v*v%mod;p>>=1;
        }return tmp;
    }
    void FFT(cpx *A,int n,int type){
        for(int i=0;i<n;++i)tmp[i]=A[rev[i]];
        for(int i=0;i<n;++i)A[i]=tmp[i];
        for(int i=2;i<=n;i<<=1){
            cpx wn(cos(2*pi/i),sin(2*pi/i)*type);
            for(int j=0;j<n;j+=i){
                cpx w(1,0);
                for(int k=0;k<(i>>1);k++){
                    x=A[k+j];y=A[k+j+(i>>1)]*w;
                    A[k+j]=x+y;A[k+j+(i>>1)]=x-y;
                    w=w*wn;
                }
            }
        }
        if(type==-1)for(int i=0;i<n;++i)A[i].r/=n;
    }
    void Get_ans(char c){
        for(int i=0;i<N;++i)A[i]=cpx();
        for(int i=0;i<n;++i)if(s[i]==c)A[i].r=1.0;
        FFT(A,N,1);
        for(int i=0;i<N;++i)A[i]=A[i]*A[i];
        FFT(A,N,-1);
        for(int i=0;i<N;++i)C[i]=C[i]+(int)(A[i].r+0.5);
    }
    int main(){
        scanf("%s",s);
        n=strlen(s);
        init();Get_PAM();
        //cout<<"-1"<<endl;
        Get_ans('a');Get_ans('b');
        for(int i=0;i<N;++i){
            ans=ans+pow_mod(2LL,(C[i]+1)>>1)-1;
            ans%=mod;
        }
        printf("%lld
    ",(ans+mod)%mod);
        return 0;
    }
    万径人踪灭
  • 相关阅读:
    bzoj3505 数三角形 组合计数
    cogs2057 殉国 扩展欧几里得
    cogs333 荒岛野人 扩展欧几里得
    bzoj1123 BLO tarjan求点双连通分量
    poj3352 road construction tarjan求双连通分量
    cogs1804 联合权值 dp
    cogs2478 简单的最近公共祖先 树形dp
    cogs1493 递推关系 矩阵
    cogs2557 天天爱跑步 LCA
    hdu4738 Caocao's Bridge Tarjan求割边
  • 原文地址:https://www.cnblogs.com/joyouth/p/5333139.html
Copyright © 2011-2022 走看看