zoukankan      html  css  js  c++  java
  • 【CF438E】小朋友和二叉树 解题报告

    【CF438E】小朋友和二叉树

    Description

    ​ 我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树。
    ​ 考虑一个含有(n)个互异正整数的序列(c_1,c_2,dots,c_n)。如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合({c_1,c_2,dots,c_n})中,我们的小朋友就会将其称作神犇的。并且他认为,一棵带点权的树的权值,是其所有顶点权值的总和。
    ​ 给出一个整数(m),你能对于任意的(s(1≤s≤m))计算出权值为(s)的神犇二叉树的个数吗?请参照样例以更好的理解什么样的两棵二叉树会被视为不同的。
    ​ 我们只需要知道答案关于(998244353)取模后的值。

    Input

    ​ 第一行有(2)个整数 (n,m(1≤n≤10^5,1≤m≤10^5)).
    ​ 第二行有(n)个用空格隔开的互异的整数 (c_1,c_2,…,c_n(1≤c[i]≤10^5)).

    Output

    ​ 输出(m)行,每行有一个整数。第(i)行应当含有权值恰为(i)的神犇二叉树的总数。请输出答案关于(998244353)取模后的结果。


    考虑(DP),设(f_i)代表权值为(i)的二叉树的个数,(C_i)代表是否存在权值为(i)的节点

    [f_n=sum_{i=1}^nC_isum_{j=0}^{n-i}f_jf_{n-i-j} ]

    [f_0=1 ]

    然后我们发现长得很像卷积,但是没法好好卷自己。

    于是构造一波生成函数,直接表示为系数就行了

    [F=C*F*F+1 ]

    关于这个(+1),我的理解是,加了一个常数项为(1)的多项式表示(f_0=1)

    然后解一下二次方程,得到

    [F=frac{1 pm sqrt{1-4C}}{2C} ]

    然后讨论一下发现需要取+

    再次化简

    [F=frac{2}{1+sqrt{1-4C}} ]

    套用多项式求逆+开根就可以了


    Code:

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    const int N=(1<<20)+10;
    const int mod=998244353,Gi=332748118,i2=499122177;
    int read()
    {
        int x=0;char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) {x=x*10+c-'0';c=getchar();}
        return x;
    }
    #define add(x,y) ((x+y)%mod)
    #define mul(x,y) (1ll*(x)*(y)%mod)
    int qp(int d,int k){int f=1;while(k){if(k&1)f=mul(f,d);d=mul(d,d),k>>=1;}return f;}
    int C[N],sq[2][N],b[2][N],A[N],B[N],turn[N];
    void NTT(int *a,int len,int typ)
    {
        for(int i=1;i<len;i++) if(i<turn[i]) std::swap(a[i],a[turn[i]]);
        for(int le=1;le<len;le<<=1)
        {
            int wn=qp(typ?3:Gi,(mod-1)/(le<<1));
            for(int p=0;p<len;p+=le<<1)
            {
                int w=1;
                for(int i=p;i<p+le;i++,w=mul(w,wn))
                {
                    int tx=a[i],ty=mul(w,a[i+le]);
                    a[i]=add(tx,ty);
                    a[i+le]=add(tx,mod-ty);
                }
            }
        }
        if(!typ)
        {
            int inv=qp(len,mod-2);
            for(int i=0;i<len;i++) a[i]=mul(a[i],inv);
        }
    }
    void polymul(int *a,int *b,int len)
    {
        int L=-1;for(int i=1;i<len;i<<=1) ++L;
        for(int i=0;i<len;i++) turn[i]=turn[i>>1]>>1|(i&1)<<L,A[i]=B[i]=0;
        for(int i=0;i<len>>1;i++) A[i]=a[i],B[i]=b[i];
        NTT(A,len,1),NTT(B,len,1);
        for(int i=0;i<len;i++) A[i]=mul(A[i],B[i]);
        NTT(A,len,0);
        for(int i=0;i<len;i++) a[i]=A[i];
    }
    void polyinv(int *a,int n)
    {
        int len=2,cur=0;
        b[cur][0]=qp(a[0],mod-2);
        while(len<=(n<<2))
        {
            cur^=1;
            for(int i=0;i<len>>1;i++) b[cur][i]=add(b[cur^1][i],b[cur^1][i]);
            polymul(b[cur^1],b[cur^1],len);
            polymul(b[cur^1],a,len);
            for(int i=0;i<len;i++) b[cur][i]=add(b[cur][i],mod-b[cur^1][i]);
            len<<=1;
        }
        for(int i=0;i<n;i++) a[i]=b[cur][i];
    }
    void polysqrt(int *a,int n)
    {
        int len=2,cur=0;
        sq[cur][0]=1;
        while(len<=(n<<2))
        {
            cur^=1;
            for(int i=0;i<len>>1;i++) sq[cur][i]=mul(sq[cur^1][i],i2);
            for(int i=0;i<len>>1;i++) sq[cur^1][i]=add(sq[cur^1][i],sq[cur^1][i]);
            polyinv(sq[cur^1],len);
            polymul(sq[cur^1],a,len);
            for(int i=0;i<len;i++) sq[cur][i]=add(sq[cur][i],sq[cur^1][i]);
            len<<=1;
        }
        for(int i=0;i<n;i++) a[i]=sq[cur][i];
    }
    int main()
    {
        int n=read(),m=read();
        for(int i=1;i<=n;i++) C[read()]=1;
        ++m;C[0]=1;
        for(int i=1;i<m;i++) C[i]=(mod-(C[i]<<2))%mod;
        polysqrt(C,m);
        C[0]=add(C[0],1);
        polyinv(C,m);
        for(int i=0;i<m;i++) C[i]=add(C[i],C[i]);
        for(int i=1;i<m;i++) printf("%d
    ",C[i]);
        return 0;
    }
    

    2018.12.17

  • 相关阅读:
    cve-2015-1635 poc
    Python实现ORM
    Android完全退出应用的方法
    Java反射理解
    Android动画
    Android进程间通信IPC
    Java的四种引用方式
    Android底部菜单的实现
    Android中AsyncTask使用
    Android自定义控件
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10132094.html
Copyright © 2011-2022 走看看