https://codeforces.com/gym/104337/problem/J
在补J题的时候,被题意折磨疯了(bushi),一直没理解题目意思。
目录
题意
小马宝莉有n块田需要耕作,且每块田有ai个资源,小马宝莉可以从第一个田开始耕作,每一秒可以耕作一块田,且初始资源为0。
之后,如果它已经耕作了x个田,那么在下一秒它可以选择耕作第x + 1个田,或者停留在第x个田不进行耕作,那么每停留一秒他可以获得前x个田的所有资源。
确保资源始终大于0,求耕作完所有田的最短时间。
思路
-
首先确定不能耕作完所有田的情况
(1)如果我们耕作完所有的田所获得的资源小于0,就说明本次无法进行耕作。
(2)因为一定可以从第一个田开始耕作,那么如果第一个田的资源为负数,则说明我们不能开始耕作。注意,这里的第一个田并不是字面上的第一,因为如果开始时资源为0,其实对我们能不能开始耕作不产生影响,所以我们判断的是(第一个非0资源的田)。 -
一定有解决方案的情况
由于所有的田都要经过,且每到一个田可以选择前面所有的田的资源数,所以我们可以用一个前缀和数组存储前 i 个田数,如果在某个时刻耕作到第 i 个田使得资源为负数,那我们应该在前面某个前缀和资源大于0的地点多停留一会才能使得我们到达该田资源不为负数。而我们要求的是最短时间,所以我们应该在最大正数前缀和停留,这样保证时间最短(贪心)。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main()
{
int n;
cin >> n;
vector<i64> arr(n + 1), summ(n + 1);
for(int i = 1; i <= n; ++i){
cin >> arr[i];
// 前缀和数组
summ[i] = summ[i - 1] + arr[i];
}
// 判断总和非负
if(summ[n] < 0){
cout << -1 << endl;
return 0;
}
// 判断第一个非零的数为正数
for(int i = 1; i <= n; ++i){
if(arr[i] != 0){
if(arr[i] < 0){
cout << -1 << endl;
return 0;
}
else break;
}
}
i64 ans = 0, cnt = 0, maxx = 0;
// ans = 秒数, cnt = 在第i个地区前的资源总数,maxx = 前缀和的最大值
for(int i = 1; i <= n; ++i){
ans++;
// 维护前缀和最大值
maxx = max(maxx, summ[i]);
cnt += summ[i];
if(cnt < 0){
// time = 在前i个最大前缀和停留的秒数
i64 time = abs(cnt) / maxx;
if(abs(cnt) % maxx != 0) time++;
ans += time;
// 资源数随着停留时间增加
cnt += time * maxx;
}
}
cout << ans << endl;
return 0;
}