# 堆的计数 #### 题目描述 我们知道包含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 ## aop ### before ```cpp #include 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; } ``` ### after ```cpp ``` ## 答案 ```cpp 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; } ``` ## 选项 ### A ```cpp 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; } ``` ### B ```cpp 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; } ``` ### C ```cpp 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], s[i * 2]) * dp[i * 2]) % mod * dp[i * 2] % mod; } } cout << dp[1] << endl; return 0; } ```