zoukankan      html  css  js  c++  java
  • [BZOJ3160] 万径人踪灭

    [BZOJ3160] 万径人踪灭


    试题分析

    由于正向求是否有断开的不好求左右匹配数,那么我们换一个角度:回文串总数-连续情况
    显然,连续情况manacher一下就是(sum_{i=1}^{2n} p_i),其中(2n)是因为还有偶长度的回文串,需要添加特殊字符。
    然后求总数就是(sum(2^{f_i}-1))
    其中(f_i)为以i位置为对称轴匹配字符的个数。-1是空集情况。
    这个可以直接FFT求,a,b分开计算,计算a的时候将ch[i]==a的位置赋为1,然后FFT就可以得出f。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<cmath>
    #include<algorithm>
     
    using namespace std;
    #define LL long long
    #define Pi 3.1415926535
    const LL Mod = 1e9+7;
     
    inline LL read(){
        LL x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const LL MAXN = 4e5+5;
    const LL INF = 2147483600;
     
    char str2[MAXN+1],str[MAXN+1]; LL N;
    LL Len[MAXN+1],f[MAXN+1];
     
    LL lim=1,l,r[MAXN+1];
    struct cpx{
        double a,b;
        cpx (double aa=0,double bb=0){a=aa,b=bb;}
    }a[MAXN+1],b[MAXN+1];
    cpx operator + (cpx a,cpx b){return cpx(a.a+b.a,a.b+b.b);}
    cpx operator - (cpx a,cpx b){return cpx(a.a-b.a,a.b-b.b);}
    cpx operator * (cpx a,cpx b){return cpx(a.a*b.a - a.b*b.b , a.a*b.b + a.b*b.a);}
    LL M; LL rev[MAXN+1];
     
    inline void FFT(cpx *A,LL type){
        for(LL i=0;i<lim;i++) if(rev[i]>i) swap(A[rev[i]],A[i]);
        for(LL mid=1;mid<lim;mid<<=1){
            cpx Wn( 1.0*cos(Pi/mid) , 1.0*type*sin(Pi/mid) );
            for(LL R=(mid<<1),j=0;j<lim;j+=R){
                cpx w(1,0);
                for(LL k=0;k<mid;k++,w=w*Wn){
                    cpx x = A[j+k] , y = w*A[j+k+mid];
                    A[j+k] = x + y; A[j+k+mid] = x - y;
                }
            }
        } return ;
    }
    inline void work(char ch){
        for(LL i=0;i<lim;i++) a[i]=cpx(str[i]==ch,0),cout<<a[i].a<<" "; cout<<endl;
        FFT(a,1); for(LL i=0;i<lim;i++) a[i]=a[i]*a[i]; FFT(a,-1);
        for(LL i=1;i<=2*N;i++) f[i]+=((LL)(a[i].a*1.0/lim+0.5)+1)/2,cout<<((LL)(a[i].a*1.0/lim+0.5)+1)/2<<" ";
        for(LL i=1;i<=2*N;i++) cout<<a[i].a<<" "; cout<<endl;
        cout<<endl;
    }
    LL Pw[MAXN+1];
     
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        scanf("%s",str2+1); N=strlen(str2+1);
        LL Mx=-INF,pos=0; Pw[0]=1;
        for(LL i=1;i<=N;i++) str[i]=str2[i]; 
        for(LL i=1;i<=N;i++) Pw[i]=Pw[i-1]*2LL%Mod;
        while(lim<=2*N) lim<<=1,++l;
         
        LL ans=0; puts(str+1);
        for(LL i=0;i<lim;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
        work('a'); work('b');
        for(LL i=1;i<=2*N;i++) ans=(ans+Pw[f[i]]-1)%Mod,cout<<f[i]<<" ";
    	cout<<endl; 
         
        str[0]='%'; str[2*N+1]='#'; 
        for(LL i=1;i<=N;i++) str[2*i]=str2[i],str[2*i-1]='#';
        for(LL i=1;i<=2*N;i++){
            if(Mx>i) Len[i]=min(Mx-i,Len[2*pos-i]); else Len[i]=1; 
            while(Len[i]<i&&str[i+Len[i]]==str[i-Len[i]]) ++Len[i];
            if(i+Len[i]>Mx) pos=i,Mx=i+Len[i];
        }
        for(LL i=1;i<=2*N;i++) ans=(ans-Len[i]/2+Mod)%Mod;
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    扫雷游戏:C++生成一个扫雷底板
    为《信息学奥赛一本通》平反(除了OJ很差和代码用宋体)
    关于最大公约数欧几里得算法辗转相除及最小公倍数算法拓展C++学习记录
    【Python】如何用较快速度用Python程序增加博客访问量——CSDN、博客园、知乎(应该包括简书)
    STL学习笔记之next_permutation函数
    C++集合容器STL结构Set
    11111111111
    express + mysql实践
    express实践
    ws:一个 Node.js WebSocket 库
  • 原文地址:https://www.cnblogs.com/wxjor/p/9570369.html
Copyright © 2011-2022 走看看