Description
Input
输入一行,一个整数 n,表示烷基中碳原子的数目。
Output
输出该烷基同分异构体的数目,对 10^9+7 取模。
Sample Input
6
Sample Output
17
Hint
1≤n≤400
注意:这里的烷基计数不用考虑空间异构,能否稳定存在等各种特殊情况。也就是说,你要求的是 n 个点的每个点度数不超过 4 且根的度数不超过 3 的有根树的数目。
题解
按照“二叉树个数”的思路,我们可以枚举每个节点儿子子树的大小来做。
值得注意的是,这棵树的儿子是无序的所以不能简单用乘法原理相乘。记 $f_k$ 为子树大小为 $k$ 的生成树的个数。记其三个儿子大小为 $i,j,p$ 显然 $i+j+p = k-1$ 。不妨设 $i <= j <= p$。
满足:
$$f_k =
\begin{cases}
C_{f_i+3-1}^3& \text{i = p}\\
C_{f_i+2-1}^2*f_p& \text{i = j}\\
C_{f_j+2-1}^2*f_i& \text{j = p}\\
f_i*f_j*f_p& \text{otherwise}
\end{cases}$$
其中形同 $C_{n+m-1}^m$ 是可重复的组合数。
1 //It is made by Awson on 2018.1.2 2 #include <set> 3 #include <map> 4 #include <cmath> 5 #include <ctime> 6 #include <queue> 7 #include <stack> 8 #include <cstdio> 9 #include <string> 10 #include <vector> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 #define LL long long 16 #define Max(a, b) ((a) > (b) ? (a) : (b)) 17 #define Min(a, b) ((a) < (b) ? (a) : (b)) 18 using namespace std; 19 const int N = 400; 20 const int MOD = 1e9+7; 21 22 int n; 23 int f[N+5]; 24 25 int quick_pow(int x, int y) { 26 int ans = 1; 27 while (y) { 28 if (y&1) ans = (LL)ans*x%MOD; 29 x = (LL)x*x%MOD, y >>= 1; 30 } 31 return ans; 32 } 33 void work() { 34 scanf("%d", &n); 35 f[0] = 1; 36 for (int k = 1; k <= n; k++) 37 for (int i = 0; i <= k; i++) 38 for (int j = i; j <= k; j++) { 39 int p = k-1-i-j; if (p < j) break; 40 if (i == p) (f[k] += (LL)f[i]*(f[i]+1)%MOD*(f[i]+2)%MOD*quick_pow(6, MOD-2)%MOD) %= MOD; 41 else if (i == j) (f[k] += (LL)f[i]*(f[i]+1)%MOD*quick_pow(2, MOD-2)%MOD*f[p]%MOD) %= MOD; 42 else if (j == p) (f[k] += (LL)f[p]*(f[p]+1)%MOD*quick_pow(2, MOD-2)%MOD*f[i]%MOD) %= MOD; 43 else (f[k] += (LL)f[i]*f[j]%MOD*f[p]%MOD) %= MOD; 44 } 45 printf("%d\n", f[n]); 46 } 47 int main() { 48 work(); 49 return 0; 50 }