2023 Hubei Provincial Collegiate Programming Contest(J)

https://codeforces.com/gym/104337/problem/J

在补J题的时候,被题意折磨疯了(bushi),一直没理解题目意思。

目录

题意

思路

首先确定不能耕作完所有田的情况

一定有解决方案的情况

由于所有的田都要经过,且每到一个田可以选择前面所有的田的资源数,所以我们可以用一个前缀和数组存储前 i 个田数,如果在某个时刻耕作到第 i 个田使得资源为负数,那我们应该在前面某个前缀和资源大于0的地点多停留一会才能使得我们到达该田资源不为负数。而我们要求的是最短时间,所以我们应该在最大正数前缀和停留,这样保证时间最短(贪心)。


题意

小马宝莉有n块田需要耕作,且每块田有ai个资源,小马宝莉可以从第一个田开始耕作,每一秒可以耕作一块田,且初始资源为0。

之后,如果它已经耕作了x个田,那么在下一秒它可以选择耕作第x + 1个田,或者停留在第x个田不进行耕作,那么每停留一秒他可以获得前x个田的所有资源。

确保资源始终大于0,求耕作完所有田的最短时间。

思路

  1. 首先确定不能耕作完所有田的情况

    (1)如果我们耕作完所有的田所获得的资源小于0,就说明本次无法进行耕作。
    (2)因为一定可以从第一个田开始耕作,那么如果第一个田的资源为负数,则说明我们不能开始耕作。注意,这里的第一个田并不是字面上的第一,因为如果开始时资源为0,其实对我们能不能开始耕作不产生影响,所以我们判断的是(第一个非0资源的田)。 

  2. 一定有解决方案的情况

        由于所有的田都要经过,且每到一个田可以选择前面所有的田的资源数,所以我们可以用一个前缀和数组存储前 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值