F - Diversity
F - Diversity
Problem Statement
There are products for sale in a store. The -th product has a price of yen, a utility value of , and a color .
You will choose some subset of these products to buy (possibly none). The total price of the chosen products must be at most yen.
Your satisfaction is , where is the sum of utilities of the chosen products, and is the number of distinct colors among the chosen products. Here, is a given constant.
You will choose products to maximize your satisfaction. Find the maximized satisfaction.
Constraints
- All input values are integers.
Input
The input is given from Standard Input in the following format:
Output
Print the answer.
Sample Input 1
3 10 5
1 3 1
7 4 2
4 5 1
Sample Output 1
17
If you buy the 1st and 2nd products, the total utility is , and the number of distinct colors is . Thus, your satisfaction is . No purchase plan makes your satisfaction or greater, so the answer is .
Sample Input 2
5 30 3
5 4 3
11 20 1
9 10 4
7 5 2
16 15 4
Sample Output 2
44
If you buy the 2nd, 3rd, and 4th products, the total utility is , and the number of distinct colors is . Thus, your satisfaction is . No purchase plan makes your satisfaction or greater, so the answer is .
Sample Input 3
22 75 6426
9 309 9
5 470 5
17 481 12
27 352 14
1 191 18
7 353 20
9 99 15
20 401 17
46 434 19
11 459 22
10 317 19
15 440 18
17 438 19
25 461 22
5 320 22
1 476 21
11 315 3
8 112 9
11 438 13
19 362 8
10 422 13
10 152 21
Sample Output 3
67717
解题思路
还是挺容易想到按照颜色分组然后 dp,定义 表示从前 种颜色的物品中选出总价格不超过 的所有方案中能获得的最大价值。
不过赛时不知道怎么转移,就对每个分组求一次 01 背包。定义 表示从颜色为 的前 个物品中选出总价格不超过 的所有方案中能获得的最大价值。这样 就能通过 进行转移( 表示颜色 的物品数量),转移方程就是 ,显然整个 dp 的复杂度是 会超时。
事实上并没有那么麻烦,不过题解给出的转移方法我就是想不到。为了更好的描述,这里重新定义状态 表示从前 种颜色以及第 种颜色的前 个中的物品中选出总价格不超过 的所有方案中能获得的最大价值。根据第 种颜色的第 个物品是否选择以及是否为首次选择该颜色物品进行状态划分,状态转移方程就是 。
其实这个有点类似于分组背包问题,不过不同的地方在与本问题中每个分组的物品可以任意选择。另外题解中把上述状态的第二维优化掉了,需要注意的是优化后要从大到小枚举价格 来转移,以避免与 01 背包类似的问题。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 505, M = 50005;
vector<array<int, 2>> g[N];
LL f[N][M];
int main() {
int n, m, k;
cin >> n >> m >> k;
for (int i = 0; i < n; i++) {
int v, w, c;
cin >> v >> w >> c;
g[c].push_back({v, w});
}
for (int i = 1; i <= n; i++) {
memcpy(f[i], f[i - 1], m + 1 << 3);
for (auto &[v, w] : g[i]) {
for (int j = m; j >= v; j--) {
f[i][j] = max(f[i][j], f[i - 1][j - v] + w + k);
f[i][j] = max(f[i][j], f[i][j - v] + w);
}
}
}
cout << f[n][m];
return 0;
}
参考资料
Editorial - Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383):https://atcoder.jp/contests/abc383/editorial/11543
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18605240
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效