Toyota Programming Contest 2023#3(AtCoder Beginner Contest 306) 6月17日比赛 第四题


题目大意

时间限制:2秒,空间限制:1024MB,分值:400分

问题描述

小明来到了一家餐厅,一共有N道菜,第i道菜具有以下属性:

  • X_{i}= 0,则这道菜是无毒的,且吃了它会得到Y_{i}的美味值
  • X_{i}= 1,则这道菜是有毒的,但吃了它同样会得到Y_{i}的美味值

最初,小明的胃是健康的。当小明吃了一道菜后,他会:

  • 当他的胃是健康的
    • 若这道菜无毒,则他的胃依然健康
    • 若这道菜有毒,他就会得胃病
  • 当他得了胃病
    • 若这道菜无毒,则他的胃就会变得健康
    • 若这道菜有毒,他就会死

现在,小明面前将依次展示第1道菜,……,直到第N道菜展示完毕为止。对于每道菜,小明可以选择吃或者不吃。选择吃就可能会改变状态并增加(减少)美味值;若选择不吃,则状态与美味值都不会有变化。

现在,我们要让小明活着走出餐厅,请问小明能获得的最大美味值是多少?

数据规模

  • 每个值都是整数
  • 1\leq N\leq 3\times 10^{5}
  • X_{i}\in \left \{ 0,1\right \} (言外之意,x_{i}不是0就是1)
  • -10^9 \leq Y_i \leq 10^9

输入

输入来自标准输入,其格式如下:

N

X_1   Y_1

X_2   Y_2

X_N   Y_N

输出

输出一个整数,表示答案。


输入样例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;
}

轻松搞定!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

H.Y_C ⁹⁹⁹⁹⁹⁹⁺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值