1 条题解
-
0
题解:烷烃同分异构体计数
一、问题转化与核心公式
题目要求计算化学式 的烷烃同分异构体个数,等价于求 个点的无标号无根树,且每个点的度数 。
设:
- :有 个碳原子的有根烷烃个数
- :有 个碳原子的无根烷烃个数
关键公式(从代码
$$f(x) = 1 + x \cdot \frac{f(x)^4 + 6f(x)^2f(x^2) + 3f(x^2)^2 + 8f(x)f(x^3) + 6f(x^4)}{24} $$Newton函数推导):其中 表示将 中 项变为 。
二、代码实现解析
2.1 牛顿迭代求解
代码中
Newton(int n)函数求解上述隐式方程:poly Newton(int n) { int os = n + 1, len = uplen(os); poly f{1}; // 初始f(x)=1 for (int i = 1; i < len; i <<= 1) { // 倍增迭代 // 计算f(x^2), f(x^3) poly f2(i << 1), f3(i << 1); for (int j = 0; j < i << 1; j += 2) f2[j] = f[j/2]; for (int j = 0; j < i << 1; j += 3) f3[j] = f[j/3]; poly f_2 = f * f; // f(x)^2 poly f_3 = f_2 * f; // f(x)^3 // F(f) = 6*(1-f) + x*(f^4 + 6f^2f(x^2) + 3f(x^2)^2 + 8f*f(x^3) + 6f(x^4)) // 为方便计算,代码中乘以x通过左移实现 poly up = 6*(1 - f) + ((f*(f_3 + 3*f2) + 2*f3) << 1); up.resize(i << 1); // F'(f)的导数部分 poly dn = ((3*(f_2 + f2)) << 1) - 6; dn.resize(i << 1); // 牛顿迭代:f_{new} = f - F(f)/F'(f) f = f - up / dn; f.resize(i << 1); } f.resize(os); return f; }注:代码中公式略有简化,等价于标准公式。
2.2 计算无根树个数
设 表示所有无根烷烃的生成函数(含对称重复),由Polya计数:
$$P(x) = 1 + x \cdot \frac{f(x)^4 + 6f(x)^2f(x^2) + 3f(x^2)^2 + 8f(x)f(x^3) + 6f(x^4)}{24} $$这正好与 方程相同,但 中 表示空树,而 中 表示单个碳原子。
代码中实际计算的是:
poly g = 1 + (((f_4 + 6*f_2*f2 + 3*f2*f2 + 8*f*f3 + 6*f4) / 24) << 1);这里
<<1相当于乘 ,所以 是 个碳原子的某种计数。
2.3 最终答案计算公式
对于奇数 (代码对应部分):
int res = (g[n] - (1ll * f_2[n] * Inv(2) - f[n]) % mod + mod) % mod;对应公式:
其中 。
对于偶数 :
int res = ((g[n] - ((f_2[n] - 1ll * f[n/2] * f[n/2]) % mod * Inv(2) - f[n]) - f[n/2] * (f[n/2] - 1ll) / 2) % mod + mod) % mod;对应公式:
$$g[n] - \left(\frac{f_2[n] - f[n/2]^2}{2} - f[n]\right) - \frac{f[n/2](f[n/2]-1)}{2} $$解释:
- 第一项 :包含所有情况
- 第二项:减去以边为根的重复计数(Otter定理)
- 第三项(仅偶数):减去中心对称边的重复情况
2.4 预处理加速
为了 回答每个 ,代码预处理了:
// f2[i] = f[i/2] (当i为偶数) for (int i = 0; i <= maxn; i += 2) f2[i] = f[i/2]; // f3[i] = f[i/3] (当i为3的倍数) for (int i = 0; i <= maxn; i += 3) f3[i] = f[i/3]; // f4[i] = f[i/4] (当i为4的倍数) for (int i = 0; i <= maxn; i += 4) f4[i] = f[i/4]; // 计算卷积 poly f_2 = f * f; // f(x)^2 的系数 poly f_3 = f_2 * f; // f(x)^3 poly f_4 = f_3 * f; // f(x)^4所有多项式均截断到 项。
三、算法复杂度分析
- 牛顿迭代求 :每次迭代进行多项式乘除,
- 预处理卷积:、、,每个
- 回答查询:每个
- 总复杂度:,满足
四、关键公式总结
4.1 有根烷烃生成函数
$$f(x) = 1 + x \cdot \frac{f(x)^4 + 6f(x)^2f(x^2) + 3f(x^2)^2 + 8f(x)f(x^3) + 6f(x^4)}{24} $$4.2 无根烷烃计数公式
设 :
当 为奇数时:
$$\text{ans}[n] = g[n] - \left(\frac{f_2[n]}{2} - f[n]\right) $$当 为偶数时:
$$\text{ans}[n] = g[n] - \left(\frac{f_2[n] - f[n/2]^2}{2} - f[n]\right) - \frac{f[n/2](f[n/2]-1)}{2} $$其中 由 Polya 公式计算:
$$g[n] = \frac{f_4[n] + 6 \cdot f_2[n] \cdot f_2'[n] + 3 \cdot f_2'[n]^2 + 8 \cdot f[n] \cdot f_3'[n] + 6 \cdot f_4'[n]}{24} $$这里 表示 (当 时)。
五、样例验证
对于 :
- :输出 (只有正丙烷)
- :输出 (正丁烷、异丁烷)
- :输出 (正戊烷、异戊烷、新戊烷)
与代码输出一致。
通过牛顿迭代求解生成函数,结合 Polya 计数和 Otter 定理去重,本代码高效地解决了烷烃同分异构体计数问题。
- 1
信息
- ID
- 6049
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者