Part 0. 前置知识

  • 简单的公式推导
  • 生成函数

大量数学公式警告

Part 1. 什么是五边形数

五边形数

看一张图吧:

XP 系统带的画图真的挺好用!

我们不难得出五边形数的数列:

P = { 1 , 5 , 12 , 22 , … } P = \{1, 5, 12, 22,\ldots\} P={1,5,12,22,…}

再找一下规律,我们就可以得到五边形数的通项公式:

P n = n ( 3 n − 1 ) 2 P_n = \frac{n(3n - 1)}{2} Pn​=2n(3n−1)​

似乎现在并没有什么用。。。

广义五边形数

也就是当 n n n 可以为负数的时候的五边形数序列,它的通项公式为:

P n = n ( 3 n ± 1 ) 2 P_n = \frac{n(3n \pm 1)}{2} Pn​=2n(3n±1)​

Part 2. 五边形数定理

定义欧拉函数(注意不要把它看成数论里面的欧拉函数)为:

ϕ ( n ) = ∏ i = 1 ∞ ( 1 − x i ) \phi (n) = \prod\limits_{i = 1}^{\infty} (1 - x^i) ϕ(n)=i=1∏∞​(1−xi)

则五边形数定理就是:

ϕ ( n ) = ∏ i = − ∞ ∞ ( − 1 ) i x i ( 3 i − 1 ) 2 = 1 + ∏ i = 0 ∞ ( − 1 ) i x i ( 3 i ± 1 ) 2 \phi (n) = \prod\limits_{i = -\infty}^{\infty}(-1)^ix^{\frac{i(3i - 1)}{2}} = 1 + \prod\limits_{i = 0}^{\infty}(-1)^ix^{\frac{i(3i \pm 1)}{2}} ϕ(n)=i=−∞∏∞​(−1)ix2i(3i−1)​=1+i=0∏∞​(−1)ix2i(3i±1)​

证明等一会给出。

Part 3. Ferrers 图

Ferrers 图是一个由 k k k 行的点阵构成的方格图,要求上一行的格子数目不超过它下面一行的格子的数目,其中总和为 n n n 的数量。

举个例子:( n = 20 n = 20 n=20 时 的一个图,我用 @ 来表示一个格子)

@@@@@@
@@@@@
@@@@
@@@
@@

我们记这时的第 k k k 行的格子数量为 m m m, s s s 为第一行最右边的 @ 右上角的对角线格子数量。

定义一种变换:

  • 当 m > s m > s m>s 时, 把最右边的对角线上的格子扔到新的一行。
  • 当 m ≤ s m \le s m≤s 时,把最后一行的所有格子分给从第一行开始的每行上,每行分到一个格子。

举个例子:(用 $ 表示被移走的格子)

@@@@@@@@        @@@@@@@@$
@@@@@@@         @@@@@@@$
@@@@@    <=>    @@@@@
@@@             @@@
$$

不难看出这个操作是显然可逆的。

这个操作还有一些性质:

我们对一个 Ferrers 图进行连续的两次变换后,它会变回它本身。

如果我们仅进行一次变换,那么行数的奇偶性可以改变。

Part 4. 五边形数定理的证明

我们将 ϕ ( n ) \phi(n) ϕ(n) 的定义式展开之后可以发现,第 n n n 项的系数应该是将 n n n 划分成偶数个互不相同的正整数的答案减掉将 n n n 划分成奇数个互不相同的正整数方案,每一项的系数应该都是 0 0 0。但实际操作后发现有些项前面是有系数的。

那么我们考虑仔细研究一下 Ferrers 图。


当 m = s + 1 m = s + 1 m=s+1 时,且底层的最右边的元素与对角线相遇,如下:

@@@@@@    @@@@@
@@@@@  => @@@@
@@@@      @@@@@@

发现此时无法操作回去了。这是一个不合法的状态。

