- 题目地址:D - Poisonous Full-Course
题目大意
时间限制:2秒,空间限制:1024MB,分值:400分
问题描述
小明来到了一家餐厅,一共有道菜,第道菜具有以下属性:
- 若,则这道菜是无毒的,且吃了它会得到的美味值
- 若,则这道菜是有毒的,但吃了它同样会得到的美味值
最初,小明的胃是健康的。当小明吃了一道菜后,他会:
- 当他的胃是健康的
- 若这道菜无毒,则他的胃依然健康
- 若这道菜有毒,他就会得胃病
- 当他得了胃病
- 若这道菜无毒,则他的胃就会变得健康
- 若这道菜有毒,他就会死
现在,小明面前将依次展示第道菜,……,直到第道菜展示完毕为止。对于每道菜,小明可以选择吃或者不吃。选择吃就可能会改变状态并增加(减少)美味值;若选择不吃,则状态与美味值都不会有变化。
现在,我们要让小明活着走出餐厅,请问小明能获得的最大美味值是多少?
数据规模
- 每个值都是整数
- (言外之意,不是0就是1)
输入
输入来自标准输入,其格式如下:
⋮
输出
输出一个整数,表示答案。
输入样例1
5
1 100
1 300
0 -200
1 500
1 300
输出样例1
600
样例解释:
以下选择使小明获得了最大的美味值(即600)且未死亡:
- 他选择跳过第一道菜,现在他的胃是健康的,共获得了0美味值;
- 他选择享用第二道菜,现在他的胃不是健康的,共获得了300美味值;
- 他选择享用第三道菜,现在他的胃是健康的,共获得了100美味值;
- 他选择享用第四道菜,现在他的胃不是健康的,共获得了600美味值;
- 他选择跳过第五道菜,现在他的胃不是健康的;
- 最终他获得了600美味值并活着走出了餐厅。
输入样例2
4
0 -1
1 -2
0 -3
1 -4
输出样例2
0
在这组样例中,他能获得的最大美味值为0。
输入样例3
15
1 900000000
0 600000000
1 -300000000
0 -700000000
1 200000000
1 300000000
0 -600000000
1 -900000000
1 600000000
1 -100000000
1 -400000000
0 900000000
0 200000000
1 -500000000
1 900000000
输出样例3
4100000000
答案不一定是32位整数。
这道题,明显是一个dp。
如果我们定义dp[i][0]表示吃完前i个菜之后胃依然健康,获得的最大美味值;dp[i][1]表示吃完前i个菜之后得了胃病,获得的最大美味值。那么:
dp[i][0]有四种情况:0,dp[i-1][0]+y[i],dp[i-1][1]+y[i](前提:x[i]==0),dp[i-1][0]
dp[i][1]只有三种情况:0,dp[i-1][0]+y(前提:x[i]==1),dp[i-1][1]
到最后,能获得的最大美味值就是max(dp[n][0],dp[n][1])。
#include <iostream>
using namespace std;
typedef long long int ll;
ll n, dp[300005][2];
int main() {
cin >> n;
ll x, y;
for (int i = 1; i <= n; i++) {
cin >> x >> y;
if (x == 0) {
dp[i][0] = max(dp[i][0], max(dp[i - 1][0] + y, dp[i - 1][1] + y));
}
else {
dp[i][1] = max(dp[i][1], dp[i - 1][0] + y);
}
dp[i][0] = max(dp[i][0], dp[i - 1][0]);
dp[i][1] = max(dp[i][1], dp[i - 1][1]);
}
cout << max(dp[n][0], dp[n][1]) << endl;
return 0;
}
当然这个代码还可以再优化一下空间复杂度:
#include <iostream>
using namespace std;
typedef long long int ll;
ll n;
int main() {
cin >> n;
ll p0 = 0, p1 = 0;
ll x, y;
for (int i = 1; i <= n; ++i) {
cin >> x >> y;
if (x == 0) {
p0 = max(p0, max(p0 + y, p1 + y));
}
else {
p1 = max(p1, p0 + y);
}
}
cout << max(p1, p0) << endl;
}
轻松搞定!