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;
    }
    万径人踪灭
  • 相关阅读:
    如何在ubuntu里面使用JNI?
    sql server 关键字一
    自己编写的 objectDataSource 配合 GridView 实现分页...
    委托和匿名委托的比较
    实现 IEnumerable IEnumator 接口的类,可直接用作 Gridivew 的数据源
    ASP.NET 中的页面事件执行顺序
    泛型,集合的根本区别
    匿名委托的示例,贴一下以供参考...
    ajax "Sys 未定义" 的问题解决方法
    抽象工厂模式(C#)
  • 原文地址:https://www.cnblogs.com/joyouth/p/5333139.html
Copyright © 2011-2022 走看看