蓝桥杯 2021国赛 :巧克力
贪心,模拟
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
题目描述
小蓝很喜欢吃巧克力,他每天都要吃一块巧克力。
一天小蓝到超市想买一些巧克力。超市的货架上有很多种巧克力,每种巧克力有自己的价格、数量和剩余的保质期天数,小蓝只吃没过保质期的巧克力,请问小蓝最少花多少钱能买到让自己吃
n
n
n 天的巧克力。
输入描述
输入的第一行包含两个整数
x
x
x,
n
n
n,分别表示需要吃巧克力的天数和巧克力的种类数。
接下来
n
n
n 行描述货架上的巧克力,其中第
i
i
i 行包含三个整数 ai,bi,ci 表示第 i 种巧克力的单价为 ai,保质期还剩 bi 天(从现在开始的 bi 天可以吃),数量为 ci。
输出描述
输出一个整数表示小蓝的最小花费。
如果不存在让小蓝吃 x 天的购买方案,输出 -1
。
样例
输入
10 3
1 6 5
2 7 3
输出
18
样例说明
一种最佳的方案是第 1 种买 5 块,第 2 种买 2 块,第 3 种买 3 块。前 5 天吃第 1 种,第 6、7 天吃第 2 种,第 8 至 10 天吃第 3 种。
评测用例规模与约定
对于 30% 的评测用例,n, x \le 1000 n,x≤1000;
对于所有评测用例,1 ≤ \leq ≤ n, x ≤ \leq ≤ 100000,1 ≤ \leq ≤ ai, bi, ci ≤ \leq ≤ 1 0 9 10^9 109
思路
这题是一道贪心问题,即要贪花费,也要贪时间。
这题我们按照时间从后往前贪,即先把数据按照保质期的大小,从大到小排序,然后再使用优先队列,把保质期大于等于当前日期的所有商品的最经济的商品找出。购买它,为了方便计算是不是要购买更多,我们只要购买一个,然后判断这个商品还有没有,如果购买了一个后,这个商品还有,我们再把这个商品放入优先队列里,在买一次。我们可以通过这样一次只买一包的形式 ,代替一次买好多包的情况。
关于按价格实惠的先买的话,我们不能确定,能不能买到第
n
n
n 天的巧克力
例如以下数据:
10 3
1 10 3
2 5 5
3 7 10
如果按时间从前往后,实惠的先买的话,就会出现下面这种情况
天数: 1 2 3 4 5 6 7 8 9 10
价格: 1 1 1 2 2 3 3 //当天吃的巧克力的价格
而正确的吃法应该是下面这样的
天数: 10 9 8 7 6 5 4 3 2 1 //第几天
价格: 1 1 1 3 3 2 2 2 2 2
代码
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N =1e5+10;
struct node
{
int a,b,c;
bool operator < (const node &w)const
{
//操作符重载
//让优先队列里的数据按价格由小到大排序
return a>w.a;
}
};
node q[N];
int cmp(node &cc,node &e)
{
//sort 排序规则
//让数据按保质期由大到小排序
return cc.b>e.b;
}
int n,x;
int main()
{
cin>>x>>n;
for(int i = 0 ; i < n ; i ++)
{
int a,b,c;
cin>>q[i].a>>q[i].b>>q[i].c;
}
sort(q,q+n,cmp);
priority_queue<node> hh;
long long sum=0; //价格总和是 n*a = 1e5 * 1e9 = 1e14 会爆int
int now_date = x; //现在买到第几天的巧克力
int cnt = 0 ;
hh.push(q[cnt++]);
while(!hh.empty()&&now_date>0)
{
while(q[cnt].b>=now_date && cnt < n)
{
hh.push(q[cnt++]);
}
node t = hh.top();
hh.pop();
sum+=t.a;
now_date--;
t.c--;
if(t.c>0) hh.push(t);
}
if(now_date>0) puts("-1");
else printf("%lld\n",sum);
return 0;
}