CCF-29次-第二题垦田计划100分

前言

比赛的时候100AC了,但现在是仅凭印象敲出来的代码,不确定是否会存在一些问题,等题目出来了,AC后,我再回来填坑,现在仅供参考。


来填坑了,之前凭印象写的代码有一丢丢小问题,已经改正了, AC100分。
在这里插入图片描述

题目描述

仅凭印象写的题目。
输入 n m k,分别表示土地数目、资源数目、土地开垦至少需要的天数。(都是整数
输入 n 行2列数据,分别表示每个土地需要开垦的天数,减少一天需要消耗的资源数目。n个土地可以同时开垦,通过消耗资源,可以减少土地的天数。
题目需要你去合理分配资源,以获得开垦完 n 个土地所需要的最少天数,但是不管资源再多,最多也只能减到 k 天。

我描述表达的可能不够清楚,写个样例解释以下。

输入

4 15 3
7 2
6 2
5 1
4 1

输出

4

分析

有4块土地可以同时开垦,开垦完的所需天数分别为7、6、5、4;
通过分配一定的资源,可以减少他们的开垦天数,他们的资源报价为 2、2、1、1 单位:资源/天。但是每块土地都至少需要3天才能开垦完。
手里有资源15。
如果我给第一块土地资源4,那么那就能从7天减为7-4/2=5天
同理,如果我把给第三块土地资源5,那么他就能从5天减为max(k,5-5/1)=max(3,0)=3

土地编号土地天数/资源分配情况土地天数/资源分配情况土地天数/资源分配情况土地天数/资源分配情况土地天数/资源分配情况
17 /06/25/44/63/8
26/06/05/24/43/6
35/05/05/04/13/2
44/04/04/04/03/1
一共消耗的资源0261117
最大天数76543

如果要把所有土地全部减为3天,至少需要资源17>m,因此最好的情况也只能减到4天。

分析

先将所有的天数尽量抹平。

即想象用柱状图来表示天数,从上往下把高的给抹平:
每抹去一定的高度,资源就需要相应减少;
等一样高了,资源的就是减去所有的num。

代码思路

  1. 排序,按天数递减,那么此时柱状图一定是高—>低(也可能有平)

  2. 我们从左往后遍历,如果遇到了坡,那我们就需要把从0~当前位置的土堆都铲平。
    (1)判断能否抹平?
    优化1:用mon记录前面的资源量,避免双重循环,增加时间复杂度。
    计算a[i-1].d-a[i].dm/mon的大小,如果可以抹平,就直接减去资源,记录目前最长天数是a[i].d
    优化2:如果不可以完全抹平,那需要计算,至少可以铲掉多少?然后结束循环:m=0; ans-=a[i].d-m/mon;

  3. 所有山坡都铲成一个高度后,计算如果m还有剩余,是否可以把整个山坡都铲掉一些高度:count=m/sum;

  4. kans-count的最大值

代码

#include<bits/stdc++.h>
using namespace std;
struct node{
	int d;
	int num;
}; 
bool cmp(const node&l,const node&r){
	if(l.d!=r.d)
	return l.d>r.d;
	return l.num>r.num;
}
vector<node> a;//用数组也可以 
int main(){
	int n,m,k;
	int sum=0;//计算全部-1天的消耗 
	cin>>n>>m>>k;//个数  资源数  至少天数
	for(int i=0;i<n;i++){//用数组也可以 
		node temp;
		cin>>temp.d>>temp.num;
		a.push_back(temp);
		sum+=temp.num; 
	} 
	sort(a.begin(),a.end(),cmp);
	
	int mon=0;//存储a[i]之前的消耗量
	int ans=a[0].d;//答案 初始化等于最大的天数 
	for(int i=1;i<a.size();i++){
		mon+=a[i-1].num;//存储a[i]之前的消耗量
		if(a[i].d<a[i-1].d){//如果天数不相等,处理,让他们相等 
			int temp=m/mon;//现有资源最多能把前面1 ~ i-1减多少天? 
			if(temp>=(a[i-1].d-a[i].d)){//满足条件,能减 抹平天数 
				m-=(a[i-1].d-a[i].d)*mon;//资源- 
				ans=a[i].d;//更新目前最长的天数 
			} else {//不满足条件,说明没法减去那么多 直接break; 
				m=0;
				ans=a[i-1].d-temp; 
				break;
			} 
		} 
	} 
	//如果此时m还有很多剩余,计算全部抹平的机会 
	int count=m/sum;	 
	
	cout<<max(k,ans-count)<<endl;
} 

如果觉得对您所帮助的话,请多多点赞!

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MORE_77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值