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

土地编号 土地天数/资源分配情况 土地天数/资源分配情况 土地天数/资源分配情况 土地天数/资源分配情况 土地天数/资源分配情况
1 7 /0 6/2 5/4 4/6 3/8
2 6/0 6/0 5/2 4/4 3/6
3 5/0 5/0 5/0 4/1 3/2
4 4/0 4/0 4/0 4/0 3/1
一共消耗的资源 0 2 6 11 17
最大天数 7 6 5 4 3

如果要把所有土地全部减为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
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;
} 

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

你可能感兴趣的:(CCF,算法,数据结构,c++)