分拆数的四种求法

· · 算法·理论

分拆数有四种求法,你知道吗?

定义: 记 P_n 为将 n 拆分成若干无序正整数的和的方案数。

模板题:loj 6268。n\le 10^5,答案对 998244353 取模。

例题:P6189 [NOI Online #1 入门组] 跑步(其实也是模板啦)

方法一

这个问题非常像完全背包。但 O(n^2) 过不去。考虑根号分治:

方法二

类似付公主的背包的做法。分拆数的 OGF 为

P(x)=\prod_{k=1}\sum_{i=0}x^{ik}=\prod_{k=1}\frac{1}{1-x^k}=\exp\sum_{k=1}\ln\frac{1}{1-x^k}=\exp\sum_{k=1}\sum_{i=1}\frac{x^{ik}}{i}

后面的求和可以 O(n\log n) 计算。具体见P4389 付公主的背包 题解

方法三

前置知识:五边形数

五边形数是能排成五边形的多边形数。

如图,前几项为 1,5,12,22\dots,其通项公式为 \frac{3n^2-n}{2}

广义五边形数: n 可以取负数,其通项公式为\frac{3n^2\mp n}{2}

五边形数定理

定义欧拉函数 \phi(x)

\begin{aligned} \phi(x)&=\prod_{i=1}(1-x^i)\\&=1-x-x^2+x^5+x^7-x^{12}-x^{15}+\dots\\ &=1+\sum\limits_{i=1}(-1)^ix^{i(3i\pm 1)/2} \end{aligned}

这条等式被称为五边形数定理。证明比较复杂,故不展开叙述。有兴趣的可以看 visit_world的博客

\phiP 乘起来

\begin{aligned} \phi(x)\sum_{k=0}^{\infty}p(k)x^k =& (1-x-x^2+x^5+x^7-\ldots)\\&(1+p(1)x+p(2)x^2+p(3)x^3+\ldots)\\ =& 1 \end{aligned}

将整个式子展开,得到:

p(k)-p(k-1)-p(k-2)+p(k-5)+p(k-7)-\ldots=0 ### 方法四 #### 前置知识:Ferrers diagram 一个分拆的 Ferrers 图,是把分拆出的每一项,用点(或方格)组成的行来表示。一般分拆写为递减正整数和,所以 Ferrers 图也用长度递减的行来表示。 Ferrers 图与分拆之间是一一对应的。如 14=6+3+3+2 的一个分拆的 Ferrers 图如下: ![img](https://cdn.luogu.com.cn/upload/image_hosting/wj6y5efz.png?x-oss-process=image/resize,m_lfit,h_420,w_625) 通过读它的列,得到的 Ferrers 图与原图互为共轭。 ##### 引申 * 对于所有行数不超过 $m$ 的 Ferrers 图,都唯一对应一个列数不超过 $m$ 的共轭图。因此整数 $n$拆分成 $m$ 个数的和的拆分数,和数 $n$ 拆分成最大数为 $m$ 的拆分数相等。 * 整数 $n$ 拆分成最多不超过 $m$ 个数的和的拆分数,和 $n$ 拆分成最大不超过 $m$ 的拆分数相等。 * 整数 $n$ 拆分成互不相同的若干奇数的和的拆分数,和 $n$ 拆分成自共轭的Ferrers图像的拆分数相等。例如:17=9+5+3 ![img](https://cdn.luogu.com.cn/upload/image_hosting/jpl3ofsh.png?x-oss-process=image/resize,m_lfit,h_420,w_625) 考虑从 Ferrers diagram 的原点引出一条 $y=x$ 的直线,它离开这个图的位置就框处了一个 $h \times h$ 的正方形,这个正方形被称为一个整数拆分的 Durfee square。 如果我们确认了正方形的边长是 $h$,它两侧放置的就都是 $\le h$ 的整数划分。因此我们得到了这样的表达式: $$ \prod_{k\ge1} \frac1{1-x^k} = \sum_{h\ge0} x^{h^2} \left(\prod_{k=1}^h \frac1{1-x^k}\right)^2 $$ 在计算前 $n$ 项时,由于 $h^2\le n$,枚举 $h$ 的上界为 $\sqrt n$,复杂度为 $O(n\sqrt n)$。 ```cpp #include<bits/stdc++.h> using namespace std; typedef long long ll; namespace FGF { int n,mo; const int N=1e5+5; int ans[N],tmp[N]; void work() { scanf("%d%d",&n,&mo); int b=sqrt(n); ans[0]=tmp[0]=1; for(int i=1;i<=b;i++) { for(int k=0;k<2;k++) for(int j=i;j<=n-i*i;j++) tmp[j]=(tmp[j]+tmp[j-i])%mo; for(int j=i*i;j<=n;j++) ans[j]=(ans[j]+tmp[j-i*i])%mo; } printf("%d\n",ans[n]); } } int main() { FGF::work(); return 0; } ``` ### 不会证的结论 * 对于 $n$ 的分拆,各个分拆方案中出现至少 $k$ 次的数的个数和,等于所有方案中 $k$ 出现的总次数。详细见[整数分拆中的一个出人意料的结论](http://www.matrix67.com/blog/archives/6348) * 对任意正整数,其奇分拆数目(每个部分均为奇数)等于其互异分拆(每个部分互不相同)数目。证明见《组合数学》 ### References * [多项式计数杂谈](https://www.luogu.com.cn/blog/command-block/sheng-cheng-han-shuo-za-tan) * [EI:分拆数的第三种计算方法](https://blog.csdn.net/EI_Captain/article/details/104729572) * 图片主要来自百度百科