问题描述
顿顿总共选中了 n 块区域准备开垦田地,由于各块区域大小不一,开垦所需时间也不尽相同。据估算,其中第 i 块(1≤i≤n)区域的开垦耗时为 天。这 n 块区域可以同时开垦,所以总耗时
取决于耗时最长的区域,即:
为了加快开垦进度,顿顿准备在部分区域投入额外资源来缩短开垦时间。具体来说:
-
在第 i 块区域每投入
单位资源,便可将其开垦耗时缩短 1 天;
-
耗时缩短天数以整数记,即第 i 块区域投入资源数量必须是
的整数倍;
-
在第 i 块区域最多可投入
×(
−k) 单位资源,将其开垦耗时缩短为 k 天;
-
这里的 k 表示开垦一块区域的最少天数,满足 0<k≤
;换言之,如果无限制地投入资源,所有区域都可以用 k 天完成开垦。
现在顿顿手中共有 m 单位资源可供使用,试计算开垦 n 块区域最少需要多少天?
输入格式
从标准输入读入数据。
输入共 n+1 行。
输入的第一行包含空格分隔的三个正整数 n、m 和 k,分别表示待开垦的区域总数、顿顿手上的资源数量和每块区域的最少开垦天数。
接下来 n 行,每行包含空格分隔的两个正整数 和
,分别表示第 i 块区域开垦耗时和将耗时缩短 1 天所需资源数量。
输出格式
输出到标准输出。
输出一个整数,表示开垦 n 块区域的最少耗时。
样例输入1
4 9 2
6 1
5 1
6 2
7 1
样例输出1
5
样例解释
如下表所示,投入 5 单位资源即可将总耗时缩短至 5 天。此时顿顿手中还剩余 4 单位资源,但无论如何安排,也无法使总耗时进一步缩短。
i | 基础耗时 | 缩减 1 天所需资源 | 投入资源数量 | 实际耗时 |
---|---|---|---|---|
1 | 6 | 1 | 1 | 5 |
2 | 5 | 1 | 0 | 5 |
3 | 6 | 2 | 2 | 5 |
4 | 7 | 1 | 2 | 5 |
样例输入2
4 30 2
6 1
5 1
6 2
7 1
样例输出2
2
样例解释
投入 20 单位资源,恰好可将所有区域开垦耗时均缩短为 k=2 天;受限于 k,剩余的 10 单位资源无法使耗时进一步缩短。
子任务
70% 的测试数据满足:0<n,,
≤100 且 0<m≤
;
全部的测试数据满足:0<n,,
≤105 且 0<m≤
。
思路:
1、由于开垦 n 块区域最少需要多少天取决于哪块区域需要的天数最多,且要想天数变少,开垦天数一样的区域需要同时利用资源来减少天数。
2、基于这种情况,采用有序的哈希表来进行存储,key为开垦需要的天数(天数一样的区域即为一个键值对),value为将key减少一天所需要的总资源。
3、优先处理开垦需要最多天数的区域,也就是倒叙遍历哈希表。根据资源m剩余情况若不可以此天数减少一天或着已经是最低天数k,则输出并返回。
4、若可以减少天数,则资源数对应减少,并且将较少后的天数作为key,减少一天需要的资源数插入到哈希表中(若天数已经存在,则key对应的value累加)。
代码实现:
#include<iostream>
#include<map>
using namespace std;
int main() {
int n, m, k;
cin >> n >> m >> k;
map<int, int>maps;
for (int i = 0; i < n; ++i) { //用有序哈希表存储开垦所需相同时间的田地一起减少一天所需的总资源
int c, t; //根据map的特性,所需天数从小大排序
cin >> c >> t;
maps[c] += t;
}
for (auto it = maps.rbegin(); it != maps.rend(); ++it) { //从哈希表的后面开始遍历即先处理所需天数最多的田地
int tmp1 = it->first; //变量临时存储,开垦土地所需天数
int tmp2 = it->second; //变量临时存储,减少一天所需资源数
if (m < tmp2 || tmp1 == k) //可用资源不足以缩短时间或者开垦天数已经达到最少天数k,则输出返回
{
cout << tmp1 << endl;
break;
}
m -= tmp2; //否则的话减少资源
maps[tmp1 - 1] += tmp2; //开垦所需天数减一,同时把减一天后所需的资源累加到哈希表中,也是有序的
}
}