“饱了么”外卖系统中维护着N 家外卖店,编号1~N。
每家外卖店都有一个优先级,初始时(0 时刻) 优先级都为0。
每经过1 个时间单位,如果外卖店没有订单,则优先级会减少1,最低减到0;
而如果外卖店有订单,则优先级不减反加,每有一单优先级加2。
如果某家外卖店某时刻优先级大于5,则会被系统加入优先缓存中;
如果优先级小于等于3,则会被清除出优先缓存。
给定T 时刻以内的M 条订单信息,请你计算T 时刻时有多少外卖店在优先缓存中。
第一行包含3 个整数N、M 和T。
以下M 行每行包含两个整数ts 和id,表示ts 时刻编号id 的外卖店收到一个订单
1<=N, M, T<=100000,1<=ts<=T,1<=id<=N。
输出一个整数代表答案
样例输入
2 6 6
1 1
5 2
3 1
6 2
2 1
6 2
样例输出
1
题目的大概意思就是根据每家店在不同时间得的订单计算其各个时间的优先级。当这家店不在优先缓存中且在某个时刻优先级大于5时,则将其加入优先缓存;当这家店在优先缓存中且在某个时刻优先级小于等于3时,则将其移除优先缓存。问最后的t时刻时优先缓存中有几家店。
这题第一眼看到的想法就是模拟,但单纯地去模拟在一些数据量较大的输入上显然会TLE,因此需要对模拟进行加速。
由此可以想到对输入按照时间进行排序。再用一个数组记录下每家店上次获得订单的时间,在下次遇到同一家店的数据时,先减去中间间隔时间中没有订单损失地优先级,并进行判断是否要移除优先缓存,再加上这个时刻上订单带来的优先级,判断是否可以加入优先缓存(一定要先判断是否要移出缓存再加上新的优先级,不然会错过将该店移出优先缓存的机会)。最后再依次减去每一个店最后一次获得订单的时刻到t时刻所失去优先级并判断其是否还在优先缓存里即可得到答案。
#include <bits/stdc++.h>
using namespace std;
//定义每一家店的数据结构
typedef struct store{
int time, id;
bool operator < (const store& a) const{
if (this->time == a.time) return this->id > a.id;
else return this->time > a.time;
}
}store;
int main() {
//用优先队列实现自动排序
priority_queue<store> q;
int n, m, t;
cin >> n >> m >> t;
for (int i = 0;i < m;i++) {
store temp;
cin >> temp.time >> temp.id;
q.push(temp);
}
vector<int> sum(n + 1, 0); //记录优先级总和
vector<bool> flag(n + 1, false); //记录是否在缓存中
vector<int> lasttime(n + 1, 0); //记录最后一次获得订单时间
while (!q.empty()) {
store temp = q.top();
q.pop();
int now = temp.time, id = temp.id;
//获得最后一次获得订单时间
int ti = lasttime[id];
//如果时间间隔小于等于1则不用减
//相当于上一个时刻或这一时刻获得了订单
sum[id] = max(0, sum[id] - (now - ti <= 1 ? 0 : now - ti - 1)) ;
if (flag[id] && sum[id] <= 3) flag[id] = false;
sum[id] += 2;
if (!flag[id] && sum[id] > 5) flag[id] = true;
//更新最后一次获得订单时间
lasttime[id] = now;
}
int res = 0;
for (int i = 1;i <= n;i++) {
//只有这家店原来就在缓存中,后续的减法操作会对其产生影响
if (flag[i] && t > lasttime[i]) {
sum[i] -= t - lasttime[i];
if (sum[i] <= 3) flag[i] = false;
}
if (flag[i]) res++;
}
cout << res << endl;;
}