专栏文章

快速计算分割函数

算法·理论参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mingojs1
此快照首次捕获于
2025/12/02 02:07
3 个月前
此快照最后确认于
2025/12/02 02:07
3 个月前
查看原文

核心思路

  1. 找到分割函数的生成函数:分割函数 p(n)p(n)(将 nn 拆分为若干正整数之和的方案数)的生成函数 P(x)P(x) 是: P(x)=n=0p(n)xn=k=111xkP(x) = \sum_{n=0}^{\infty} p(n)x^n = \prod_{k=1}^{\infty} \frac{1}{1-x^k} 我们的目标是计算这个 P(x)P(x)(modxN+1)\pmod{x^{N+1}} 意义下的系数,即 p(0),p(1),,p(N)p(0), p(1), \dots, p(N)
  2. 利用多项式求逆P(x)P(x) 可以看作是另一个多项式 A(x)A(x) 的倒数: P(x)=1A(x)其中A(x)=k=1(1xk)P(x) = \frac{1}{A(x)} \quad \text{其中} \quad A(x) = \prod_{k=1}^{\infty} (1-x^k) 如果我们能快速计算出 A(x)(modxN+1)A(x) \pmod{x^{N+1}},我们就可以用一次 O(NlogN)O(N \log N)多项式求逆来得到 P(x)(modxN+1)P(x) \pmod{x^{N+1}}
  3. 使用欧拉五边形数定理: 直接计算 A(x)=(1x)(1x2)(1xN)(modxN+1)A(x) = (1-x)(1-x^2)\dots(1-x^N) \pmod{x^{N+1}} 需要 O(N2)O(N^2) 或更差的复杂度,这太慢了。 幸运的是,欧拉发现了一个神奇的定理——五边形数定理k=1(1xk)=k=(1)kxgk=1+k=1(1)k(xgk+xgk)\prod_{k=1}^{\infty} (1-x^k) = \sum_{k=-\infty}^{\infty} (-1)^k x^{g_k} = 1 + \sum_{k=1}^{\infty} (-1)^k \left( x^{g_k} + x^{g_{-k}} \right) 其中 gk=k(3k1)2g_k = \frac{k(3k-1)}{2}广义五边形数
    展开来看 A(x)A(x)
    • k=0k=0: g0=0g_0 = 0, A(x)A(x)+1x0=1+1 \cdot x^0 = 1
    • k=1k=1: g1=1g_1 = 1, g1=2g_{-1} = 2, A(x)A(x)1x11x2=xx2-1 \cdot x^1 - 1 \cdot x^2 = -x - x^2
    • k=2k=2: g2=5g_2 = 5, g2=7g_{-2} = 7, A(x)A(x)+1x5+1x7=+x5+x7+1 \cdot x^5 + 1 \cdot x^7 = +x^5 + x^7
    • k=3k=3: g3=12g_3 = 12, g3=15g_{-3} = 15, A(x)A(x)1x121x15-1 \cdot x^{12} - 1 \cdot x^{15}
    • ...
    所以: A(x)=1xx2+x5+x7x12x15+A(x) = 1 - x - x^2 + x^5 + x^7 - x^{12} - x^{15} + \dots
    这是一个稀疏多项式

O(NlogN)O(N \log N) 算法步骤

现在我们可以整合出完整的算法:

步骤 1:构造稀疏多项式 A(x)A(x)

我们需要计算 A(x)=k=(1)kxgk(modxN+1)A(x) = \sum_{k=-\infty}^{\infty} (-1)^k x^{g_k} \pmod{x^{N+1}}
我们只需要计算所有 gkNg_k \le N 的项。 由于 gk3k22g_k \approx \frac{3k^2}{2}kk 的取值范围大致在 O(N)O(\sqrt{N}) 级别。
  1. 初始化一个全零的多项式(数组) AA ,长度为 N+1N+1
  2. 设置 A[0]=1A[0] = 1
  3. k=1k = 1 开始循环: a. 计算五边形数 gk=k(3k1)2g_k = \frac{k(3k-1)}{2}。 b. 如果 gk>Ng_k > N,跳出循环。 c. 根据 kk 的奇偶性设置 A[gk]A[g_k]: * 如果 kk 是奇数, A[gk]=1A[g_k] = -1。 * 如果 kk 是偶数, A[gk]=+1A[g_k] = +1。 d. 计算 gk=k(3k+1)2g_{-k} = \frac{k(3k+1)}{2}。 e. 如果 gk>Ng_{-k} > N,跳出循环(理论上可以只跳出这一半)。 f. 同样设置 A[gk]A[g_{-k}](符号与 gkg_k 相同)。
