• bzoj3160(FFT+回文自动机)


    题目描述

    https://www.lydsy.com/JudgeOnline/problem.php?id=3160

    题解

    先把问题转化一下,我们要求的是非连续对称回文子序列。

    ans=回文子序列数-回文子串数。

    回文子串数可以用PAM或manachar求出来。

    复习了一下PAM,用它求回文子串数和SAM一样,就是size[fa[i]]+=size[i],这时每一个节点代表的是所有它的后缀回文串。

    然后怎么求回文子序列数。

    考虑每一条对称轴,它能被谁贡献。

    f[(i+j)/2]可以被i和j更新,当i和j是一种字符时。然后我们把前面的/2去掉,然后这个可以用卷积做。

    最后我们发现对于一对字符会被统计两次,但是对于对称中心的字符只会被统计一次,所以我们/2时要向下取整。

    坑点:PAM的size

        last=ch[last][s[i]-'a'];size[last]++;

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define N 100009
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    const double pai=acos(-1.0);
    ll ans;
    int len[N],cnt,last,fail[N],ch[N][2],size[N];
    int L,l,n,rev[N<<2];
    char s[N];
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    inline int power(ll x,int y){
        ll ans=1;
        while(y){
            if(y&1)ans=(ans*x)%mod;
            x=(x*x)%mod;
            y>>=1;
        }
        return ans;
    }
    struct fs{
        double x,y;
        fs(){}
        fs(double xx,double yy){x=xx;y=yy;}
        fs operator +(const fs &b)const{return fs{x+b.x,y+b.y};}
        fs operator -(const fs &b)const{return fs{x-b.x,y-b.y};}
        fs operator *(const fs &b)const{return fs{x*b.x-y*b.y,x*b.y+y*b.x};}
    }a[N<<2],b[N<<2];
    inline void FFT(fs *a,int tag){
        for(int i=0;i<l;++i)if(rev[i]>i)swap(a[i],a[rev[i]]);
        for(int i=1;i<l;i<<=1){
            fs wn(cos(pai/i),tag*sin(pai/i));
            for(int j=0;j<l;j+=(i<<1)){
                fs w(1,0);
                for(int k=0;k<i;++k,w=w*wn){
                    fs x=a[j+k],y=w*a[k+i+j];
                    a[j+k]=x+y;a[i+j+k]=x-y;
                }
            }
        }
    }
    int main(){
        scanf("%s",s+1);n=strlen(s+1);
        l=1;L=0;while(l<=(n<<1))l<<=1,++L;
        for(int i=0;i<l;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
        for(int i=1;i<=n;++i)if(s[i]=='a')a[i].x=1;else b[i].x=1;
        FFT(a,1);FFT(b,1);
        for(int i=0;i<l;++i)a[i]=a[i]*a[i]+b[i]*b[i];FFT(a,-1);
        for(int i=0;i<l;++i)a[i].x=(int)(a[i].x/l+0.1);
        for(int i=0;i<l;++i)ans=(ans+power(2,ceil((double)a[i].x/2))-1)%mod;
        cnt=last=1;len[1]=-1;fail[0]=1;
        for(int i=1;i<=n;++i){
            while(s[i-len[last]-1]!=s[i])last=fail[last];
            if(!ch[last][s[i]-'a']){
                len[++cnt]=len[last]+2;
                int y=fail[last];
                while(s[i-len[y]-1]!=s[i])y=fail[y];
                fail[cnt]=ch[y][s[i]-'a'];ch[last][s[i]-'a']=cnt;
            }
            last=ch[last][s[i]-'a'];size[last]++;
        }
        for(int i=cnt;i;--i)(size[fail[i]]+=size[i])%=mod;
        for(int i=2;i<=cnt;++i)ans=(ans-size[i]+mod)%mod;
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    Linux常用命令之 查找命令 find —— 细说 -atime,-mtime,-ctime
    centos设置静态ip
    Linux中vim的基本操作
    Linux中/和~的区别
    Linux安装vmtools工具
    关于 [lambda x: x*i for i in range(4)] 理解
    Ubuntu虚拟环境的搭建
    tomcat的中的Apache的apr是个啥东东???
    什么是web资源????
    Handlebars学习第一天
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10205723.html
Copyright © 2020-2023  润新知