整数划分问题

整数划分

先给出几个定义:

一、整数的划分
将正整数 n n n 拆分成若干个正整数的和就叫做整数的划分。

二、整数的 k k k 划分
即将其拆分成若干个不大于 k k k 的正整数的和。

三、整数的 k k k 分部划分
即将其拆分成 k k k 个正整数的和。

四、有序划分和无序划分
有序划分即顺序有关的划分,例如 1 + 2 1+2 1+2 2 + 1 2+1 2+1 被视为 3 3 3 的不同的划分。而无序划分则是顺序无关的。

五、划分数
即对应条件下的划分的方案数。
在本文中,将 n n n 的无序划分数记为 B n B_n Bn ,将 n n n 的无序 k k k 划分数记为 B k ( n ) B_k(n) Bk(n) ,将 n n n 的无序 k k k 分部划分数记为 B n , k B_{n,k} Bn,k

本文的重点在于如何求各种不同的划分数。

有序划分

整数 n n n k k k 分部划分数为 C n − 1 k − 1 C_{n-1}^{k-1} Cn1k1

这不难理解: f n , k = ∑ i = 1 n f n − i , k − 1 f_{n,k}=\sum \limits _{i=1}^n f_{n-i,k-1} fn,k=i=1nfni,k1 ,平凡的有其值等于 C n − 1 k − 1 C_{n-1}^{k-1} Cn1k1

n n n 的有序划分数为 ∑ i = 1 n C n − 1 k − 1 = 2 n − 1 \sum\limits_{i=1}^nC_{n-1}^{k-1}=2^{n-1} i=1nCn1k1=2n1

n n n 的有序 k k k 划分数满足 f n , k = ∑ i = 1 k f n − i , k f_{n,k}=\sum\limits_{i=1}^kf_{n-i,k} fn,k=i=1kfni,k ,是一个经典的线性递推式。不过由于其特征多项式为 x k + 1 − 2 x k + 1 x − 1 \frac{x^{k+1}-2x^k+1} {x-1} x1xk+12xk+1 ,可以做到 O ( n ) O(n) O(n) 取模,因此可以做到 O ( n ) O(n) O(n) O ( k log ⁡ k log ⁡ n ) O(k \log k \log n) O(klogklogn) 求值。

有序划分较易理解,这里不再赘述。本文重点在于下面的无序划分。

无序划分

动态规划法

先从朴素的角度切入。

考虑 n n n k k k 划分。

我们可以使用 k k k ,也可以不使用 k k k

因此有 B k ( n ) = B k ( n − k ) + B k − 1 ( n ) B_k(n)=B_k(n-k)+B_{k-1}(n) Bk(n)=Bk(nk)+Bk1(n)

注意当 n ≥ k n \ge k nk B k ( n ) = B k ( k ) B_{k}(n)=B_{k}(k) Bk(n)=Bk(k)

现在考虑无序 k k k 分部划分。

我们知道对于其任意一个合法的划分有 ∑ i = 1 k a i = n \sum\limits_{i=1}^{k}a_i=n i=1kai=n a i ≥ 1 a_i\ge 1 ai1

由于 a i ≥ 1 a_i \ge 1 ai1 的条件不好处理,因此我们令 b i = a i − 1 b_i=a_i-1 bi=ai1

则有 ∑ i = 1 k b i = n − k , b i ≥ 0 \sum\limits_{i=1}^{k}b_i=n-k,b_i \ge 0 i=1kbi=nk,bi0

我们可以考虑将值为 0 0 0 的去掉。

因此 ∑ i = 1 j b i = n − k , b i ≥ 1 , 1 ≤ j ≤ k \sum\limits_{i=1}^{j}b_i=n-k,b_i\ge1,1\le j\le k i=1jbi=nk,bi1,1jk

由于顺序无关,我们可以将任意一种 a a a 的方案以此法一一映射到 b b b 的一种方案。

因此有 B n , k = ∑ i = 1 k B n − k , i B_{n,k}=\sum\limits_{i=1}^{k} B_{n-k,i} Bn,k=i=1kBnk,i