令 t = 1 − m t = 1 - m t=1−m,可以得到 n = ( 1 − t ) + ( 2 − t ) + ( 3 − t ) + ⋯ + ( − 2 t ) = t ( 3 t − 1 ) 2 n = (1 - t) + (2 - t) + (3 - t) + \cdots + (-2t) = \frac{t(3t - 1)}{2} n=(1−t)+(2−t)+(3−t)+⋯+(−2t)=2t(3t−1)​,这一项对答案的贡献为 ( − 1 ) t (-1) ^ t (−1)t。


当 m = s m = s m=s,且底层的最右边的元素与对角线相遇,如下:

@@@@@    @@@@@@
@@@@  => @@@@@
@@@      @

这个显然是不合法的,令 t = m t = m t=m,可以得到 n = t + ( t + 1 ) + ( t + 2 ) + ⋯ + 2 t = t ( 3 t + 1 ) 2 n = t + (t + 1) + (t + 2) + \cdots + 2t = \frac{t(3t + 1)}{2} n=t+(t+1)+(t+2)+⋯+2t=2t(3t+1)​,对第 n n n 项的贡献为 ( − 1 ) t (-1) ^ t (−1)t。


这样一来,当 n = k ( 3 k ± 1 ) 2 n = \frac{k(3k \pm 1)}{2} n=2k(3k±1)​ 时,即 n n n 是一个广义五边形数时, n n n 的奇偶拆分就在抵消之后留下一项。所以五边形定理成立。

Part 5. 整数划分问题

问题概要

将一个整数 n n n 划分成任意个可以相等的整数,求方案数。

分析

我们不难写出一个 O ( n 2 ) O(n^2) O(n2) 的 DP 来解决整数划分问题。但当 n n n 超过 1 0 4 10^4 104 之后就跑不动了。

考虑高效解法 (利用五边形数定理)

定义函数 P ( i ) P(i) P(i) 为将 n n n 拆分成若干个可以相等的整数的方案数。

考虑 P ( i ) P(i) P(i) 的生成函数 F ( x ) F(x) F(x):

F ( x ) = ∑ i = 1 ∞ P ( i ) x i = ∏ i = 1 ∞ ( x 0 + x i + x 2 i + ⋯ ) = ∏ i = 1 ∞ 1 1 − x i \begin{aligned} F(x) & = \sum\limits_{i = 1}^{\infty}P(i)x^i \\ &= \prod\limits_{i = 1}^{\infty}(x^0 + x^i + x^{2i} + \cdots) \\ & =\prod\limits_{i = 1}^{\infty} \frac{1}{1 - x^i} \end{aligned} F(x)​=i=1∑∞​P(i)xi=i=1∏∞​(x0+xi+x2i+⋯)=i=1∏∞​1−xi1​​

再看一下上面提到的欧拉函数:

ϕ ( x ) = ∏ i = 1 ∞ ( 1 − x i ) \phi(x) = \prod\limits_{i = 1}^{\infty} (1 - x^i) ϕ(x)=i=1∏∞​(1−xi)

显然可以得到: F ( x ) ⋅ ϕ ( x ) = 1 F(x)\cdot\phi(x) = 1 F(x)⋅ϕ(x)=1。

然后根据五边形数定理将 ϕ ( x ) \phi(x) ϕ(x) 代入:

[ ∑ i = 1 ∞ P ( i ) x i ] ⋅ ( ∑ i = 0 ∞ 1 + ∏ i = 0 ∞ ( − 1 ) i x i ( 3 i ± 1 ) 2 ) = 1 \left[\sum\limits_{i = 1}^{\infty}P(i)x^i\right] \cdot \left(\sum\limits_{i = 0}^{\infty}1 + \prod\limits_{i = 0}^{\infty}(-1)^ix^{\frac{i(3i \pm 1)}{2}}\right) = 1 [i=1∑∞​P(i)xi]⋅(i=0∑∞​1+i=0∏∞​(−1)ix2i(3i±1)​)=1

直接暴力展开可以得到:

