【贪心】逃跑(jzoj 1748)

逃跑

jzoj 1748

题目大意

你有一个能量值l,在接下来的n天里,你每天有两个选择:
1、增加l个食物
2、使l加一,
你第i天要吃 a i a_i个 食物,如果吃不到就会死掉,现在问你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, 且测试点中只有一组数据;
另外40%的数据, 1 n 1000 1\leqslant n\leqslant 1000。
对于100%的数据, 1 n 100000 0 L A i 1 0 9 1\leqslant n\leqslant 100000,0\leqslant L,Ai\leqslant 10^9。

解题思路

我们可以如果当前是第i天,增加l的奉献是 n i n-i ,即接下来 n i n-i 天能量多1
当l大于 n l n-l 时我们就不考虑加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;
}
发布了334 篇原创文章 · 获赞 57 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/ssllyf/article/details/104321737