LOJ6089. 小 Y 的背包计数问题 题解
本题是一个背包计数问题,发现 ,显然普通的多重背包计数不可取,需要优化。
本着多重背包计数时间复杂度成本较高,我们总是希望尽量不做多重背包计数,发现对于编号 的物品,由于要装满背包,它们永远不可能用完,所以我们可以对其使用其它方法计数。故考虑一种类似于根号分治的思想,对编号不超过 和超过该值的物品分类讨论。
- 对于编号 的物品:
由于 数量级在我们接受范围内,故考虑直接使用多重背包计数,设 表明考虑只从前 个物品中取物品,取出的物品总体积为 的方案数,则不难列出方程:
可以使用滚动数组优化掉 那一维,又发现每次转移都是取 的值,可见每次取值都是各相邻 个位置取一次值,这样我们可以使用类似于前缀和优化的方式进行优化转移。(其实这里如果不使用滚动数组的话也可以,毕竟 那一维的大小已经被我们控制在了 ,而加上 那一维,空间复杂度为 也不会爆空间)
- 对于编号 的物品:
由于此类物品无法取完,故不用考虑每种物品取了多少个。我们发现这类物品我们最多只能取 个,故不妨设 为取 个此类物品,取出的这 个物品总体积为 的方案数。我们考虑如何列递推式,要想知道 ,就需要知道其可以由哪些状态变化而来,注意这里提到的状态必须保证计数不重(前驱状态和后续状态一一对应)不漏(不会少考虑情况) 。考虑到这两点后我们就来寻找这些状态吧 qwq
首先容易想到的是取 个物品的状态一定是可以由取 个物品的状态推出来的,但这时我们似乎需要枚举 到 所有值,这显然还是会超时,但我们发现一个有趣的事情是,如果我们取了一个体积大于 的物品,我们可以将其看成先取了一个体积为 的物品,再通过某种方式使物品的总体积“增长”到我们要的目标 ,考虑寻找增长的方式,由于前后状态必须一一对应,所以每次所有已选的物品的体积增长量必须相同,由于不能跳过某些状态,所以这个增长量只能为 1,所以我们就找到了一种增长的方法,使得这样计数不重不漏。
所以可以推出 的状态有两种:一种是已经取了 个物品,又取了一个体积为 的物品,达到了状态 ,即 ;一种是我们上文中所述的,将取体积大于 的物品的情况进行分解,将其分解为第一种状态与“增长”这两步,由于第一步在前面的状态中肯定会被当成第一种状态算进答案中,故我们只需考虑如何利用“增长”统计这部分答案,而正如上文所述,增长是要求每一个已选物品体积均增加 1,所以总体积增加 ,而已选物品数量是不会通过增长改变的,所以这一种可以推出 的状态为 。
综上,状态转移方程为:
由于我们将物品按编号分类讨论,所以我们最终要使用乘法原理合并答案,我们设 ,则答案为:
两部分时间复杂度均为 ,故总时间复杂度也为 。
下面是简短的代码qwq:
Code
复制#include <algorithm> #include <cmath> #include <cstdio> #include <cstring> const int maxn = 1e5 + 10; const int p = 23333333; int n, m, f[maxn], sum[maxn], g[320][maxn]; int main() { scanf("%d", &n); m = sqrt(n); f[0] = 1; for (int i = 1; i <= m; ++i) { for (int j = 0; j < i; ++j) sum[j] = f[j]; for (int j = i; j <= n; ++j) sum[j] = (f[j] + sum[j - i]) % p; for (int j = 0; j <= n; ++j) { if (j >= i * (i + 1)) f[j] = (sum[j] - sum[j - i * (i + 1)] + p) % p; else f[j] = sum[j]; } } g[0][0] = 1; int ans = f[n]; for (int i = 1; i <= m; ++i) { for (int j = i * (m + 1); j <= n; ++j)//根据 g 的定义 g[i][i * (m + 1)] 之前数组的值都应为 0,所以直接跳过 { g[i][j] = (g[i - 1][j - (m + 1)] + g[i][j - i]) % p; ans = (ans + 1ll * f[n - j] * g[i][j] % p) % p;//这里直接统计答案,但需注意 f[n] 无法在循环中统计到 } } printf("%d\n", ans); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!