【题解】整数划分 [51nod1201] 整数划分 V2 [51nod1259]

传送门:整数划分 \([51nod1201]\) 整数划分 \(V2\) \([51nod1259]\)**

【题目描述】

\(【T1】\)

将整数 \(N\) 划分为若干个不同整数的和,有多少种不同的划分方式,答案对 \(10^9 + 7\) 取模。

例:\(n=6\),\(n\) 可划分为 \(\{6\} \{1,5\} \{2,4\} \{1,2,3\}\) 共 \(4\) 种。

【样例】

样例输入:
6 样例输出:
4

【数据范围】

\(100\%\) \(1 \leqslant N \leqslant 50000\)


\(【T2】\)

将 \(N\) 划分为若干个整数的和,有多少种不同的划分方式,答案对 \(10^9 + 7\) 取模。

例:\(n=4\),\(n\) 可划分为 \(\{4\} \{1,3\} \{2,2\} \{1,1,2\} \{1,1,1,1\}\) 共 \(5\) 种。

【样例】

样例输入:
4 样例输出:
5

【数据范围】

\(100\%\) \(1 \leqslant N \leqslant 50000\)


【分析】

【球盒问题】

这两道题实际上是一种球盒问题的变型。

球盒问题见隔壁 【学习笔记】薛定谔的喵咪 \(Cat\) \(—\) 球盒问题(全详解)

先来看 \(T2\),想象一下,有 \(n\) 个 \(1\) 整整齐齐地站成一排,你可以将其划分为 \(m\) 个区间,其中 \(m \in [1,n]\)。实际上就是要把 \(n\) 个相同的球放进 \(m\) 个相同的盒子,盒子不可为空。

可以发现,如果随意放的话,会有大量的重复情况。而每一种分配方式都可以将盒子按照球的数量从大到小排序,排出来一个非严格降序(或升序)的序列。所以,每次为新的盒子分配时,只要分配的球数小于等于上一次的分配球数,就可以保证不重不漏。

设 \(dp[i][j]\) 表示将 \(j\) 个球放入 \(i\) 个盒子的方案数。

\(dp\) 方程为: \(dp[i][j]=dp[i−1][j−1]+dp[i][j−i]\) 。

用简单一些的方式来理解(我也不知道是否严谨,数学证明见隔壁):

\(dp[i-1][j-1]\) 指的是新的盒子 \(i\) 里面只放了一个球。

\(dp[i][j-i]\) 指的是在所有已经分好的 \(i\) 个盒子里面都多放一个球。

那么 \(T1\) 呢?由于同一整数只能用一次,即任意两个盒子里面不能放入相同数量的球,那么降序排列后就应该是严格单调下降的,新盒子所分配的球数需要小于上一次的分配球数。

多了一些限制,还是一样的状态表示,\(dp[i][j-i]\) 方程中的仍可保留。

而 \(dp[i-1][j-1]\) 出现了一个问题:每次都在新盒子中放 \(1\) 会触犯到限制。但如果先把前面 \(i-1\) 个盒子都加 \(1\),新盒子就可以放 \(1\) 了,所以改为 \(dp[i-1][j-(i-1)-1]\) 。

\(dp\) 方程为:\(dp[i][j]=dp[i−1][j−i]+dp[i][j−i]\) 。

【背包问题】

用背包也可以做做。

将 \(1,2,3,4...n\) 使作 \(n\) 个不同的物品,其编号就是体积。

用 \(dp[j]\) 表示选了总体积为 \(V\) 的物品的方案数,正序枚举 \(i\) 的同时保证了物品的选择保持单调不下降态,至于后面的 \(j\),两道题用不同的做法。

\(T1\) 倒序枚举,即 \(01\) 背包。\(T2\) 正序枚举,即完全背包。

\(dp\) 方程均为:\(dp[j]+=dp[j-i]\) 。


但以上两种做法时间复杂度均为是 \(O(n^2)\),需要想办法优化。


【优化加速】

【T1】

考虑【球盒问题】的优化。

如果尽量让每个盒子中的球数最小,那么选出来的盒子那么选出来的升序序列就是这样子的:\(1,2,3...n\),而使用的盒子数量最大值就是此时的 \(m\)。

