堆的计数
题目描述
我们知道包含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;
}