Loading

整数划分模型

整数划分模型

经典问题

1:求把 n 划分成 k 个正整数的方案数?

2:求把 n 划分成互不相同 k 个正整数的方案数?

3:求把 n 划分成 k 个不大于 m 的互不相同正整数的方案数?

4:求把 n 划分成 k 个奇数的方案数?

发现这类为题都是把一个整数划分成 \(k\) 个有要求的正整数的方案数

先从简单开始,考虑最为暴力的Dp

状态:

\(dp[i][j][sum]\) 表示前 \(i\) 个数,和为 \(sum\) 的方案数是多少,答案就是 \(dp[n][k][n]\)

转移:

考虑下一个数选几个来转移, $ t $ 表示当前 \(i\) 这个数选了多少个

\[dp[i][j][sum] =max\lbrace dp[i-1][j-t][sum - t*i]\rbrace \]

时间复杂度

状态:\(n*k*n\)

转移: \(O(sum/i)\)

均摊的话: \(O(n*k*n*log(n))\)

本质是个完全背包,可以做到 \(O(n*k*n)\) 不会

接下来就是神仙操作了……

我们直接设 \(dp[i][j]\) 表示把 \(i\) 划分成 \(j\) 个数的方案数

可以得到下面这个式子:

\[dp[i][j]=dp[i-j][j]+dp[i-1][j-1] \]

???

咋来的??

\(i\) 分成 \(j\) 个数的方案数等于把 \(i-j\) 分成 \(j\) 个数的方案数+把 \(i-1\) 分成 \(j-1\) 个数的方案数

???

啥啊这是

这里单靠瞅式子已经不能说服自己了

上图

以下是 \(dp[22][4]\) 的两类情况: 考虑有没有 \(1\) 的部分

划分的数,分别对应着四个矩形的高度,第一个图是7,6,6,3 第二个图是7,7,7,1

考虑去掉蓝色的部分

发现左边去掉蓝色部分后状态成了 \(f[i - j][j]\)

右边去掉蓝色的部分后状态成了 \(f[i - 1][j - 1]\)

所以就不难看出:\(f[i][j]\) 是由 \(f[i-j][j]\)\(f[i-1][j-1]\) 转移过来的

来个栗题

T1

求把 \(n\) 划分成互不相同 \(k\) 个正整数的方案数

solution

同样先考虑暴力

状态:

\(dp[i][j][sum]\)\(i\) 个数,选了 \(j\) 个数,和为 \(sum\) 的方案数是多少

转移

考虑第 \(i\) 个数选不选

转移:

\[f[i][j][sum] = max\lbrace f[i-1][j-1][sum],f[i-1][j-1][sum-i]\rbrace \]

实际是就是个01背包

时间复杂度:

\(O(n*k*n)\)

正解

还是直接设 \(dp[i][j]\) 表示把 \(i\) 划分成 \(j\) 个数的方案数

\(dp[i][j]=dp[i-j][j]+dp[i-j][j-1]\)

考虑去掉蓝色的部分

同样要考虑 \(1\) 的情况,但与上题不同的是这里第一维是 \([i-j]\),表示当前数加上 \(j\) 这一行,并且新多了一行

因为是整行都加,所以就避免了重复的情况

T2

求把 \(n\) 划分成 \(k\) 个不大于 \(m\) 的互不相同正整数的方案数

背包方法和上题一个样,枚举第 \(i\) 个数选不选就好了;

而正解也只需要把超过 \(m\) 的那些不合法的删掉就好了

\(N = 20,k = 4,m = 6\) 不合法方案

\[dp[i][j]=dp[i-j][j]+dp[i-j][j-1]-dp[i-(m+1)][j-1] \]

最后一个的减法就是要把不合法的情况减掉,直接减掉不符合条件的那一列

看个栗题

给定一个杠杆,等距均匀分布一共 \(2*n+1\) 个等重质点,支点在 \(n+1\) 处,求拿走 \(k\) 个质点后使杠杆仍然保持平衡的方案数 \(mod~~p\) 的值

化简:

\(-n => n\) 中求选 \(k\) 个不同的数,和为 0 的方案数

solution

根据上面整数划分原理

求出来 \(f[i][j]\) 表示选出 \(j\) 个数和为 \(i\) 的方案数,然后枚举其中一端拿走几个 \(a\),以及拿走的数的重量之和 \(x\),把\(f[x][a]*f[x][k-a]\) 累加之和就是最后的答案了

然后就变成了上面的把 \(n\) 划分成互不相同 \(k\) 个正整数的方案数

\(f\) 的复杂度和统计答案的复杂度均是 \(O(n*k*k)\)

\(n\) 划分成 \(k\) 个奇数或者 \(k\) 个偶数的方案数

状态:

\(g[i][j]\) :将 \(i\) 划分为 \(j\) 个偶数

\(f[i][j]\): 将 \(i\) 划分为 \(j\) 个奇数

转移:

\(g[i][j] = f[i - j][j]\)

联想上面的图,偶数可以由将每个奇数减1就都成了偶数

\(f[i][j] = f[i - 1][j - 1] + g[i - j][j]\)

奇数的话

分两种情况

奇数有可能右边有个单独的1,这就可能由 \(f[i - 1][j - 1]\) 来转移过来(新填了一行正好有个单独的1)

当然一般情况为 \(g[i - j][j]\) 每个偶数-1转移过来

关于整数划分模型

就是分类讨论罢了,注意不要漏掉情况,也不能情况计算重叠(max,min可以重叠) ,每个 \(dp\) 值可以用以前的\(dp\) 值表示出来,保证要递归到已经求好的 \(dp\) 值中

posted @ 2021-02-07 17:39  Dita  阅读(205)  评论(0编辑  收藏  举报