序列之和 \(\frac {m(m+1)}{2}=n\),\(m\) 算出来大概是 \(\sqrt{2n}+1\),所以枚举盒子数时只需要枚举 \(1\) 到 \(m\) 就可以了。

时间复杂度为 \(O(n\sqrt{2n})\)

【T2】

由于可以重复分配某一数量的球,盒子数最大可以达到 \(n\) (全部都只放一个),\(T1\) 的优化不再适用。

考虑分成 \([1,m-1],[m,n]\) 两块计算。

即分别算出只使用某块以内的数来组成 \(n\) 的方案数,然后乘法原理再求和即可。

前面部分就用【完全背包】,不多废话。

后面部分用【球盒问题】解决。

由于可以选的数大于等于 \(m\),所用盒子数量必定小于等于 \(\lceil \frac{n}{m}\rceil\),因此盒子数量只需要枚举 \([1,\lceil \frac{n}{m}\rceil]\)。

只是这次可选的最小数变成了 \(m\) 而不是 \(1\),所以将 \(dp[i-1][j-1]\) 改成 \(dp[i-1][j-m]\),即在新的盒子 \(i\) 里面放 \(m\) 个球。

\(dp\) 方程为:\(dp[i][j]=dp[i−1][j−m]+dp[i][j−i]\) 。

总时间复杂度为 \(O(n(m+\frac{n}{m}))\)。

由均值不等式可知:\(m+\frac{n}{m} \geqslant 2\sqrt{m*\frac{n}{m}} = 2\sqrt{n}\),当且仅当 \(m=\frac{n}{m}\) 时等号成立,所以 \(m\) 取 \(\sqrt{n}+1\) 即可(老师说每次使用 \(sqrt\) 时都要注意精度误差,在后面加个 \(1\) 比较保险)。


【Code】

【T1】

#include<algorithm>
#include<cstdio>
#include<cmath>
#define Re register int
const int N=5e4+3,P=1e9+7;
int n,m,ans,dp[320][N];
int main(){
scanf("%d",&n);m=sqrt(2*n)+1;
dp[0][0]=1;
for(Re i=1;i<=m;++i)
for(Re j=i;j<=n;++j)
(dp[i][j]=(dp[i-1][j-i]+dp[i][j-i])%P)%=P;
for(Re i=1;i<=m;++i)(ans+=dp[i][n])%=P;
printf("%d",ans);
}

【T2】

#include<algorithm>
#include<cstdio>
#include<cmath>
#define Re register int
const int N=5e4+3,P=1e9+7;
int n,m,ans,f2[250][N],ans1[N],ans2[N];
int main(){
scanf("%d",&n);m=sqrt(n)+1;
ans1[0]=1;
for(Re i=1;i<m;++i)
for(Re j=i;j<=n;++j)
(ans1[j]+=ans1[j-i])%=P;
f2[0][0]=ans2[0]=1;
for(Re i=1;i<=m;++i)
for(Re j=m;j<=n;++j){//j>=i&&j>=m,又因为i<=m所以j从m开始枚举
(f2[i][j]+=(f2[i-1][j-m]+f2[i][j-i])%P)%=P;
(ans2[j]+=f2[i][j])%=P;
}
for(Re i=0;i<=n;++i)(ans+=(long long)ans1[i]*ans2[n-i]%P)%=P;
printf("%d",ans);
}

