CF - Div2 - G - Adilbek and the Watering System

分析:这道题很明显是贪心,关键是怎么写代码;

将朋友按照达到时刻和收费排序,一次遍历;

假设在时刻ti,此时有价格各异的水的集合,优先消耗便宜的水,满足ti-1 ~ ti中间时间间隔的用水。然后将ti的水全部买入,再更新此时水的集合,多出容量的部分,从价格高开始删除,相当于买入i的水替换掉前面价格高的(也就是“反悔”操作,类似于退货);到了最后时刻剩下的水再全部退回就好了。

这道题可以用map维护水的集合,key是价格,value是拥有的量

#include<bits/stdc++.h>
using namespace std;

#define ll long long
int n, m, c, c0;
struct node
{
    int t, a; ll p;
}fr[500000 + 10];
bool cmp(const node &a, const node &b)
{
    if(a.t == b.t)return a.p < b.p;
    return a.t < b.t;
}
map<ll, int> mmp;

ll solve()
{
    ll ret = 0;
    mmp.clear();
    mmp[0] = c0;
    int i = 0, now = 0;
    int cap = c0;
    fr[n].t = m;
    fr[n].a = 0;
    while(i <= n)
    {
        int t = fr[i].t - now;
        while(cap >= t && t)
        {
            int temp = min(mmp.begin()->second, t);
            mmp.begin()->second -= temp, t -= temp;
            if(mmp.begin()->second==0)mmp.erase(mmp.begin());
            cap -= temp;
        }
        if(cap < t)return -1;
        if(mmp.count(fr[i].p))mmp[fr[i].p] += fr[i].a;
        else mmp[fr[i].p] = fr[i].a;
        cap += fr[i].a, ret += fr[i].a * fr[i].p;
        while(cap > c)
        {
            map<ll, int >::iterator it = --mmp.end();
            int temp = min(cap - c, (it -> second));
            cap -= temp, it -> second -= temp, ret -= it->first * temp;
            if(it -> second == 0) mmp.erase(it);
        }
        while(fr[1 + i].t == fr[i].t && cap < c)
        {
            ++i;
            int temp = min(c - cap, fr[i].a);
            cap += temp, ret += temp * fr[i].p;
            if(mmp.count(fr[i].p))mmp[fr[i].p] += temp;
            else mmp[fr[i].p] = temp;
        }
        now = fr[i].t;
        ++i;
    }
    for(map<ll,int>::iterator it = mmp.begin(); it != mmp.end(); ++it)
    {
        ret -= it -> first * it -> second;
    }
    return ret;
}

int main()
{
    int q;
    scanf("%d", &q);
    while(q--)
    {
        scanf("%d%d%d%d", &n, &m, &c, &c0);
        for(int i = 0; i < n; ++i)
        {
            scanf("%d%d%lld", &fr[i].t, &fr[i].a, &fr[i].p);
        }
        sort(fr, fr + n, cmp);
        printf("%lld\n", solve());
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值