CSUSTOJ 你真的会泡面吗?(优先队列模拟)

在这里插入图片描述

思路:
用两个优先队列模拟就好了

#pragma GCC optimize(2)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <unordered_map>
#include <vector>
#include <queue>

using namespace std;

typedef unsigned long long ull;
typedef long long ll;
const int maxn = 2e5 + 7;
const int mod = 1e9 + 7;
ll E[maxn],S[maxn],T[maxn];
int n;

struct Node1 { //按到来的时间和剩余时间和编号排序
    int id;
    ll tim,res;
    bool operator < (const Node1&rhs) const {
        if(tim != rhs.tim) {
            return tim > rhs.tim;
        }
        if(res != rhs.res) {
            return res > rhs.res;
        }
        if(id != rhs.id) {
            return id > rhs.id;
        }
        return true;
    }
};

struct Node2 { //按剩余时间和编号排序
    int id;
    ll tim,res;
    bool operator < (const Node2&rhs) const {
        if(res != rhs.res) {
            return res > rhs.res;
        }
        if(id != rhs.id) {
            return id > rhs.id;
        }
        return true;
    }
};

priority_queue<Node1>q; //到来的时间优先
priority_queue<Node2>p; //剩余的时间优先

int main() {
    scanf("%d",&n);
    for(int i = 1;i <= n;i++) {
        scanf("%lld%lld",&S[i],&T[i]);
        q.push({i,S[i],T[i]});
    }
    ll tim = 0;//泡面花了多少时间
    ll pre = 0;
    while(!q.empty()) {
        Node1 now = q.top();q.pop();
        ll num = now.tim - pre; //两次间隔的时间
        if(!p.empty()) {
            while(!p.empty() && num >= p.top().res) {
                E[p.top().id] += (p.top().res + tim) % mod;
                tim += p.top().res;
                num -= p.top().res;
                p.pop();
            }
            tim += num;
            if(num && !p.empty()) {
                Node2 tp = p.top();p.pop();
                tp.res -= num;
                p.push(tp);
            }
        } else {
            tim += num;
        }
        pre = now.tim;
        p.push(Node2{now.id,now.tim,now.res});
        while(!q.empty() && q.top().tim == now.tim) {
            now = q.top();q.pop();
            p.push(Node2{now.id,now.tim,now.res});
        }
    }
    
    while(!p.empty()) {
        Node2 now = p.top();p.pop();
        E[now.id] = (now.res + tim) % mod;
        tim += now.res;
    }
    
    ll ans = 0;
    for(int i = 1;i <= n;i++) {
//        printf("FUCK %lld\n",E[i]);
        ans += E[i] - S[i] - T[i];
        ans %= mod;
    }
    
    ans = ((ans % mod) + mod) % mod;
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值