CodeForces 438E The Child and Binary Tree(DP + 生成函数 + 多项式模运算)

CodeForces 438E The Child and Binary Tree(DP + 生成函数 + 多项式模运算)_第1张图片

CodeForces 438E The Child and Binary Tree(DP + 生成函数 + 多项式模运算)_第2张图片

 

 

大致题意:给定一个集合{Cn},一棵二叉树上的所有节点的点权值从这个集合中选取。现在给定一个m,问对于1..m中的每一个数字i,权值和恰好为i的不同的二叉树的个数有多少个。这里形态不同但点权集合的二叉树视为两种方案。

与前面做的题目类似,这种题目我们还是用dp的思维去考虑。令fi表示权值和为i的二叉树的个数。那么考虑增加一个点x,这个点的权值可以取i,Ci表示数值i在初始给定集合中是否出现过,两个儿子对应子树的点权值和为fj和fk,那么这样的话就会对点权和为ci*(fj+fk)的方案数产生贡献。于是我们可以写出状态转移方程:

                                                      \large f_x=\sum_{i=1}^{x}C_i\sum_{j=0}^{x-i}f_j*f_{x-i-j}

现在我们考虑这个式子。这是一个卷积套卷积的式子,直接去做的话是完成不了的。但是根据式子,我们表示成生成函数的形式,大致可以推出:

                                                                  \large f=f^2*C

然后根据C[0]=0,f[0]=1,可以完善,得到:

                                                            

我们需要求f,于是把f当作位置数,这个就是一个一元二次方程。可以解得这个方程的根是:

                                                            \large f=\frac{1\pm \sqrt{1-4C}}{2}

进行分子有理化得:

                                                           \large f=\frac{2}{1\mp \sqrt{1-4C}}

考虑到当取0的时候,f=1,C=0,如果取减号,那么分母为0无意义,所有这里只能取加号。

                                                           \large f=\frac{2}{1 + \sqrt{1-4C}}

NTT加多项式开根再求逆元即可。具体见代码:

#include 
#define LL long long
using namespace std;

const int mod = 998244353;//(119 << 23) + 1;
const int modinv2 = (mod+1)/2; // 1/2 in F_p
const int G = 3;
const int N = 270010;

int c[N];

//取模加减乘
inline int add(int a,int b) {return a+b>=mod?a+b-mod:a+b;}
inline void inc(int&a,int b) {if ((a+=b)>=mod) a-=mod;}
inline int sub(int a,int b) {return a-b<0?a-b+mod:a-b;}
inline void dec(int&a,int b) {if ((a-=b)<0) a+=mod;}
inline int mul(int a,int b) {return (LL)a*b%mod;}
inline int qpow(int x,int n) {int ans=1;for (;n;n>>=1,x=(LL)x*x%mod) if (n&1) ans=(LL)ans*x%mod; return ans;}//quick power
//-------------------------------NTT--------------------------------
int wn[30],iwn[30]; //wn[i] = G^((P-1)/(2^i)) (mod P), iwn[i] = wn[i]^(-1) (mod P)
inline void init() //do this before NTT
{
    wn[23] = qpow(G,(mod-1)/(1<<23));
    for (int i=22;i>=0;i--) wn[i] = mul(wn[i+1],wn[i+1]);
    iwn[23] = qpow(wn[23],(1<<23)-1);
    for (int i=22;i>=0;i--) iwn[i] = mul(iwn[i+1],iwn[i+1]);
}
inline void revbin_permute(int a[],int n) {
    int i=1, j=n>>1, k;
    for (;i>1;j>=k;) {j -= k; k >>= 1;}
        if (j < k) j += k;
    }
}

inline void NTT(int *f,int ldn,int is) {
    int n = (1<>1);
        int dw = is>0?wn[ldm]:iwn[ldm], w = 1;
        for (int j=0;j=0;i--) if (n&(1<=0;i--) if (n&(1<

 

你可能感兴趣的:(---------Online,Judge--------,CodeForces,数论,FFT/NTT/FWT,组合计数,母函数)