逃跑
jzoj 1748
题目大意
你有一个能量值l,在接下来的n天里,你每天有两个选择:
1、增加l个食物
2、使l加一,
你第i天要吃ai个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,1⩽n⩽20,且测试点中只有一组数据;
另外40%的数据,1⩽n⩽1000。1\leqslant n\leqslant 1000。1⩽n⩽1000。
对于100%的数据,1⩽n⩽100000,0⩽L,Ai⩽109。1\leqslant n\leqslant 100000,0\leqslant L,Ai\leqslant 10^9。1⩽n⩽100000,0⩽L,Ai⩽109。
解题思路
我们可以如果当前是第i天,增加l的奉献是n−in-in−i,即接下来n−in-in−i天能量多1
当l大于n−ln-ln−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就是加了多少次lscanf("%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;
}