NC14704 美味菜肴

题目链接

题目

题目描述

小明是个大厨,早上起来他开始一天的工作。他所在的餐厅每天早上都会买好 n 件食材(每种食材的数量可以视为无限),小明从到达餐厅开始就连续工作 T 时间。每道菜肴的制作需要特定的一种食材以及一段时间,但是食材一旦放久就不新鲜了,菜的美味值会降低。第 i 道菜肴有三个属性 ai,bi,ciai 是该菜肴的美味值,bi 是该菜肴所选食材不新鲜的速率,如果在第 t 时刻完成第 i 道菜则美味值为:aitbi,完成这道菜需要 ci 的时间。小明希望在这 T 时间内能做出菜肴使得总美味值最大,所以小明求助于你。

输入描述

第1行输入三个整数 n,m,T ,分别代表食材种类,菜肴种类和工作时间。
第2行输入 n 个整数 bi ,代表第 i 个食材不新鲜的速率。
接下来的m行,每行输入三个整数 j,ai,ci ,分别代表第 i 道菜肴需要的食材编号,菜肴的美味值,完成时间。
数据保证:0<n,m50,0<jn ,其他值均 <106 ,美味值必须通过完整做出菜肴得到,数据保证在规定时间内至少能完整做出1道菜肴。

输出描述

输出一行,一个整数,表示最大总美味值。

示例1

输入

1 1 74
2
1 502 47

输出

408

示例2

输入

2 2 10
2 1
1 100 8
2 50 3

输出

84

备注

最大总美味值可能为负。

题解

知识点:贪心,背包dp。

注意到贡献是会被选择顺序影响,有后效性,不能直接dp。尝试用排序找到最优相对位置消除后效性。假设A菜先做比B菜先做更好,交换后其他菜的贡献不变,因此可以有如下邻项交换证明:

Σw+AaAbΣt+BaBb(Σt+Ac)+ΣwΣw+BaBbΣt+AaAb(Σt+Bc)+ΣwAcBbAbBcAbAcBbBc

注意到最终排序结果由自身属性决定,因此可以以此贪心排序消除后效性。

随后就是个普通的01背包,注意至少要做一个菜,因此要初始化负无穷,避免一个菜都不选的情况,因此最后也要遍历区间 [1,t]找最大值。

时间复杂度 O(mlogm+mt+n)

空间复杂度 O(n+m+t)

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll b[57];
struct node {
ll a, b, c;
}cai[57];
ll dp[1000007];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m, t;
cin >> n >> m >> t;
for (int i = 1;i <= n;i++) cin >> b[i];
for (int i = 1;i <= m;i++) cin >> cai[i].b >> cai[i].a >> cai[i].c, cai[i].b = b[cai[i].b];
///由于时间会导致美味度变化,所以做菜顺序有后效性,因此贪心排序为最优顺序
sort(cai + 1, cai + m + 1, [&](node A, node B) {return A.b * B.c >= B.b * A.c;});
memset(dp, -0x3f, sizeof(dp));///因为不能不做,所以不放空气
dp[0] = 0;
for (int i = 1;i <= m;i++) {
for (int j = t;j >= cai[i].c;j--) {///不是完全背包
dp[j] = max(dp[j], dp[j - cai[i].c] + cai[i].a - j * cai[i].b);
}
}
ll ans = -1e18;
for (int i = 1;i <= t;i++) ans = max(ans, dp[i]);///i≠0
cout << ans << '\n';
return 0;
}
posted @   空白菌  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示