逃 跑 逃跑 逃跑
题目链接: j z o j 1748 jzoj\ 1748 jzoj 1748
题目
A l i c e Alice Alice被困在一个山洞里,而且这个山洞还有 n n n天就要倒塌了!
幸运的是,山洞里资源足够丰富,已知 A l i c e Alice Alice一开始有一个能力值 L L L,而她每天可以选择以下两种操作之一:
- 把自己的能力值 L L L加 1 1 1;
- 利用山洞的资源制造出当前能力值个单位的食物;
同时, A l i c e Alice Alice每天必须吃掉 A i A_i Ai个单位的食物,如果某天食物不足,那么她会死掉。
现在, A l i c e Alice Alice需要你来告诉她,她在 n n n天过后最多能带着多少食物逃离山洞?
输入
第一行输入一个整数,表示测试数据的组数,每个测试点包含不超过 10 10 10组数据,对于每组数据:
- 第一行两个非负整数 n n n和 L L L。
- 第二行 n n n个正整数 A i A_i Ai。
输出
如果 A l i c e Alice Alice无法逃出山洞,输出 − 1 -1 −1;否则输出她最多能带上的食物总数。
样例输入
1
5 2
1 1 1 4 2
样例输出
2
样例解释
一个可行的最优方案如下:
第一天制造
2
2
2个单位的食物,第二天把
L
L
L 升级到
3
3
3,后面三天各制造
3
3
3个单位的食物。
最后得到
2
+
3
+
3
+
3
−
1
−
1
−
1
−
4
−
2
=
2
2\!+\!3\!+\!3\!+\!3\!-\!1\!-\!1\!-\!1\!-\!4\!-\!2\!=\!2
2+3+3+3−1−1−1−4−2=2单位的食物。
数据范围
对于
30
%
30\%
30%的数据,
1
<
=
n
<
=
20
1\!<\!=\!n\!<\!=\!20
1<=n<=20,且测试点中只有一组数据;
另外
40
%
40\%
40%的数据,
1
<
=
n
<
=
1000
1\!<\!=\!n\!<\!=\!1000
1<=n<=1000。
对于
100
%
100\%
100%的数据,
1
<
=
n
<
=
100000
1\!<\!=\!n\!<\!=\!100000
1<=n<=100000,
0
<
=
L
0\!<\!=\!L
0<=L,
A
i
<
=
1
0
9
A_i\!<\!=\!10^9
Ai<=109。
思路
这道题其实可以贪心。
首先,我们每一天就看当前的食物够不够:
- 如果不够吃,就要做食物,但是如果还是不够吃,就要让之前加能量值的日子也来做吃的,但是如果就算无论如何都不够吃,那就只能饿死了。
- 如果够吃,就又有两种选择。要么加能力值,要么做吃的。那如果假设剩下的日子食物都够吃,那肯定是前一段时间一直加能量值,后面的时间疯狂做吃的。而这时候还是要让最后做出来的吃的最多,其实就是要让(最后的能量值) ∗ * ∗(做食物的天数最大)。显而易见,我们要让它们尽量相同,那我们判断做吃的还是加能量值的时候就按照这个标准来判断就可以了。
代码
#include<cstdio>
#define ll long long
using namespace std;
ll t, n, l, a, ans, grow;
int main() {
scanf("%d", &t);//读入
for (ll o = 1; o <= t; o++) {
scanf("%lld %lld", &n, &l);//读入
ans = 0;//初始化
grow = 0;
for (ll i = 1; i <= n; i++) {
scanf("%lld", &a);//读入
if (a > ans) {//当前的食物不够吃
ans += grow + l;//只能做食物
int back = 0;
while (ans < a) {//还是不够
back++;//退回去做吃的
grow--;//能力值加的次数就要减少
ans += grow + l - back;//重新算这样能做出来的食物数量
}
if (grow < 0) break;//无论怎么样都会饿死
ans -= a;//扣食物
}
else {//当前的食物够吃
ans -= a;//扣吃的
if (l + grow < n - i) grow++;//当前加能力值更赚
else ans += grow + l;//当前做吃的更赚
}
}
if (grow < 0) printf("-1\n");//只能饿死
else printf("%lld\n", ans);//输出
}
return 0;
}