题目
Description
Alice被困在一个山洞里,而且这个山洞还有n天就要倒塌了!
幸运的是,山洞里资源足够丰富,已知Alice一开始有一个能力值L,而她每天可以选择以下两种操作之一:
1、 把自己的能力值加1;
2、 利用山洞的资源制造出当前能力值个单位的食物;
同时,Alice每天必须吃掉Ai个单位的食物,如果某天食物不足,那么她会死掉。
现在,Alice需要你来告诉她,她在n天过后最多能带着多少食物逃离山洞?
Input
第一行输入一个整数,表示测试数据的组数,每个测试点包含不超过10组数据,对于每组数据:
第一行两个非负整数n和L。
第二行n个正整数Ai。
Output
如果Alice无法逃出山洞,输出-1;否则输出她最多能带上的食物总数。
Sample Input
1
5 2
1 1 1 4 2
Sample Output
2
Hint
【样例解释】
一个可行的最优方案如下:
第一天制造2个单位的食物,第二天把l升级到3,后面三天各制造3个单位的食物。
最后得到2+3+3+3-1-1-1-4-2=2单位的食物。
【数据规模】
对于30%的数据,1<=n<=20,且测试点中只有一组数据;
另外40%的数据,1<=n<=1000。
对于100%的数据,1<=n<=100000,0<=L,Ai<=10^9。
分析
如果要求最终剩余食物最大,我们就要考虑什么情况下是制作食物,什么情况下是提升能力值。
- 我们用贪心的思想来思考
先不考虑自己会不会被饿死,就只考虑如何分配提升能力值和制造食物的时间。
设当前是第x天,且第x天以前都是提升能力值的。
那么, W总食物=(l+x)×(n−x)
化简得: W总食物=−x2+(n−l)x+nl
因为这里是二次函数关系,所以有一个界点。
- 那怎么找这个界点呢?
观察这个式子 W总食物=(l+x)×(n−x)
很显然,在(l+x)<(n-x)是提升能力值。
- 现在再来考虑可能会饿死的情况。
1、如果今天剩余的食物不足,那么今天只能生产食物。如果今天生产完了食物,还是不够吃的话,为了生存,只能从前面用了提升能力值的时间来生产食物。
2、如果食物足够,那么就按照上面的关系来判断今天用了干什么。
那道式子就稍微变化一下,变为:
W总食物=(l+add)×(n−x)
x仍表示第几天,add表示在此之前,提升了多少能力值。
- 注意:要开long long
code(c++)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <stdlib.h>
#include <math.h>
using namespace std;
long long t,n,sum,l,add,x,y;
int main()
{
scanf("%d",&t);
for(;t;t--)
{
scanf("%lld%lld",&n,&l);
add=0;
sum=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
if(sum<x)
{
sum+=add+l;
y=1;
while(sum<x)
{
add--;
sum+=add+l-y;
y++;
}
if(add<0)break;
sum-=x;
}
else
{
sum-=x;
if(l+add<n-i)add++;
else sum+=add+l;
}
}
if(add<0)printf("-1\n");
else printf("%lld\n",sum);
}
}