【洛谷P1417】烹调方案 题解
题目大意
一共有 nnn 件食材,每件食材有三个属性,aia_iai,bib_ibi 和 cic_ici,如果在 ttt 时刻完成第 iii 样食材则得到 ai−t×bia_i-t\times b_iai−t×bi 的美味指数,用第 iii 件食材做饭要花去 cic_ici 的时间。
需要设计烹调方案使得在TTT的时间内美味指数最大并输出。
数据范围及约定
- 对于 40%40\%40% 的数据 1≤n≤101 \le n \le 101≤n≤10;
- 对于 100%100\%100% 的数据 1≤n≤501 \le n \le 501≤n≤50。
所有数字均小于 10510^5105。
暴力想法
首先我们可以观察到,若不考虑烹饪顺序,或是已知顺序的情况下,求解是很简单的:只需要使用复杂度O(n^2)的01背包进行dp即可
(如果不知道01背包,强烈建议跳转主页学习)
注意到前40%数据的N很小,我们便可以直接暴力枚举菜品的全排列,进行dp即可。
想明白后,我们稍加计算,就会发现:
超时辣!
时间复杂度O(n22n)O(n^22^n)O(n22n)是过不了哒!(理论上超3e8次运算,数据很水就当我没说)
正解
其实刚刚的想法已经比较接近正解了。我们来看看上面的做法能怎么优化。
对于后半部分,可以基本确定是没有优化空间的——首先dp是必做,其次就算能将dp优化到O(nlogn)O(nlogn)O(nlogn)甚至O(n)O(n)O(n),大数据依旧是过不了的。
于是我们考虑如何排列烹饪顺序。
首先可以观察到一个性质:如果交换相邻两个菜品的烹饪顺序,对前后菜品产生的贡献是没有影响的,因为交换后此前烹饪的总时间不变!
也就是说,如果存在菜品A优于B(即先烹饪A价值更大)、B优于C,则一定有A优于C!
接下来我们开始推理每种菜品的应有顺序。
假设有两个相邻的菜品序号为 i,ji,ji,j ,之前所用的总时间为TTT
根据题意可得,若先烹饪iii号菜品,得到的价值一共是:
w1=(ai−bi×(T+ci))+(aj−bj×(T+ci+cj))w_1=(a_i-b_i×(T+c_i))+(a_j-b_j×(T+c_i+c_j))w1=(ai−bi×(T+ci))+(aj−bj×(T+ci+cj))
=ai+aj−T×(bi+bj)−bi×ci−bj×ci−bj×cj=a_i+a_j-T×(b_i+b_j)-b_i×c_i-b_j×c_i-b_j×c_j=ai+aj−T×(bi+bj)−bi×ci−bj×ci−bj×cj
若先烹饪jjj号菜品,得到的价值一共是:
w2=(aj−bj×(T+cj))+(ai−bi×(T+cj+ci))w_2=(a_j-b_j×(T+c_j))+(a_i-b_i×(T+c_j+c_i))w2=(aj−bj×(T+cj))+(ai−bi×(T+cj+ci))
=ai+aj−T×(bi+bj)−bi×ci−bi×cj−bj×cj=a_i+a_j-T×(b_i+b_j)-b_i×c_i-b_i×c_j-b_j×c_j=ai+aj−T×(bi+bj)−bi×ci−bi×cj−bj×cj
显然,若先烹饪iii号更优,则有w1>w2w_1>w_2w1>w2
带入并化简两边,可以得到 −bj×ci>−bi×ci-b_j×c_i>-b_i×c_i−bj×ci>−bi×ci,
即:若bj×ci<bi×cjb_j×c_i<b_i×c_jbj×ci<bi×cj,则先烹饪iii号菜品更优。
所以,我们可以先根据上述结论对数组排序,再做dp
时间复杂度O(nT)O(nT)O(nT)(毕竟nnn很小,排序时间可以不计)
AC代码
#include<bits/stdc++.h>
using namespace std;
#define For(i, j, k) for(int i = j; i <= k; i++)
#define dFor(i, j, k)for(int i = j; i >= k; i--)
#define MaxN 55
#define int long longstruct Node{int a, b, c;bool operator<(const Node x) const{ //重载运算符,按之前的结论排序return c * x.b < b * x.c;}
}a[MaxN];
int T, n;
int f[MaxN][100005];signed main()
{cin >> T >> n;For(i, 1, n) cin >> a[i].a;For(i, 1, n) cin >> a[i].b;For(i, 1, n) cin >> a[i].c;sort(a+1, a+n+1);int ans = 0;For(i, 1, n){For(j, 1, T){ //01背包,虽然没有降维优化awaf[i][j] = max(f[i][j], f[i-1][j]);if(j >= a[i].c){f[i][j] = max(f[i][j], f[i-1][j-a[i].c] + a[i].a-a[i].b*j);}ans = max(ans, f[i][j]);}}cout << ans << endl;return 0;
}
总结
思维难度相对较高,主要在于推理传递性和排序规则
类似的题目还有P1060国王游戏等,可以练习
最后,制作实在不易。如果你喜欢这篇文章,可以点个免费的关注和免费的赞
我们下期再见!