- 对分拆数的多种求法做了简单的整理。
问题
- 令 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) n≤105(n≤105),求 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 的方案数,转移有两种:
- 新加入一个数,初始值为 S + 1 S + 1 S+1: g i , j + = g i − 1 , j g_{i,j} += g_{i - 1, j} gi,j+=gi−1,j;
- 给之前选的所有数
+1
: g i , j + = g i , j − i g_{i,j} += g_{i,j - i} gi,j+=gi,j−i。
- 不难发现,这样转移对于每一种拆分都有唯一的构造方式,并且第一维只有 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=0∑∞fixi=i=1∏∞1−xi1=exp(i=1∑∞ln1−xi1) - 注意到
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} ln1−xi1=∫(1−xi)(1−xi1)′dx=j=1∑∞xij−j=2∑∞jj−1xij=j=1∑∞jxij - 所以
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=1∑∞j=1∑∞jxij) - 可以 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∏∞(1−xi)=1+k=1∑∞(−1)kx2k(3k−1) - 这里直接引用 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)。