[LOJ 6185]烷基计数

Posted navi-awson

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[LOJ 6185]烷基计数相关的知识,希望对你有一定的参考价值。

Description

众所周知,大连 24 中是一所神奇的学校,在那里,化竞的同学很多都擅长写代码。

有一天,化学不及格的胡小兔向化竞巨佬晴岚请教化学题:

n 个碳原子的烷基共有多少种同分异构体?”

刚刚得了化竞全市第一的晴岚听了,认为这道题十分简单,建议胡小兔写个程序解决这个问题。但胡小兔弱得连什么是同分异构体都不知道,于是晴岚给胡小兔画了个图——例如 n=4 时(即丁基),有 4 种同分异构体:

技术分享图片

同理,其他常见烷基同分异构体数目如下表:

n 1 2 3 4 5 6
同分异构体数目 1 1 2 4 8 17

现在已知碳原子个数 n,求对应的烷基有多少种同分异构体。

P.S. 2017.11.30更新:化竞巨佬晴岚高二进国集保送北大了……

Input

输入一行,一个整数 n,表示烷基中碳原子的数目。

Output

输出该烷基同分异构体的数目,对 10^9+7 取模。

Sample Input

6

Sample Output

17

Hint

1n400

注意:这里的烷基计数不用考虑空间异构,能否稳定存在等各种特殊情况。也就是说,你要求的是 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 }

 

以上是关于[LOJ 6185]烷基计数的主要内容,如果未能解决你的问题,请参考以下文章

loj6538烷基计数 加强版 加强版 Burnside引理+多项式牛顿迭代

烷基计数加强版加强版

烷基计数加强版加强版

HDU 6185(打表代码

@loj - 2320@ 「清华集训 2017」生成树计数

Loj #6703 -「清华集训 2017」生成树计数