1. 程式人生 > >BZOJ3625: 小朋友和二叉樹

BZOJ3625: 小朋友和二叉樹

傳送門

Sol

f x f_x 表示權值為 x x 的二叉樹的個數
s

x s_x 表示是否有 x x 這種權值可以選擇
那麼
f n
= i = 0 n
j = 0 n i
f j f n i j s i f_n=\sum_{i=0}^{n}\sum_{j=0}^{n-i}f_jf_{n-i-j}s_i

構造
F ( x ) = i = 0 f i x i F(x)=\sum_{i=0}f_ix^i
S ( x ) = i = 0 s i x i S(x)=\sum_{i=0}s_ix^i
由於 s 0 = 0 , f 0 = 1 s_0=0,f_0=1
那麼
F 2 ( x ) S ( x ) = F ( x ) 1 F^2(x)S(x)=F(x)-1
所以可以求得
F ( x ) = 1 ± 1 4 S ( x ) 2 S ( x ) F(x)=\frac{1\pm \sqrt{1-4S(x)}}{2S(x)}
由於 F ( 0 ) = 1 , S ( 0 ) = 0 F(0)=1,S(0)=0 所以
F ( x ) = 1 1 4 S ( x ) 2 S ( x ) F(x)=\frac{1- \sqrt{1-4S(x)}}{2S(x)}
正是因為 S ( 0 ) = 0 S(0)=0 沒有辦法求逆
所以化簡得到
F ( x ) = 2 1 + 1 4 S ( x ) F(x)=\frac{2}{1+ \sqrt{1-4S(x)}}
開根(常數項是 1 1 所以不用二次剩餘)+求逆即可

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn(4e5 + 5);
const int mod(998244353);
const int inv2(499122177);

inline int Pow(ll x, int y) {
    register ll ret = 1;
    for (; y; y >>= 1, x = x * x % mod)
        if (y & 1) ret = ret * x % mod;
    return ret;
}

inline void Inc(int &x, int y) {
    if ((x += y) >= mod) x -= mod;
}

int a[maxn], b[maxn], c[maxn], w[2][maxn], deg, r[maxn], l;