这样直接转移是 O ( n k 2 ) O(nk^2) O(nk2) 的。

将转移方程稍微变形:

B n , k = ∑ i = 1 k B n − k , i = ∑ i = 1 k − 1 B n − k , i + B n − k , k = B n − 1 , k − 1 + B n − k , k B_{n,k}=\sum_{i=1}^{k} B_{n-k,i}=\sum_{i=1}^{k-1}B_{n-k,i}+B_{n-k,k}=B_{n-1,k-1}+B_{n-k,k} Bn,k=i=1kBnk,i=i=1k1Bnk,i+Bnk,k=Bn1,k1+Bnk,k

这样就是 O ( n k ) O(nk) O(nk) 了。

我们发现这个递推式与 k k k 划分是向一致的,只是这两个数列初始边界差异才导致了两个数列的差异。我们尝试考虑两个数列的联系:

无序性实际上加一个限制 a i ≤ a i + 1 a_i \le a_{i+1} aiai+1 即可。

将一中拆分方案抽象为图形,那么这实际上就是一张各列高度递增的网格图,由于平面的特性我们可以将其旋转 90 ° 90 \degree 90° 得到一个新的方案。

实质上我们在做的就是:记 b i = ∑ j = 1 k [ a j ≥ i ] b_i=\sum\limits_{j=1}^{k}[a_j\ge i] bi=j=1k[aji] ,则 ∑ j = 1 max ⁡ { a } b i = n \sum\limits_{j=1}^{\max\{a\}}b_i=n j=1max{a}bi=n b 1 = k , b i ≥ b i + 1 b_1=k,b_i\ge b_{i+1} b1=k,bibi+1

因此我们可以得到 n n n 的无序 k k k 分部划分数等于 n n n 的最大分部值为 k k k 的方案数,于是就有 B n , k = B k ( n ) − B k − 1 ( n ) B_{n,k}=B_{k}(n)-B_{k-1}(n) Bn,k=Bk(n)Bk1(n)

b 2 = k b_2 =k b2=k a i ≥ 2 a_i \ge 2 ai2 ,我们可以令 a i a_i ai 都减去 1 1 1 。否则我们可以在 b b b 中去掉 b 1 = k b_1=k b1=k ,这样就得到了 B n , k = B n − k , k + B n , k − 1 B_{n,k}=B_{n-k,k}+B_{n,k-1} Bn,k=Bnk,k+Bn,k1

当然根据 B n , k = B k ( n ) − B k − 1 ( n ) B_{n,k}=B_{k}(n)-B_{k-1}(n) Bn,k=Bk(n)Bk1(n) 也能得到以上递推式,这也很好解释了为何两个数列的初始边界有所不同。

上述算法的复杂度较大,我们尝试继续优化。

生成函数法

我们尝试从生成函数的角度切入。

先考虑 n n n k k k 划分。

我们可以选任意多的 1 1 1 k k k 之间的数,且需要使之总和为 n n n 。两种方案不同等价于任意一个数选的个数不同。

因此我们可以构造 ∑ j = 0 ∞ x i j \sum\limits_{j=0}^{\infty}x^{ij} j=0xij 表示选取 j j j i i i 的方案。

那么

∑ n = 0 ∞ B k ( n ) x n = ∏ i = 1 k ( ∑ j = 0 ∞ x i j ) = 1 ∏ i = 1 k ( 1 − x i ) \sum\limits_{n=0}^{\infty} B_{k}(n)x^n=\prod_{i=1}^{k}(\sum\limits_{j=0}^{\infty}x^{ij})=\frac{1} {\prod_{i=1}^{k}(1-x^i)} n=0Bk(n)xn=i=1k(j=0xij)=i=1k(1xi)1

显然我们可以转为线性递推来解决这个问题,其特征多项式为 ∏ i = 1 k ( x i − 1 ) \prod_{i=1}^{k}(x^i-1) i=1k(xi1) 。并且我们可以根据 x n   m o d   ( x i − 1 ) = x n   m o d   i x^n \bmod (x^i-1)=x^{n \bmod i} xnmod(xi1)=xnmodi 列出同余方程组。