P ( n ) − P ( n − 1 ) − P ( n − 2 ) + P ( n − 5 ) + P ( n − 7 ) − ⋯ = 0 P(n) - P(n - 1) - P(n - 2) + P(n - 5) + P(n - 7) - \cdots = 0 P(n)−P(n−1)−P(n−2)+P(n−5)+P(n−7)−⋯=0

不难发现减去的每一项都是广义五边形数。于是直接暴力计算即可。

由于五边形数 p n = n ( 3 n ± 1 ) 2 p_n = \frac{n(3n \pm 1)}{2} pn​=2n(3n±1)​ 的增长速度为 O ( n 2 ) O(n ^ 2) O(n2)。所以最多枚举不超过 O ( n ) O(\sqrt n) O(n ​) 项五边形数就可以退出循环,故时间复杂度为 O ( n n ) O(n\sqrt n) O(nn ​)。

Part 6. 例题

HDU 4651

题目大意

求将正整数 n n n 划分成多个正整数的和的方案数。

分析

就是一个模板了。。。好好看一看上面的就可以了。

HDU 4658

题目大意

将一个正整数 n n n 划分为多个正整数的和的方案数,但每个数的使用次数不能够大于等于 k k k 次。

分析

记这种方式下的划分数为 P ′ ( n ) P'(n) P′(n)。先给出生成函数 G ( x ) = ∏ i = 1 ∞ ( 1 + x i + x 2 i + ⋯ + x ( k − 1 ) i ) G(x) = \prod\limits_{i = 1}^{\infty}(1 + x^i + x^{2i} + \cdots + x^{(k - 1)i}) G(x)=i=1∏∞​(1+xi+x2i+⋯+x(k−1)i)。

尝试化简:

G ( x ) = ∏ i = 1 ∞ 1 + x i + x i + x i + ⋯ 1 + x k i + x 2 k i + x 3 k i + ⋯ = ∏ i = 1 ∞ 1 1 − x i 1 1 − x k i = ∏ i = 1 ∞ 1 − x k i 1 − x i = ϕ ( x k ) ϕ ( x ) = ϕ ( x k ) ⋅ F ( x ) \begin{aligned} G(x) & = \prod\limits_{i = 1}^{\infty}\frac{1+ x^i + x^i + x^i + \cdots}{1 + x^{ki} + x^{2ki} + x^{3ki} + \cdots} \\ & = \prod_{i = 1}^{\infty}\frac{\frac{1}{1 - x^i}}{\frac{1}{1 - x^{ki}}} \\ & = \prod_{i = 1}^{\infty}\frac{1 - x^{ki}}{1 - x^i} \\ & = \frac{\phi(x^k)}{\phi(x)} \\ & = \phi(x^k) \cdot F(x) \end{aligned} G(x)​=i=1∏∞​1+xki+x2ki+x3ki+⋯1+xi+xi+xi+⋯​=i=1∏∞​1−xki1​1−xi1​​=i=1∏∞​1−xi1−xki​=ϕ(x)ϕ(xk)​=ϕ(xk)⋅F(x)​

然后暴力展开 ϕ ( x k ) ⋅ F ( x ) \phi(x^k) \cdot F(x) ϕ(xk)⋅F(x) 得到:

∑ i = 1 ∞ P ′ ( i ) x i = ( 1 − x k − x 2 k + x 5 k + ⋯ ) [ 1 + P ( 1 ) x + P ( 2 ) x 2 + ⋯ ] \sum\limits_{i = 1}^{\infty}P'(i)x^i = (1 - x^k - x^{2k} + x^{5k} + \cdots)[1 + P(1)x + P(2)x^2 + \cdots] i=1∑∞​P′(i)xi=(1−xk−x2k+x5k+⋯)[1+P(1)x+P(2)x2+⋯]

然后可以得到 P ′ ( i ) = P ( i ) − P ( i − k ) − P ( i − 2 k ) + P ( i − 5 k ) + ⋯ P'(i) = P(i) - P(i - k) - P(i - 2k) + P(i - 5k) + \cdots P′(i)=P(i)−P(i−k)−P(i−2k)+P(i−5k)+⋯

