zoukankan      html  css  js  c++  java
  • 题解 小朋友和二叉树

    题目传送门

    题目大意

    给出集合(S={c_1,c_2,c_3,..,c_m}),求出对于任意(tin[1,m])有多少个二叉树满足所有顶点的权值都在(S)中且权值之和为(t)

    思路

    我们设(F)为答案的生成函数,(G)为集合(S)的生成函数。可以得到:

    [F=F^2G+1 ]

    (F^2)就是枚举左右儿子,(G)就是根节点,加(1)是因为可以是空子树。

    得到:

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

    因为如果取正号的话,当(G=0)为零时为正无穷而取负号的话可以用洛必达法则求出来,所以取负号。我们再化简得到:

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

    于是,我们就在(Theta(mlog m))的时间复杂度内解决了这个问题。

    ( ext {Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define inv2 499122177
    #define ll long long
    #define mod 998244353
    #define MAXN 400005
    #define Gi 3
    
    int quick_pow (int a,int b){
    	int res = 1;for (;b;b >>= 1,a = 1ll * a * a % mod) if (b & 1) res = 1ll * res * a % mod;
    	return res; 
    }
    
    int limit = 1,l,r[MAXN];
    
    void NTT (int *a,int type){
    	for (Int i = 0;i < limit;++ i) if (i < r[i]) swap (a[i],a[r[i]]);
    	for (Int mid = 1;mid < limit;mid <<= 1){
    		int Wn = quick_pow (Gi,(mod - 1) / (mid << 1));
    		if (type == -1) Wn = quick_pow (Wn,mod - 2);
    		for (Int R = mid << 1,j = 0;j < limit;j += R){
    			for (Int k = 0,w = 1;k < mid;++ k,w = 1ll * w * Wn % mod)
    			{
    				int x = a[j + k],y = 1ll * w * a[j + k + mid] % mod;
    				a[j + k] = (x + y) % mod,a[j + k + mid] = (x + mod - y) % mod;
    			}
    		}
    	} 
    	if (type == 1) return ;
    	int Inv = quick_pow (limit,mod - 2);
    	for (Int i = 0;i < limit;++ i) a[i] = 1ll * a[i] * Inv % mod;
    }
    
    int c[MAXN];
    
    void Solve (int len,int *a,int *b){
    	if (len == 1) return b[0] = quick_pow (a[0],mod - 2),void ();
    	Solve ((len + 1) >> 1,a,b);
    	limit = 1,l = 0;
    	while (limit < (len << 1)) limit <<= 1,l ++;
    	for (Int i = 0;i < limit;++ i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
    	for (Int i = 0;i < len;++ i) c[i] = a[i];
    	for (Int i = len;i < limit;++ i) c[i] = 0;
    	NTT (c,1);NTT (b,1);
    	for (Int i = 0;i < limit;++ i) b[i] = 1ll * b[i] * (2 + mod - 1ll * c[i] * b[i] % mod) % mod;
    	NTT (b,-1);
    	for (Int i = len;i < limit;++ i) b[i] = 0;
    }
    
    int C[MAXN],D[MAXN];
    
    void Sqrt (int *a,int *b,int n){
    	if (n == 1) return b[0] = a[0],void ();
    	Sqrt (a,b,n >> 1);
    	for (Int i = 0;i < n;++ i) C[i] = a[i];
    	Solve (n,b,D);
    	NTT (C,1);NTT (D,1);
    	for (Int i = 0;i < limit;++ i) D[i] = 1ll * D[i] * C[i] % mod;
    	NTT (D,-1);
    	for (Int i = 0;i < limit;++ i) b[i] = 1ll * (b[i] + D[i]) % mod * inv2 % mod,C[i] = D[i] = 0; 
    }
    
    int read (){
    	int x = 0;char c = getchar();int f = 1;
    	while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}
    	while (c >= '0' && c <= '9'){x = (x << 3) + (x << 1) + c - '0';c = getchar();}
    	return x * f;
    }
    
    void write (int x){
    	if (x < 0){x = -x;putchar ('-');}
    	if (x > 9) write (x / 10);
    	putchar (x % 10 + '0');
    }
    
    int n,m,G[MAXN],F[MAXN],T[MAXN];
    
    signed main(){
    	n = read (),m = read ();
    	for (Int i = 1,w;i <= n;++ i){
    		w = read ();
    		if (w <= m) F[w] ++;
    	}
    	while (limit <= m) limit <<= 1,l ++;
    	for (Int i = 0;i < limit;++ i) F[i] = (i == 0) ? 1 + mod - 4 * F[i] : mod - 4 * F[i];
    	Sqrt (F,T,limit),T[0] ++,Solve (limit,T,G);
    	for (Int i = 1;i <= m;++i) write (2 * G[i] % mod),putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    简单介绍三层架构
    Java字符串常量池是什么?为什么要有这种常量池?
    java中String、StringBuffer和StringBuilder的区别(简单介绍)
    java中equals以及==的用法(简单介绍)
    关于java中Exception异常
    职场沟通,别光靠嘴
    小目标 | DAX高级实践-Power BI与Excel联合应用
    本号讯 | 微软和百度携手推进全球自动驾驶技术; 微软发布新一代可垂直可水平滚动的Arc鼠标
    你有一枚私人同声传译员待领取
    有了这套物联网节水平台,他决定回去继续管理农场
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13288949.html
Copyright © 2011-2022 走看看