复杂度 O ( k 2 log ⁡ 2 k ) O(k^2\log^2 k) O(k2log2k) ,注意这是一个与 n n n 无关的复杂度。

但这样 k k k 较大而 n n n 的阶比 k k k 并不是高很多的时候效率较低。考虑是否有其他的处理方式。

暴力乘法是 O ( n k ) O(nk) O(nk) 的,无法继续优化,尝试变换思路。

事实上我们只需要求 f ( x )   m o d   x n + 1 f(x) \bmod x^{n+1} f(x)modxn+1 。超过 n + 1 n+1 n+1 的项是无需计算的。

由于乘法无法继续优化,且我们只需要取函数的前几项,因此我们对函数取对数转为加法。

ln ⁡ f ( x ) = ln ⁡ 1 ∏ i = 1 k ( 1 − x i ) = − ∑ i = 1 k ∑ j = 1 ∞ − x i j j = ∑ i = 1 k ∑ j = 1 ∞ x i j j \ln f(x)=\ln \frac{1} {\prod_{i=1}^{k}(1-x^i)} =-\sum_{i=1}^{k}\sum_{j=1}^{\infty} \frac{-x^{ij}} {j}=\sum_{i=1}^{k}\sum_{j=1}^{\infty} \frac{x^{ij}} {j} lnf(x)=lni=1k(1xi)1=i=1kj=1jxij=i=1kj=1jxij

我们只需要计算前 n + 1 n+1 n+1 项,因此求 ln ⁡ f ( x ) \ln f(x) lnf(x) 的复杂度为 O ( n log ⁡ k ) O(n\log k) O(nlogk)

最后多项式 exp ⁡ \exp exp 即可。总复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)

而根据 B n , k = B k ( n ) − B k − 1 ( n ) B_{n,k}=B_{k}(n)-B_{k-1}(n) Bn,k=Bk(n)Bk1(n) ,我们有 n n n k k k 分部划分的生成函数为

∑ n = 0 ∞ B n , k x n = ∑ n = 0 ∞ B k ( n ) x n − ∑ n = 0 ∞ B k − 1 ( n ) x n = ( 1 1 − x k − 1 ) 1 ∏ i = 1 k − 1 ( 1 − x i ) = x k ∏ i = 1 k ( 1 − x i ) \sum\limits_{n=0}^{\infty} B_{n,k}x^n=\sum\limits_{n=0}^{\infty} B_{k}(n)x^n-\sum\limits_{n=0}^{\infty} B_{k-1}(n)x^n=(\frac{1}{1-x^k}-1)\frac{1} {\prod_{i=1}^{k-1}(1-x^i)}=\frac{x^k} {\prod_{i=1}^{k}(1-x^i)} n=0Bn,kxn=n=0Bk(n)xnn=0Bk1(n)xn=(1xk11)i=1k1(1xi)1=i=1k(1xi)xk

求法与 k k k 划分是一样的。

根据 B n = B ∞ ( n ) B_n=B_{\infty}(n) Bn=B(n) n n n 划分数的生成函数为

∑ n = 0 ∞ B n x n = 1 ∏ i = 1 ∞ ( 1 − x i ) = 1 1 + ∑ i = 1 ∞ ( − 1 ) i x i ( 3 i ± 1 ) 2 \sum_{n=0}^{\infty}B_nx^n=\frac{1} {\prod_{i=1}^{\infty}(1-x^i)}=\frac{1}{1+\sum\limits_{i=1}^{\infty}(-1)^ix^{\frac{i(3i\pm1)} {2}}} n=0Bnxn=i=1(1xi)1=1+i=1(1)ix2i(3i±1)1

这里用到了五边形数。

可以使用 O ( n n ) O(n \sqrt n) O(nn ) 的递推或 O ( n log ⁡ n ) O(n\log n) O(nlogn) 的多项式求逆。但要注意这个问题不能转化为线性递推问题。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值