于是就可以在 O ( n ) O(\sqrt n) O(n ​) 的时间内回答询问了,总时间复杂度为 O ( n n + T n ) O(n\sqrt n + T\sqrt n) O(nn ​+Tn ​)。

参考代码

HDU 4651

#include <cstdio>
#include <algorithm>
using namespace std;typedef long long ll;
const int Maxn = 1e5;
const ll Mod = 1000000007;ll f[Maxn * 2 + 5];
ll p[Maxn + 5];
void Init() {for(int i = -Maxn; i <= Maxn; i++)f[i + Maxn] = 1LL * i * (i * 3 - 1) / 2;//计算五边形数p[0] = 1;for(int i = 1; i <= Maxn; i++)for(int j = 1; j <= i; j++) {if(f[j + Maxn] <= i) {if(j & 1) p[i] = (p[i] + p[i - f[j + Maxn]]) % Mod;else p[i] = (p[i] - p[i - f[j + Maxn]] + Mod) % Mod;} else break;//根据 j 的奇偶性来判断当前应该加还是应该减if(f[Maxn - j] <= i) {if(j & 1) p[i] = (p[i] + p[i - f[Maxn - j]]) % Mod;else p[i] = (p[i] - p[i - f[Maxn - j]] + Mod) % Mod;} else break;}
}int main() {#ifdef LOACLfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
#endifInit();int _;scanf("%d", &_);while(_--) {int n;scanf("%d", &n);printf("%lld\n", p[n]);}return 0;
}

HDU 4658

#include <cstdio>
#include <algorithm>
using namespace std;typedef long long ll;
const int Maxn = 1e5;
const ll Mod = 1e9 + 7;ll f[Maxn * 2 + 5];
ll p[Maxn + 5];
ll ans[Maxn + 5];
void Init() {for(int i = -Maxn; i <= Maxn; i++)f[i + Maxn] = 1LL * i * (3 * i - 1) / 2;p[0] = 1;for(int i = 1; i <= Maxn; i++)for(int j = 1; j <= i; j++) {if(f[j + Maxn] <= i) {if(j & 1) p[i] = (p[i] + p[i - f[j + Maxn]]) % Mod;else p[i] = (p[i] - p[i - f[j + Maxn]] + Mod) % Mod;} else break;if(f[Maxn - j] <= i) {if(j & 1) p[i] = (p[i] + p[i - f[Maxn - j]]) % Mod;else p[i] = (p[i] - p[i - f[Maxn - j]] + Mod) % Mod;} else break;}
}ll Solve(int n, int k) {ll ret = p[n], dir = -1;for(int i = 1; ; i++) {ll val1 = 1LL * k * i * (3 * i - 1) / 2,val2 = 1LL * k * i * (3 * i + 1) / 2;if(val1 > n && val2 > n) break;if(val1 <= n) ret = (ret + dir * p[n - val1] + Mod) % Mod;if(val2 <= n) ret = (ret + dir * p[n - val2] + Mod) % Mod;dir *= -1;}return ret;
}int main() {#ifdef LOACLfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
#endifInit();int _;scanf("%d", &_);while(_--) {int n, k;scanf("%d %d", &n, &k);printf("%lld\n", Solve(n, k));}return 0;
}

