[学习笔记] 分拆数的几种求法

  • 对分拆数的多种求法做了简单的整理。

问题

  • f n f_n fn 表示将 n n n 进行分拆的方案数。
  • 例如, 1 + 1 + 1 + 1 = 1 + 1 + 2 = 1 + 3 = 2 + 2 = 4 1 + 1 + 1 + 1 = 1 + 1 + 2 = 1 + 3 = 2 + 2 = 4 1+1+1+1=1+1+2=1+3=2+2=4 ,所以 f 4 = 5 f_4 = 5 f4=5
  • 给出 n ≤ 1 0 5 ( n ≤ 1 0 5 ) n \le 10^5(n \le 10^5) n105(n105),求 f 1 , f 2 , . . . , f n f_1, f_2, ..., f_n f1,f2,...,fn 998244353 998244353 998244353 取模。

算法一

  • 考虑根号分治,设 S = n S = \sqrt{n} S=n
  • 对于 > S > S >S 的数,设 g i , j g_{i,j} gi,j 表示选了 i i i 个数总和为 i ( S + 1 ) + j i(S+1) + j i(S+1)+j 的方案数,转移有两种:
    1. 新加入一个数,初始值为 S + 1 S + 1 S+1 g i , j + = g i − 1 , j g_{i,j} += g_{i - 1, j} gi,j+=gi1,j
    2. 给之前选的所有数 +1 g i , j + = g i , j − i g_{i,j} += g_{i,j - i} gi,j+=gi,ji
  • 不难发现,这样转移对于每一种拆分都有唯一的构造方式,并且第一维只有 O ( n ) \mathcal O( \sqrt{n}) O(n ) 级别,时间复杂度 O ( n n ) \mathcal O(n \sqrt{n}) O(nn )
  • 求出 > S >S >S 的数的 DP \text{DP} DP 数组后,对于 ≤ S \le S S 的数,暴力背包 DP \text{DP} DP 即可,总的时间复杂度 O ( n n ) \mathcal O(n \sqrt{n}) O(nn )
  • 这应该是最为通用的做法,常数也比较小。

算法二

  • f 0 = 1 f_0 = 1 f0=1,考虑 f i f_i fi 的生成函数
    F ( x ) = ∑ i = 0 ∞ f i x i = ∏ i = 1 ∞ 1 1 − x i = exp ⁡ ( ∑ i = 1 ∞ ln ⁡ 1 1 − x i ) \begin{aligned} F(x) &= \sum \limits_{i = 0}^{\infty}f_ix^i \\ &= \prod \limits_{i = 1}^{\infty} \frac{1}{1 - x^i}\\ &= \exp\left(\sum \limits_{i = 1}^{\infty} \ln \frac{1}{1-x^i}\right)\\ \end{aligned} F(x)=i=0fixi=i=11xi1=exp(i=1ln1xi1)
  • 注意到
    ln ⁡ 1 1 − x i = ∫ ( 1 − x i ) ( 1 1 − x i ) ′ d x = ∑ j = 1 ∞ x i j − ∑ j = 2 ∞ j − 1 j x i j = ∑ j = 1 ∞ x i j j \begin{aligned} \ln \frac{1}{1 - x^i} &= \int (1 - x^i)\left(\frac{1}{1 - x^i}\right)' dx\\ &= \sum \limits_{j = 1}^{\infty}x^{ij} - \sum \limits_{j = 2}^{\infty}\frac{j - 1}{j}x^{ij}\\ &= \sum \limits_{j = 1}^{\infty}\frac{x^{ij}}{j}\\ \end{aligned} ln1xi1=(1xi)(1xi1)dx=j=1xijj=2jj1xij=j=1jxij
  • 所以
    F ( x ) = exp ⁡ ( ∑ i = 1 ∞ ∑ j = 1 ∞ x i j j ) \begin{aligned} F(x) = \exp\left(\sum \limits_{i = 1}^{\infty}\sum \limits_{j = 1}^{\infty} \frac{x^{ij}}{j}\right)\\ \end{aligned} F(x)=exp(i=1j=1jxij)
  • 可以 O ( n ln ⁡ n ) \mathcal O(n \ln n) O(nlnn) 预处理出内部系数,再 exp ⁡ \exp exp 回去。
  • 总的时间复杂度 O ( n log ⁡ n ) \mathcal O(n \log n) O(nlogn)

算法三

  • 还是算法二中的生成函数,由 五边形数定理 得:
    ϕ ( x ) = ∏ i = 1 ∞ ( 1 − x i ) = 1 + ∑ k = 1 ∞ ( − 1 ) k x k ( 3 k − 1 ) 2 \begin{aligned} \phi(x) = \prod \limits_{i = 1}^{\infty} (1 - x^i) = 1 + \sum \limits_{k = 1}^{\infty}(-1)^kx^{\frac{k(3k - 1)}{2}} \end{aligned} ϕ(x)=i=1(1xi)=1+k=1(1)kx2k(3k1)
  • 这里直接引用 visit_world博客中的证明。
  • 由于 ϕ ( x ) F ( x ) = 1 \phi(x)F(x) = 1 ϕ(x)F(x)=1,可以直接多项式求逆,时间复杂度 O ( n log ⁡ n ) \mathcal O(n \log n) O(nlogn)
  • 还有一种更简单的方法, 注意到 ϕ ( x ) ( m o d    x n + 1 ) \phi(x)(\mod x^{n + 1}) ϕ(x)(modxn+1) 中系数不为 0 0 0 的项只有 O ( n ) \mathcal O(\sqrt{n}) O(n ) 个,暴力模拟求逆即可,时间复杂度 O ( n n ) \mathcal O(n \sqrt{n}) O(nn )

你可能感兴趣的:(学习笔记,多项式,DP,根号分治,五边形数定理)