【贪心】逃跑(jzoj 1748)

逃跑

jzoj 1748

题目大意

你有一个能量值l,在接下来的n天里,你每天有两个选择:
1、增加l个食物
2、使l加一,
你第i天要吃 a i 个 a_i个 ai食物,如果吃不到就会死掉,现在问你n天后你能活下去吗,如果能那最多剩多少个食物?(有t组数据)

输入样例

1
5 2
1 1 1 4 2

输出样例

2

样例解释

一个可行的最优方案如下:
第一天制造2个单位的食物,第二天把l升级到3,后面三天各制造3个单位的食物。
最后得到2+3+3+3-1-1-1-4-2=2单位的食物。

数据范围

对于30%的数据, 1 ⩽ n ⩽ 20 , 1\leqslant n\leqslant 20, 1n20且测试点中只有一组数据;
另外40%的数据, 1 ⩽ n ⩽ 1000 。 1\leqslant n\leqslant 1000。 1n1000
对于100%的数据, 1 ⩽ n ⩽ 100000 , 0 ⩽ L , A i ⩽ 1 0 9 。 1\leqslant n\leqslant 100000,0\leqslant L,Ai\leqslant 10^9。 1n1000000LAi109

解题思路

我们可以如果当前是第i天,增加l的奉献是 n − i n-i ni,即接下来 n − i n-i ni天能量多1
当l大于 n − l n-l nl时我们就不考虑加l了
那如果当前天不够食物,我们就要撤回之前的加l改为加食物,因为加l的奉献到当前状态还不一定会大于加食物的奉献(详情见代码)

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll t, n, l, x, add, sum, a[100500];//a存某一次加l的时间
int main()
{
	scanf("%lld", &t);
	while(t--)
	{
		sum = 0;//sum就是还剩多少食物
		add = 0;//add就是加了多少次l
		scanf("%lld %lld", &n, &l);
		for (int i = 1; i <= n && sum != -1; ++i)
		{
			scanf("%lld", &x);
			if (sum < x)//食物不够
			{
				sum += add + l;//当前天造食物
				while(sum < x && add > 0 && (add + l - 1) > i - a[add])//不够且还能再撤回,以及撤回这个加的是否大于对后面造成的负影响,-1是因为add少了1
				{
					sum = sum + add + l - 1 - (i - a[add]);//奉献以及负影响
					add--;
				}
				if (sum < x) sum = -1;//还不够
				else sum -= x;//够了
			}
			else
			{
				if (n - i > add + l) a[++add] = i;//有奉献
				else sum += add + l;//无奉献
				sum -= x;//减所需食物
			}
		}
		printf("%lld\n", sum);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值