前言
比赛的时候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。
代码思路
-
排序,按天数递减,那么此时柱状图一定是高—>低(也可能有平)
-
我们从左往后遍历,如果遇到了坡,那我们就需要把从0~当前位置的土堆都铲平。
(1)判断能否抹平?
优化1:用mon
记录前面的资源量,避免双重循环,增加时间复杂度。
计算a[i-1].d-a[i].d
和m/mon
的大小,如果可以抹平,就直接减去资源,记录目前最长天数是a[i].d
优化2:如果不可以完全抹平,那需要计算,至少可以铲掉多少?然后结束循环:m=0; ans-=a[i].d-m/mon;
-
所有山坡都铲成一个高度后,计算如果
m
还有剩余,是否可以把整个山坡都铲掉一些高度:count=m/sum;
-
取
k
和ans-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;
}
如果觉得对您所帮助的话,请多多点赞!