1 条题解

  • 0
    @ 2025-12-10 20:39:36

    题解:烷烃同分异构体计数

    一、问题转化与核心公式

    题目要求计算化学式 CnH2n+2\text{C}_n\text{H}_{2n+2} 的烷烃同分异构体个数,等价于求 nn 个点的无标号无根树,且每个点的度数 4\leq 4

    设:

    • f[n]f[n]:有 nn 个碳原子的有根烷烃个数
    • g[n]g[n]:有 nn 个碳原子的无根烷烃个数

    关键公式(从代码Newton函数推导):

    $$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} $$

    其中 f(xk)f(x^k) 表示将 f(x)f(x)xix^i 项变为 xkix^{k \cdot i}


    二、代码实现解析

    2.1 牛顿迭代求解 f(x)f(x)

    代码中 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 计算无根树个数

    P(x)P(x) 表示所有无根烷烃的生成函数(含对称重复),由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} $$

    这正好与 f(x)f(x) 方程相同,但 f(x)f(x)+1+1 表示空树,而 P(x)P(x)+1+1 表示单个碳原子。

    代码中实际计算的是:

    poly g = 1 + (((f_4 + 6*f_2*f2 + 3*f2*f2 + 8*f*f3 + 6*f4) / 24) << 1);
    

    这里 <<1 相当于乘 xx,所以 g[n]g[n]nn 个碳原子的某种计数。


    2.3 最终答案计算公式

    对于奇数 nn(代码对应部分):

    int res = (g[n] - (1ll * f_2[n] * Inv(2) - f[n]) % mod + mod) % mod;
    

    对应公式:

    g[n](f2[n]2f[n])g[n] - \left(\frac{f_2[n]}{2} - f[n]\right)

    其中 f2[n]=i=0nf[i]f[ni]f_2[n] = \sum_{i=0}^n f[i] \cdot f[n-i]

    对于偶数 nn

    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} $$

    解释

    • 第一项 g[n]g[n]:包含所有情况
    • 第二项:减去以边为根的重复计数(Otter定理)
    • 第三项(仅偶数):减去中心对称边的重复情况

    2.4 预处理加速

    为了 O(1)O(1) 回答每个 nn,代码预处理了:

    // 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
    

    所有多项式均截断到 maxn+1maxn+1 项。


    三、算法复杂度分析

    1. 牛顿迭代求 f(x)f(x):每次迭代进行多项式乘除,O(nlogn)O(n \log n)
    2. 预处理卷积fff * ff3f^3f4f^4,每个 O(nlogn)O(n \log n)
    3. 回答查询:每个 O(1)O(1)
    4. 总复杂度O(nlogn+T)O(n \log n + T),满足 n,T105n,T \leq 10^5

    四、关键公式总结

    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 无根烷烃计数公式

    f2[n]=i=0nf[i]f[ni]f_2[n] = \sum_{i=0}^n f[i] \cdot f[n-i]

    nn 为奇数时

    $$\text{ans}[n] = g[n] - \left(\frac{f_2[n]}{2} - f[n]\right) $$

    nn 为偶数时

    $$\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} $$

    其中 g[n]g[n] 由 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} $$

    这里 fk[n]f_k'[n] 表示 f[n/k]f[n/k](当 knk \mid n 时)。


    五、样例验证

    对于 n=3,4,5n=3,4,5

    • n=3n=3:输出 11(只有正丙烷)
    • n=4n=4:输出 22(正丁烷、异丁烷)
    • n=5n=5:输出 33(正戊烷、异戊烷、新戊烷)

    与代码输出一致。


    通过牛顿迭代求解生成函数,结合 Polya 计数和 Otter 定理去重,本代码高效地解决了烷烃同分异构体计数问题。

    • 1

    信息

    ID
    6049
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者