inline void Init(int n) {
	register int i, k, wn, iwn;
	for (deg = 1, l = 0; deg < n; deg <<= 1) ++l;
	for (i = 0; i < deg; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
	for (i = 1; i < deg; i <<= 1) {
		w[0][0] = w[1][0] = 1;
		wn = Pow(3, (mod - 1) / (i << 1)), iwn = Pow(wn, mod - 2);
		for (k = 1; k < i; ++k) {
			w[0][deg / i * k] = 1LL * w[0][deg / i * (k - 1)] * wn % mod;
			w[1][deg / i * k] = 1LL * w[1][deg / i * (k - 1)] * iwn % mod;
		}
	}
}

inline void NTT(int *p, int opt) {
	register int i, j, k, t, wn, x, y;
	for (i = 0; i < deg; ++i) if (r[i] < i) swap(p[r[i]], p[i]);
	for (i = 1; i < deg; i <<= 1)
		for(t = i << 1, j = 0; j < deg; j += t)
			for (k = 0; k < i; ++k) {
				wn = w[opt == -1][deg / i * k];
				x = p[j + k], y = 1LL * wn * p[i + j + k] % mod;
				p[j + k] = x + y, p[i + j + k] = x - y;
				if (p[j + k] >= mod) p[j + k] -= mod;
				if (p[i + j + k] < 0) p[i + j + k] += mod;
			}
	if (opt == -1) {
		wn = Pow(deg, mod - 2);
		for (i = 0; i < deg; ++i) p[i] = 1LL * p[i] * wn % mod;
	}
}

int n, m, f[maxn], g[maxn], s[maxn];

void Inv(int *p, int *q, int len) {
	if (len == 1) {
		q[0] = Pow(p[0], mod - 2);
		return;
	}
	Inv(p, q, len >> 1);
	register int i, tmp = len << 1;
	for (i = 0; i < len; ++i) a[i] = p[i], b[i] = q[i];
	Init(tmp), NTT(a, 1), NTT(b, 1);
	for (i = 0; i < tmp; ++i) a[i] = 1LL * a[i] * b[i] % mod * b[i] % mod;
	NTT(a, -1);
	for (i = 0; i < len; ++i) q[i] = (2LL * q[i] + mod - a[i]) % mod;
	for (i = 0; i < tmp; ++i) a[i] = b[i] = 0;
}

void Sqrt(int *p, int *q, int len) {
    if (len == 1) {
        q[0] = sqrt(p[0]);
        return;
    }
    Sqrt(p, q, len >> 1), Inv(q, c, len);   
    register int i, tmp = len << 1;
    
            
           

相關推薦

BZOJ3625: 小朋友

傳送門 Sol 設 f x f_

[bzoj3625][Codeforces Round #250]小朋友

math init std isp 二叉樹 表示 scrip fine c中 [bzoj3625][Codeforces Round #250]小朋友和二叉樹

BZOJ3625 [Codeforces Round #250]小朋友

using name 技術分享 const ++ 二叉 amp inverse gpo BZOJ3625 http://www.lydsy.com/JudgeOnline/problem.php?id=3625 #include<cstdio>

BZOJ3625】【codeforces438E】小朋友 生成函數+多項式求逆+多項式開根

== reverse turn chang 一個 函數 span 化簡 amp 首先,我們構造一個函數$G(x)$,若存在$k∈C$,則$[x^k]G(x)=1$。 不妨設$F(x)$為最終答案的生成函數,則$[x^n]F(x)$即為權值為$n$的神犇二叉樹個數

[BZOJ3625][Codeforces Round #250][多項式求逆][多項式開根]小朋友

模板題 題解 #include <cstdio> #include <iostream> #include <algorithm> #include <string> #include <cstrin

BZOJ3625】【CF438E】小朋友(生成函式,多項式求逆,多項式開根,NTT)

Description 我們的小朋友很喜歡電腦科學,而且尤其喜歡二叉樹。 考慮一個含有n個互異正整數的序列c[1],c[2],...,c[n]。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c[1],c[2],...,c[n]}中,我們的小朋友就會將其稱作神犇的。

BZOJ3625】【CF438E】小朋友 NTT 生成函式 多項式開根 多項式求逆

題目大意   考慮一個含有n個互異正整數的序列c1,c2,…,cn。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c1,c2,…,cn}中,我們的小朋友就會將其稱作神犇的。並且他認為,一棵帶點權的樹的權值,是其所有頂點權值的總和。   給出一個整數

bzoj3625】【CF438E/round250E】小朋友【FFT/NTT】【多項式求逆】【多項式開根】

題目連結 題解:我們設f[i]表示權值為i的二叉樹的數目,g[i]為i這個值是否在C集合中出現。則很容易得到f[x]=∑xi−1g[i]∑x−ij=0f[j]f[x−i−j]f[x]=∑i−1xg[i]∑j=0x−if[j]f[x−i−j],且f[0]=1f[

BZOJ3625: [Codeforces Round #250]小朋友(OGF+牛頓迭代)

傳送門 題解: 看到這種二叉樹的題第一反應就是類似卡特蘭數的遞推。或者另外一種直觀的想法是看成一個點和兩邊的二叉樹的拼接,注意這裡不帶標號。 那麼很簡單了,對於點和二叉樹分別構造OGF:g(x),f(x),那麼: f=gf2+1 解二次方程: f=2

bzoj3625:[Codeforces Round #250]小朋友

n-1 namespace git using clas register ++ lin algo bzoj傳送門 luogu 生成函數,多項式 首先考慮這個題最顯然的\(dp\)方程,設\(f(n)\)為根節點權值為\(n\)的二叉樹個數,\(g(n)\)為權值為\(n\

【CF438E】小朋友 解題報告

【CF438E】小朋友和二叉樹 Description ​ 我們的小朋友很喜歡電腦科學,而且尤其喜歡二叉樹。 ​ 考慮一個含有\(n\)個互異正整數的序列\(c_1,c_2,\dots,c_n\)。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合\(\{c_1,c_2,\dots,c_n\}\)中,

BZOJ 3625 [Codeforces Round #250]小朋友 多項式開根

題意:連結 方法:多項式開根 解析: 首先先搞出來C(x)->即C的生成函式。 然後推一下式子嘛 選或者不選,選的話是一個遞迴,不選是1。 設F(x)為權值的生成函式。 即F(x)=C(x)∗F2(x)+1 然後搞一下。

[多項式開根 模板題] BZOJ 3625 [Codeforces Round #250]小朋友

令A(x)=∑i∈Sxi 以及f(x)為答案的母函式 那麼f(x)=A(x)∗f2(x)+1A(x)∗f2(x)−f(x)+1=0f(x)=1±1−4A(x)−−−−−−−−√2A(x)=21±1−4A(x)−−−−−−−−√ 因為f(0)=1 必取 21

bzoj-3625 小朋友

題意: 給出一個大小為n的集合C; 對於i=1...m計算有多少二叉樹滿足每個節點的權值都在集合C中且所有結點權值和為i; 對998244353取模,左右兒子有別; 題解: 生成函式系列題解之三? 這題先對C搞個生成函式吧,令其為C(x); 而我們要求的是樹的計數的函式F

[bzoj 3625][Codeforces Round #250]小朋友 NTT多項式求逆+多項式開根

Description 我們的小朋友很喜歡電腦科學,而且尤其喜歡二叉樹。 考慮一個含有n個互異正整數的序列c[1],c[2],…,c[n]。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c[1],c[2],…,c[n]}中,我們的小朋友就會將其稱作

BZOJ 3625 小朋友(生成函式+FFT)

Description 我們的小朋友很喜歡電腦科學,而且尤其喜歡二叉樹。 考慮一個含有n個互異正整數的序列c[1],c[2],...,c[n]。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c[1],c[2],...,c[n]}中,我們的小朋友就會

bzoj 3625 小朋友 多項式開根

常數大到飛起。 O(nlogn)的演算法在CF上跑了2000ms也是神奇。 有空看下怎麼常數寫小一點。。 NTT做了個小優化,快了一點 #include <iostream> #include <cstdio> #include <cs

BZOJ 3625: [Codeforces Round #250]小朋友 dp 生成函式 多項式開根

3625: [Codeforces Round #250]小朋友和二叉樹Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 743  Solved: 336[Submit][Status][Discuss]Description我們

[CF438E] 小朋友

Description 給定一個整數集合 \(c\),對於每個 \(i\in[1,m]\),求有多少種不同的帶點權的二叉樹使得這棵樹點權和為 \(i\) 並且頂點的點權全部在集合 \(c\) 中。\(m\leq 10^5\)。 Solution 設 \(f[i]\) 為點權為 \(i\) 的二叉樹的方案