【生成函数】五边形数定理与整数划分问题详解相关推荐

  1. 力扣13 罗马数字转整数逻辑详解

    力扣 13 .罗马数字转整数逻辑详解 题目详情 逻辑分析 代码实现 题目详情 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 1 ...

  2. 算法问题:整数除法详解(Java方向)

    算法问题:整数除法详解(Java方向) 1.力扣题目 2.结果代码分析 3.完整的结果代码 4.代码出处和教学出处 5.博主 边学习边记录算法的学习 1.力扣题目 1.给定两个整数 a 和 b ,求它 ...

  3. 如何判断立即数的合法性?(详解详析)

    如何判断立即数的合法性?(详解详析) <ARM体系结构与编程>一书中对立即数有这样的描述:每个立即数由一个8位的常数循环右移偶数位得到. 一个32位的常数,只有能够通过上面构造方法得到的才 ...

  4. 五边形数定理与拆分数

    只做梳理,不做证明 (因为不会证) 五边形数 图片摘自百度百科. 可以发现, g i = g i − 1 + 3 ( i − 1 ) + 1 g_i=g_{i-1}+3(i-1)+1 gi​=gi−1 ...

  5. hive linux进程数,控制Hive MAP个数详解

    控制Hive MAP个数详解 Hive的MAP数或者说MAPREDUCE的MAP数是由谁来决定的呢?inputsplit size,那么对于每一个inputsplit size是如何计算出来的,这是做 ...

  6. 数通--交互技术--STP+RSTP详解

    交互技术–STP+RSTP详解 STP: 一.作用: 1.解决环路(广播风暴.Mac地址表震荡) 2.实现链路备份的目的 二.stp流程(原理): 1.选举一个根桥 (优先级=BID<0-655 ...

  7. 【原】费马小定理(Fermat little theorem)详解

    Fermat定理: 如果P是任意一个不能整除整数a的素数,则  之后我会展示一些用到这一经典定理的算法. 例如: , 等等 证明: 考虑a的倍数:   (1) 证明这些整数中任意两个都不能模p同余. ...

  8. C语言经典回溯算法之解决数的组合问题(详解)

    文章目录 一.回溯算法 二.数的组合问题 一.回溯算法 1.回溯法 也叫试探法,实际上是一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就"回溯&q ...

  9. 200 300的完数 c语言,C语言求完数(完全数)(详解版)

    问题描述 求某一范围内完数的个数. 如果一个数等于它的因子之和,则称该数为"完数"(或"完全数").例如,6的因子为1.2.3,而 6=1+2+3,因此6是&q ...

最新文章

  1. 使用AngularJS上传文件
  2. Apache与Tomcat整合
  3. lua运行外部程序_LTUI v2.2 发布, 一个基于lua的跨平台字符终端UI界面库
  4. Python正则表达式笔记
  5. 玩转运维编排服务的权限:Assume Role+Pass Role
  6. java连接kafka接收不到数据_Kafka客户端无法接收消息
  7. jQuery 1.11 / 2.1 beta 版发布
  8. 在新窗口中打开链接 javascript
  9. Json Formatter 1.0 Json格式化工具
  10. linux centos erlang,CentOS 7.7安装Erlang和Elixir
  11. Java-JVM第一篇认识JVM
  12. vs2008/vs2010新手快速入门必读教程
  13. hmcl手机版_hmcl启动器app下载
  14. ch2 gpio应用:Buzzer封装
  15. 微信小程序-icon图标
  16. 五子棋AI算法(一)
  17. 传奇清理服务器信息,传奇行会信息等清除问题
  18. 导入导出专栏(poi,jxls)
  19. 火狐linux 32位,火狐浏览器下载电脑版32位
  20. 2015阿里校园招聘笔试题(8.29 测试开发工程师)

热门文章

  1. 企业老总亲自回答:计算机视觉方向今年招聘情况怎么样?是否已经人才过剩?...
  2. 西安Java培训 | java设计模式之工厂设计模式
  3. 李亚涛:python中文如何转换成拼音?
  4. React 官方纪录片:我们亲手将 JSX 推向神坛!
  5. linearlayout靠右显示
  6. 【QT从零开始系列12】QT学习心得及资源汇总
  7. linux恢复bios出厂设置密码,笔记本bios恢复出厂设置方法【图文详解】
  8. Ubuntu16.04配置高端霸气VIM
  9. 等待队列、工作队列、消息队列的区别和用法
  10. xp系统打印机服务器不可用,xp系统使用打印机服务提示“打印不成功”的步骤介绍...