题目
思路
部分借鉴了@connect 的博客,不完全相同。
一个方案由三部分组成:根节点、左子树、右子树。任意一部分不同,得到的方案便不同。
所以,如果用 f i f_i fi 表示权值为 i i i 的树的个数, g i g_i gi 表示 i i i 是否属于集合 { c } \{c\} {c} (是,则为一;否则为零)。对于 n ( n ≥ 1 ) n(n\ge 1) n(n≥1) ,一定有递推式 f n = ∑ x = 0 n g x ∑ i = 0 n − x f i f n − x − i f_n=\sum_{x=0}^{n}g_x\sum_{i=0}^{n-x}f_if_{n-x-i} fn=x=0∑ngxi=0∑n−xfifn−x−i
边界是 f 0 = 1 f_0=1 f0=1 (“世界上所有的空树都是一样的。”——沃兹基硕德)。
这是一个卷积的形式。用两个生成函数 F ( x ) = ∑ i = 0 + ∞ f i x i , G ( x ) = ∑ i = 0 + ∞ g i x i F(x)=\sum_{i=0}^{+\infty}f_ix^i,G(x)=\sum_{i=0}^{+\infty}g_ix^i F(x)=∑i=0+∞fixi,G(x)=∑i=0+∞gixi 来描述这一关系,即是
F ( x ) − f 0 x 0 = G ( x ) F ( x ) 2 F(x)-f_0x^0=G(x)F(x)^2 F(x)−f0x0=G(x)F(x)2
减去的 f 0 x 0 f_0x^0 f0x0 ,是因为递推式只对 n ≥ 1 n\ge 1 n≥1 的情况生效。
结合 f 0 = 1 f_0=1 f0=1 ,可以将式子写成 G ( x ) F ( x ) 2 − F ( x ) + 1 = 0 G(x)F(x)^2-F(x)+1=0 G(x)F(x)2−F(x)+1=0
解一元二次方程,得到 F ( x ) = 1 ± 1 − 4 G ( x ) 2 G ( x ) F(x)=\frac{1±\sqrt{1-4G(x)}}{2G(x)} F(x)=2G(x)1±1−4G(x)
由于 [ 1 + 1 − 4 G ( x ) ] [ 1 − 1 − 4 G ( x ) ] = 4 G ( x ) \left[1+\sqrt{1-4G(x)}\right]\left[1-\sqrt{1-4G(x)}\right]=4G(x) [1+1−4G(x)][1−1−4G(x)]=4G(x) ,所以将式子化简得到:
F ( x ) = 2 1 ± 1 − 4 G ( x ) F(x)=\frac{2}{1±\sqrt{1-4G(x)}} F(x)=1±1−4G(x)2
怎么会有两个可能的 F ( x ) F(x) F(x) ?难道答案不唯一?难道数学有漏洞?第四次数学危机就此爆发?
合理的解释只有一个:这两个 F ( x ) F(x) F(x) 中,有且仅有一个,满足 ∀ j ∈ [ 0 , + ∞ ) , f j ≥ 0 \forall j\in[0,+\infty),f_j\ge 0 ∀j∈[0,+∞),fj≥0 。
也就是说, F ( x ) F(x) F(x) 的系数非负。其必要条件是, F ( x ) F(x) F(x) 在 x x x 非负时不降。
形式化地,我们有 ∀ x ∈ [ 0 , + ∞ ) , F ′ ( x ) ≥ 0 \forall x\in[0,+\infty),F'(x)\ge 0 ∀x∈[0,+∞),F′(x)≥0
类似的,因为 G ( x ) G(x) G(x)的系数非负,并且存在一个非零次项的系数为正,所以 ∀ x ∈ [ 0 , + ∞ ) , G ′ ( x ) > 0 \forall x\in[0,+\infty),G'(x)>0 ∀x∈[0,+∞),G′(x)>0
如果你注意到, F ( x ) = 2 1 − 1 − 4 G ( x ) F(x)=\frac{2}{1-\sqrt{1-4G(x)}} F(x)=1−1−4G(x)2 ,不妨设 x ≥ 0 x\ge 0 x≥0 ,当 x x x 增大时, G ( x ) G(x) G(x) 增大,于是 1 − 4 G ( x ) \sqrt{1-4G(x)} 1−4G(x) 减小,即分母在增大,故 F ( x ) F(x) F(x) 减小,那么此解可以舍弃。
最后写出结论, F ( x ) = 2 1 + 1 − 4 G ( x ) F(x)=\frac{2}{1+\sqrt{1-4G(x)}} F(x)=1+1−4G(x)2
只需要多项式开根与多项式求逆即可。时间复杂度 O ( n log n ) \mathcal O(n\log n) O(nlogn)。
另: F ( x ) F(x) F(x) 的“舍弃其中一个解”的方法,也可以用检测 x → 0 x\rightarrow 0 x→0 时的极限来判断。见文章开头链接。
代码
我不想打。真是抱歉。
所以你在期待些什么呀?