复杂度:这个循环最多执行 O(N)O(\sqrt{N}) 次。所以构造 A(x)A(x) 的时间复杂度仅为 O(N)O(\sqrt{N})

步骤 2:计算多项式求逆

我们现在有了 A(x)A(x) (一个 N+1N+1 项的多项式,尽管它很稀疏)。 我们的目标是计算 P(x)P(x) 使得: A(x)P(x)1(modxN+1)A(x) P(x) \equiv 1 \pmod{x^{N+1}}
这可以通过基于牛顿迭代法 的标准多项式求逆算法实现,从而可以在 O(NlogN)O(N \log N) 的时间内计算出 A(x)A(x) 的逆 P(x)P(x)
多项式求逆简介: 假设我们已经求得 P0(x)P_0(x) 满足 A(x)P0(x)1(modxk)A(x)P_0(x) \equiv 1 \pmod{x^k}。 我们想求 P(x)P(x) 满足 A(x)P(x)1(modx2k)A(x)P(x) \equiv 1 \pmod{x^{2k}}
迭代公式为: P(x)P0(x)(2A(x)P0(x))(modx2k)P(x) \equiv P_0(x) \left( 2 - A(x)P_0(x) \right) \pmod{x^{2k}}
P(x)1(modx1)P(x) \equiv 1 \pmod{x^1} (即 p(0)=1p(0)=1) 开始,我们通过 logN\log N 次迭代(每次将精度加倍:124N1 \to 2 \to 4 \to \dots \to N'),每次迭代涉及两次多项式乘法(和一次减法),总复杂度为 O(NlogN)O(N \log N)

步骤 3:获得答案

执行完多项式求逆后,得到的 P(x)=n=0Np(n)xnP(x) = \sum_{n=0}^{N} p(n)x^n。 数组 PP 中的第 nnP[n]P[n] 即为分割函数 p(n)p(n) 的值。
总时间复杂度O(N+NlogN)=O(NlogN)O(\sqrt{N} + N \log N) = O(N \log N)

附:另一种 O(NlogN)O(N \log N) 方法 (多项式 Exp)

顺便一提,还有一种相关的方法,不使用五边形数定理,而是使用多项式指数函数
  1. P(x)=k=111xkP(x) = \prod_{k=1}^{\infty} \frac{1}{1-x^k}
  2. 取对数:lnP(x)=k=1ln(1xk)=k=1j=1(xk)jj=k=1j=1xkjj\ln P(x) = \sum_{k=1}^{\infty} -\ln(1-x^k) = \sum_{k=1}^{\infty} \sum_{j=1}^{\infty} \frac{(x^k)^j}{j} = \sum_{k=1}^{\infty} \sum_{j=1}^{\infty} \frac{x^{kj}}{j}
  3. 交换求和次序,令 n=kjn = kjlnP(x)=n=1xn(jn1j)=n=1xn(1njnnj)=n=1σ1(n)nxn\ln P(x) = \sum_{n=1}^{\infty} x^n \left( \sum_{j|n} \frac{1}{j} \right) = \sum_{n=1}^{\infty} x^n \left( \frac{1}{n} \sum_{j|n} \frac{n}{j} \right) = \sum_{n=1}^{\infty} \frac{\sigma_1(n)}{n} x^n (其中 σ1(n)\sigma_1(n)nn 的约数和)
  4. Q(x)=lnP(x)Q(x) = \ln P(x)
  5. 算法: 使用 O(NlogN)O(N \log N)多项式指数函数 计算 P(x)=exp(Q(x))(modxN+1)P(x) = \exp(Q(x)) \pmod{x^{N+1}}

评论

0 条评论,欢迎与作者交流。

正在加载评论...