• CF438E The Child and Binary Tree 题解


    CF438E The Child and Binary Tree

    本文版权归 Azazel 与博客园共有,欢迎转载,但需保留此声明,并给出原文地址,谢谢合作。

    原文地址:https://www.cnblogs.com/Azazel/p/15182481.html

    题意

    (~~~~) 给出 (n) 个权值 (c_i),求有多少棵二叉树,其所有的点权均在这些权值之中且点权和为 (Sin[1,m])。答案对 (998244353) 取模。

    (~~~~) (1leq n,m,c_ileq 10^5)

    题解

    (~~~~) 首先考虑 ( exttt{DP}),设 (f_{i}) 表示权值和为 (i) 且满足要求的二叉树的个数。并记 (g_{i}in[0,1]) 表示 (i) 是否是可行的点权之一。

    (~~~~) 先有初始值 (f_0=1) ,则可以推出下面这个式子:

    [large f_{i}=sum_{j=1}^ig_isum_{k=0}^{i-j}f_k imes f_{i-k-j} ]

    (~~~~) 然后不难发现把 (f)(g) 看作多项式后就是个卷积形式:

    [large f=g * f^2+1 ]

    (~~~~) 由于 (g) 已知,我们试图通过此来推一波 (f)

    [large g * f^2-f+1=0\ large f=dfrac{1 pm sqrt{1-4g}}{2g} ]

    (~~~~) 由于一些我不会推原因,(dfrac{1 + sqrt{1-4g}}{2g}) 会被舍去,所以只有 (dfrac{1 - sqrt{1-4g}}{2g}) 合法。

    (~~~~) 理论上可做了,但是我们发现 ([x^0]g(x)=0) ,不能求逆,所以我们进行一波分子有理化(或者叫分母无理化?):

    [dfrac{2}{1+sqrt{1-4g}} ]

    (~~~~) 然后多项式开根+求逆套上来即可卷出 (f)

    代码

    查看代码
    #include <cstdio>
    #include <cstring> 
    #include <algorithm>
    #define ll long long
    using namespace std;
    const ll MOD=998244353;
    ll To[5000005],N;
    ll qpow(ll a,ll b)
    {
    	ll ret=1;
    	while(b)
    	{
    		if(b&1) ret=ret*a%MOD;
    		b>>=1;a=a*a%MOD;
    	}
    	return ret;
    }
    const ll g=3,gi=qpow(g,MOD-2);
    const ll Inv2=qpow(2,MOD-2);
    inline ll Add(ll a,ll b){return ((a+b)%MOD+MOD)%MOD;}
    inline ll Mul(ll a,ll b){return a*b%MOD;}
    void NTT(ll *S,ll op)
    {
    	for(int i=0;i<N;i++) if(i<To[i]) swap(S[i],S[To[i]]);
    	for(int i=1;i<N;i<<=1)
    	{
    		ll W=qpow(op==1?g:gi,(MOD-1)/(i<<1));
    		for(int j=0;j<N;j+=i<<1)
    		{
    			ll w=1;
    			for(int k=0;k<i;k++,w=w*W%MOD)
    			{
    				ll x=S[j+k],y=Mul(S[i+j+k],w);
    				S[j+k]=Add(x,y);S[i+j+k]=Add(x,-y);
    			}
    		}
    	}
    	if(op==-1)
    	{
    		ll Inv=qpow(N,MOD-2);
    		for(int i=0;i<N;i++) S[i]=Mul(S[i],Inv);
    	}
    }
    ll C[5000005];
    void GetInv(int deg,ll *A,ll *B)
    {
    	if(deg==1){B[0]=qpow(A[0],MOD-2);return;}
    	GetInv((deg+1)>>1,A,B);
    	for(N=1;N<=(deg<<1);N<<=1);
    	for(int i=0;i<N;i++) To[i]=(To[i>>1]>>1)|((i&1)*(N>>1)),C[i]=A[i];
    	for(int i=deg;i<N;i++) C[i]=0;
    	NTT(C,1);NTT(B,1);
    	for(int i=0;i<N;i++) B[i]=Mul(Add(2ll,-Mul(C[i],B[i])),B[i]);
    	NTT(B,-1);
    	for(int i=deg;i<N;i++) B[i]=0;
    }
    ll inv[5000005],D[5000005];
    void GetSqrt(int deg,ll *A,ll *B)
    {
    	if(deg==1){B[0]=1;return;}
    	GetSqrt((deg+1)>>1,A,B);
    	for(N=1;N<=(deg<<1);N<<=1);
    	for(int i=0;i<N;i++) To[i]=(To[i>>1]>>1)|((i&1)*(N>>1)),D[i]=inv[i]=0;
    	for(int i=0;i<deg;i++) D[i]=A[i];
    	GetInv(deg,B,inv);
    	NTT(inv,1);NTT(D,1);NTT(B,1);
    	for(int i=0;i<N;i++) B[i]=Mul(Add(B[i],Mul(D[i],inv[i])),Inv2);
    	NTT(B,-1);
    	for(int i=deg;i<N;i++) B[i]=0;
    }
    template<typename T>void read(T &x)
    {
        T f=1;x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
        x*=f;
    }
    template<typename T>void print(T x) {
        if(x<0) putchar('-'),x=-x;
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    ll F[1000005],G[1000005],H[1000005];
    int main() {
    	int n,m;
    	scanf("%d %d",&n,&m);
    	for(int i=1,x;i<=n;i++)
    	{
    		scanf("%d",&x);
    		G[x]=1;
    	}
    	G[0]=1; for(int i=1;i<=m;i++) G[i]=(MOD-4*G[i]%MOD)%MOD;
    	GetSqrt(m+1,G,F);F[0]++;
    	GetInv(m+1,F,H);
    	for(int i=0;i<=m;i++) H[i]=H[i]*2%MOD;
    	for(int i=1;i<=m;i++) printf("%lld
    ",H[i]);
    	return 0;
    }
    
  • 相关阅读:
    myEclipse Debug
    C# DataTable的詳細使用方法
    算法 《秦九韶算法java实践》
    【闲聊产品】之五:谁来背黑锅?
    ubuntu install mysql server method
    H264解码的一个測试程序
    Struts2自己定义拦截器实例—登陆权限验证
    【剑指offer】二叉树的镜像
    ubuntu12.04下搭建ftpserver
    C++Vector使用方法
  • 原文地址:https://www.cnblogs.com/Azazel/p/15182481.html
Copyright © 2020-2023  润新知