[bzoj3625] 小朋友和二叉树

[bzoj3625] 小朋友和二叉树


生成函数不难推出,给定的A,然后求F=F*F*A+1

然后要注意的是这里直接套公式然后求的话会在求逆的时候崩掉,然后具体处理方法就是把上面的除下来就行了。

最后的式子是:

\frac {2} {1+\sqrt {1-4C} }

  • 代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
typedef long long ll;

const int mod=998244353,g=3;
int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
int sub(int a,int b){a-=b;return a<0?a+mod:a;}
int mul(int a,int b){return (ll)a*b%mod;}
int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
/*math*/

namespace Template_Poly{
    typedef vector<int> Poly;
    int rev[N];
    Poly Poly_add(Poly A,Poly B){
        A.resize(max(A.size(),B.size()));
        for(size_t i=0;i<B.size();i++)A[i]=add(A[i],B[i]);
        return A;
    }
    Poly Poly_sub(Poly A,Poly B){
        A.resize(max(A.size(),B.size()));
        for(size_t i=0;i<B.size();i++)A[i]=sub(A[i],B[i]);
        return A;
    }
    void DFT(int *t,int n,int type){
        int l=0;while(1<<l<n)++l;
        for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
        for(int i=0;i<n;i++)if(rev[i]>i)swap(t[rev[i]],t[i]);
        for(int step=1;step<n;step<<=1){
            int wn=qpow(g,(mod-1)/(step<<1));
            for(int i=0;i<n;i+=step<<1){
                int w=1;
                for(int k=0;k<step;k++,w=mul(w,wn)){
                    int x=t[i+k],y=mul(t[i+k+step],w);
                    t[i+k]=add(x,y),t[i+k+step]=sub(x,y);
                }
            }
        }
        if(type==1)return;
        for(int i=1;i<n-i;i++)swap(t[i],t[n-i]);
        int inv=qpow(n,mod-2);
        for(int i=0;i<n;i++)t[i]=mul(t[i],inv);
    }
    Poly NTT(Poly A,int n,Poly B,int m){
        static Poly res,PolA,PolB;
        PolA=A,PolB=B;
        int len=1;while(len < n+m)len<<=1;
        res.resize(len);
        PolA.resize(len),PolB.resize(len);
        DFT(&PolA[0],len,1);DFT(&PolB[0],len,1);
        for(int i=0;i<len;i++) res[i]= mul(PolA[i],PolB[i]);
        DFT(&res[0],len,-1);
        res.resize(n+m-1);
        return res;
    }
    Poly NTT(Poly A,Poly B){
        return NTT(A,A.size(),B,B.size());
    }
    Poly Poly_inv(Poly A,int n){
        if(n==1)return Poly(1,qpow(A[0],mod-2));
        int len=1<<((int)ceil(log2(n))+1);
        Poly x=Poly_inv(A,(n+1)>>1),y;
        x.resize(len),y.resize(len);
        for(int i=0;i<n;i++)y[i]=A[i];
        DFT(&x[0],len,1),DFT(&y[0],len,1);
        for(int i=0;i<len;i++)x[i]=mul(x[i],sub(2,mul(x[i],y[i])));
        DFT(&x[0],len,-1);
        x.resize(n);
        return x;
    }
    Poly Poly_inv(Poly A){
        return Poly_inv(A,A.size());
    }
    Poly Deri(Poly A){
        int n=A.size();
        for(int i=1;i<n;i++)A[i-1]=mul(A[i],i);
        A.resize(n-1);
        return A;
    }

    Poly Inte(Poly A){
        int n=A.size();
        A.resize(n+1);
        for(int i=n;i;i--)A[i]=mul(A[i-1],qpow(i,mod-2));
        A[0]=0;
        return A;
    }

    Poly ln(Poly A){
        int len=A.size();
        A=Inte(NTT(Deri(A),Poly_inv(A)));
        A.resize(len);
        return A;
    }

    Poly exp(Poly A,int n){
        if(n==1)return Poly(1,1);
        Poly x=exp(A,(n+1)>>1),y;
        x.resize(n);
        y=ln(x);
        for(int i=0;i<n;i++)y[i]=sub(A[i],y[i]);
        y[0]++;
        x=NTT(x,y);
        x.resize(n);
        return x;
    }
    Poly exp(Poly A){
        return exp(A,A.size());
    }

    Poly sqrt(Poly A,int n){
        if(n==1)return Poly(1,1);
        Poly x=sqrt(A,(n+1)>>1),y;
        x.resize(n),y.resize(n);
        for(int i=0;i<n;i++)y[i]=A[i];
        x=Poly_add(NTT(Poly_inv(x),y),x);
        int inv2=qpow(2,mod-2);
        for(int i=0;i<n;i++)
            x[i]=mul(x[i],inv2);
        x.resize(n);
        return x;
    }
    Poly sqrt(Poly A){
        return sqrt(A,A.size());
    }
}
using namespace Template_Poly;
int n,m;
int a[N];
Poly T,A,B,M;
int main()
{
    scanf("%d%d",&n,&m);
    T.resize(m+1);A.resize(m+1);
    for(int i=1;i<=n;i++){scanf("%d",&a[i]);if(a[i]<=m)A[a[i]]++;}
    for(int i=0;i<=m;i++)T[i]=mul(4,sub(0,A[i]));
    T[0]=add(T[0],1);
    T=sqrt(T);
    T[0]=add(T[0],1);
    T=Poly_inv(T);
    for(int i=1;i<=m;i++)printf("%d\n",mul(T[i],2));
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值