【BZOJ4001】概率论(TJOI2015)-生成函数+卡特兰数+微积分

测试地址:概率论
做法:本题需要用到生成函数+卡特兰数+微积分。
g ( i ) i 个节点的不同构的二叉树数目,我们知道这就是卡特兰数。再令 f ( i ) i 个节点的所有不同构的二叉树的叶子节点数总和。答案显然就是 f ( n ) g ( n )
首先很快得出 f 的递推式:
f ( 1 ) = 1 , f ( n ( n 2 ) ) = 2 i = 0 n 1 f ( i ) g ( n i 1 )
G , F 分别为 g , f 的生成函数,根据 g 的递推式:
g ( 0 ) = 1 , g ( n ( n 1 ) ) = i = 0 n 1 g ( i ) g ( n i 1 )
发现很是一个卷积的形式,但是右边算的卷积会被放在 n 1 的位置上,要使它放在 n 的位置上需要往右移一位,在生成函数上的体现就是乘个 x 。别忘了补一个 1 来表示 g ( 0 ) 。于是有:
G ( x ) = x [ G ( x ) ] 2 + 1
解一元二次方程得: G ( x ) = 1 1 4 x 2 x (分子那个 为什么不能取 + 尚不了解,但往下算到某一步能看出 + 不行)。
我们用相似的方式分析 f 的递推式,有:
F ( x ) = 2 x F ( x ) G ( x ) + x
将前面求出的 G ( x ) 代入计算,得到:
F ( x ) = x 1 4 x
有了 F ( x ) 的表达式,但是怎么把它写成级数展开的形式呢?直接泰勒展开?太麻烦了。我们注意到:
1 4 x 的导数是 2 1 4 x (用链式法则计算)。
也就是说:
F ( x ) x d x = 1 2 1 4 x + C = x G ( x ) (当 C = 1 2 时)
于是我们有:
F ( x ) = x [ x G ( x ) ] ( x ) 表示 x 的导函数)
这就变成了对生成函数乘 x 和求导的问题。乘 x 就相当于数列向后移位,那么求导是什么呢?因为生成函数是一个多项式,因此可以每一项分开求导。因此我们有:
G ( x ) = i = 0 g ( i ) x i
x G ( x ) = i = 0 g ( i ) x i + 1
[ x G ( x ) ] = i = 0 ( i + 1 ) g ( i ) x i
x [ x G ( x ) ] = i = 0 ( i + 1 ) g ( i ) x i + 1 = F ( x )
因此 f ( n ) = n g ( n 1 ) ,所以 f ( n ) g ( n ) = n g ( n 1 ) g ( n )
有因为我们知道 g 是卡特兰数,所以 g ( n ) = 1 n + 1 C 2 n n ,那么把组合数拆开化简得:
n g ( n 1 ) g ( n ) = n ( n + 1 ) 2 ( 2 n 1 )
于是寥寥几行代码就解决了这个问题(这真的不是在考数学么……)。
(当然你要是打表找规律或者硬是通过组合意义得出这个式子我也没有意见……)
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
double n;

int main()
{
    scanf("%lf",&n);
    printf("%.9lf",n*(n+1.0)/(2.0*(2.0*n-1.0)));

    return 0;
}

猜你喜欢

转载自blog.csdn.net/Maxwei_wzj/article/details/80954029
今日推荐