用C++解决​堆的计数问题

​堆的计数
题目描述

我们知道包含N个元素的堆可以看成是一棵包含N个节点的完全二叉树。

每个节点有一个权值。对于小根堆来说,父节点的权值一定小于其子节点的权值。
假设N个节点的权值分别是1~N,你能求出一共有多少种不同的小根堆吗?
例如对于N=4有如下3种:

1

/
2 3
/
4

1

/
3 2
/
4

1

/
2 4
/
3

由于数量可能超过整型范围,你只需要输出结果除以1000000009的余数。

输入格式

一个整数N。

对于40%的数据,1 <= N <= 1000

对于70%的数据,1 <= N <= 10000

对于100%的数据,1 <= N <= 100000

输出格式

一个整数表示答案。

输入样例

4

输出样例

3

资源约定:

峰值内存消耗(含虚拟机) < 256M

CPU消耗 < 1000ms


#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
const int maxn = 100000;
ll s[maxn + 10], dp[maxn + 10], inv[maxn + 10], f[maxn + 10];
ll n;
ll mod = 1000000009;
ll qPow(ll a, ll b)
{
    ll ans = 1;
    while (b != 0)
    {
        if (b & 1)
        {
            ans = ans * a % mod;
        }
        a = a * a % mod;
        b >>= 1;
    }
    return ans % mod;
}
ll C(ll n, ll m)
{
    return (f[n] * inv[f[m]]) % mod * inv[f[n - m]] % mod;
}
 
int main()
{
    cin >> n;
    f[0] = 1;
    for (int i = 1; i <= maxn; i++)
    {
        f[i] = (f[i - 1] * i) % mod;
        inv[i] = qPow(i, mod - 2);
    }
    for (int i = n; i >= 1; i--)
    {
        s[i] = (s[i * 2 + 1] <= n ? s[i * 2 + 1] : 0) + (s[i * 2] <= n ? s[i * 2] : 0) + 1;
    }
    for (int i = 1; i <= n; i++)
    {
        dp[i] = 1;
    }
    for (int i = n; i >= 1; i--)
    {
        if (i * 2 + 1 <= n)
        {
            dp[i] = (C(s[i] - 1, s[i * 2 + 1]) * dp[i * 2 + 1]) % mod * dp[i * 2] % mod;
        }
    }
    cout << dp[1] << endl;
    return 0;
}