【题解】整数划分 [51nod1201] 整数划分 V2 [51nod1259]的更多相关文章

  1. 【LeetCode题解】7_反转整数

    目录 [LeetCode题解]7_反转整数 描述 方法一 思路 Java 实现 类似的 Java 实现 Python 实现 方法二:转化为求字符串的倒序 Java 实现 Python 实现 [Leet ...

  2. pick定理:面积=内部整数点数+边上整数点数/2-1

    //pick定理:面积=内部整数点数+边上整数点数/2-1 // POJ 2954 #include <iostream> #include <cstdio> #include ...

  3. 转:int整数除以int整数一定得到的是int整数(易忽视)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/u014053368/article/de ...

  4. 题解 [51nod1201] 整数划分

    题面 解析 首先,因为是不同的数字, 可以从小到大依次枚举加上每一个数字的贡献,再枚举每个数. 然而这样会T掉... 考虑到\(n\)只有\(50000\), 当分成的数最多时,设最大的数为\(m\) ...

  5. 51nod1201 整数划分

    01背包显然超时.然后就是一道神dp了.dp[i][j]表示j个数组成i的方案数.O(nsqrt(n)) #include<cstdio> #include<cstring> ...

  6. 力扣(LeetCode)整数形式的整数加法 个人题解

    对于非负整数 X 而言,X 的数组形式是每位数字按从左到右的顺序形成的数组.例如,如果 X = 1231,那么其数组形式为 [1,2,3,1]. 给定非负整数 X 的数组形式 A,返回整数 X+K 的 ...

  7. 洛谷 题解 P1025 【数的划分】

    将n个小球放到k个盒子中的情况总数 = (a)至少有一个盒子只有一个小球的情况数 + (b)没有一个盒子只有一个小球的情况数 这样写出表达式: a.因为盒子不加区分,那么=情况数与"将n-1 ...

  8. 题解0005:数的划分(洛谷P1025)

    题目描述:将整数 n 分成 k 份,每份不能为空,颠倒顺序的被看成一种分法. 题目链接:https://www.luogu.com.cn/problem/P1025 题目思路:深搜剪枝,规定搜索的下一 ...

  9. 编写一个js函数,该函数有一个n(数字类型),其返回值是一个数组,该数组内是n个随机且不重复的整数,且整数取值范围是[2,32]

    首先定义个fn用来返回整数的取值范围: function getRand(a,b){ var rand = Math.ceil(Math.random()*(b-a)+a); return rand; ...

随机推荐

  1. linux pid文件

    在Linux系统的目录/var/run下面一般我们都会看到很多的*.pid文件 作用 防止进程启动多个副本 有写入权限(F_WRLCK)的进程才能正常启动并把自身的PID写入该文件中 fcntl in ...

  2. SqlServer数据库之递归

    递归的实现比较简单,这里就直接贴SQL了. --简单创建一个用户表 CREATE TABLE User( UserID ,) , ParentUserID INT ) 假设这张有几千条数据,开始递归它 ...

  3. HTTP的发展历史和各个版本差别

    HTTP前世今生 1989年,蒂姆·伯纳斯-李发表论文确立了三项关键技术: URI: 统一资源标志符,作为互联网上资源的唯一身份 HTML: 超文本标记语言,描述超文本文档 HTTP: 超文本传输协议 ...

  4. python之pip安装软件包常用命令

    # pip版本号查询 pip -V # 安装软件包.格式:pip install 软件包名 pip install pygame # 安装指定版本号的软件包.格式:pip install 软件包==软 ...

  5. django logger转载

    https://www.cnblogs.com/jiangchunsheng/p/8986452.html https://www.cnblogs.com/jeavy/p/10926197.html ...

  6. MySQL数据库(一)-- 数据库介绍、MySQL安装、基础SQL语句

    一.数据库介绍 1.什么是数据库 数据库即存储数据的仓库 2.为什么要用数据库 (1)用文件存储是和硬盘打交道,是IO操作,所以有效率问题 (2)管理不方便 (3)一个程序不太可能仅运行在同一台电脑上 ...

  7. python接口自动化17-multipart/form-data表单提交

    前言 multipart/form-data这种格式官方文档给的参考案例比较简单,实际情况中遇到会比较复杂,本篇讲解multipart/form-data的表单如何提交,非图片上传 禅道提交bug 1 ...

  8. CNCF LandScape Summary

    CNCF Cloud Native Interactive Landscape 1. App Definition and Development 1. Database Vitess:itess i ...

  9. 小学四则运算口算练习app---No.2

    经过昨天的了解,虽然还是很懵,总要下手摸到鼠标来写第一个页面! 这是一开始设置出体数目和时间的页面,使用者根据提示进行相关设置即可! 代码如下: <?xml version="1.0& ...

  10. CentOS7.5 系统最小化安装与初始化配置

    CentOS7.5 系统最小化安装与初始化配置 1.安装标准化的系统 1.1.系统安装期间的语言 选择:中文-简体中文,安装完成也会默认支持中文输出,便于管理 1.2.时区选择 亚洲上海,CST时区( ...