题目描述
原题链接:1241.外卖店优先级
解题思路
1.朴素做法
首先用一个结构体存储每一个订单的店铺号和时刻。
然后根据订单的时刻和店铺号按从小到大排序。
可以看出,上述做法的时间复杂度为
o
(
T
∗
(
n
+
m
)
)
≈
o
(
T
2
)
=
1
0
10
>
1
0
8
o(T*(n+m)) \approx o(T^2)=10^{10}\gt10^8
o(T∗(n+m))≈o(T2)=1010>108。
虽然如此,暴力做法依然可以拿到
90
%
90\%
90%的分数。
2.改进做法
可以看出,上述做法的一个缺点是每次枚举 T T T的时候都需要枚举每一个订单和店铺。因此可以考虑在循环内部优化。
(1)订单优化
可以当只有当此时订单的时刻=此时刻
时,才进行下一步。
(2)店铺衰减的优化
假如我们不每个时刻都衰减没有订单店铺,而是等到该店铺出现订单时,我们再比较他上一次拿到订单的时刻和本时刻的差距,一次性衰减两个时刻内所有没有订单的时刻。我们可以用last[k]
表示第k个店铺上一次接到订单的时刻。
而这种问题我们又需要分两种情况讨论:
情况1: 该段时间出现在T时刻之前
这个时候我们需要判断j-last[k]
是否大于1,如果大于1,那么说明两个时刻之间出现了空,需要进行衰减。
cnt[k] = max(0, cnt[k] - (j - last[k] - 1)); # 与0做比较,防止优先级小于0
情况2: 该段时间截止至在T时刻
那么就需要判断最后接到订单的时间last[k]
与T
的关系,如果小于T
,则说明在某一时刻到T时刻之间有没有接到订单的时段,需要进行衰减。
cnt[k] = max(0, cnt[k] - (t - last[k]));
3.改进做法的时间复杂度
由于我们只枚举每个时刻的订单,因此算法的时间复杂度为 o ( m a x ( T , m ) ) ≈ o ( T ) = 1 0 5 o(max(T,m)) \approx o(T)=10^5 o(max(T,m))≈o(T)=105
C++代码
朴素算法( o ( T 2 ) o(T^2) o(T2))
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100100;
struct Node{
int ts,id;
}a[N];
bool cmp(Node a, Node b)
{
return a.ts < b.ts;
}
int n,m,t,cnt[N];
bool ans[N];
int main()
{
cin >> n >> m >> t;
for(int i = 1; i <= m; i++)
{
int ts,id;
cin >> ts >> id;
a[i] = {ts, id};
}
sort(a+1, a+1+m, cmp);
int i = 1;
for(int j = 1; j <= t; j++)
{
int flag[N] = {0};
for(; i <= m && a[i].ts == j; i++)
{
cnt[a[i].id] += 2;
flag[a[i].id] = 1;
}
for(int k = 1; k <= n; k++)
{
if(!flag[k] && cnt[k] > 0) cnt[k]--;
if(cnt[k] <= 3 && ans[k]) ans[k] = false;
if(cnt[k] > 5 && !ans[k]) ans[k] = true;
}
memset(flag, 0, sizeof flag);
}
int res = 0;
for(int k = 1; k <= n; k++)
if(ans[k]) res++;
cout << res;
改进做法( o ( T ) o(T) o(T))
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100100;
struct Node{
int ts,id;
}a[N];
bool cmp(Node a, Node b)
{
if(a.ts != b.ts) return a.ts < b.ts;
return a.id < b.id;
}
int n,m,t,cnt[N],last[N];
bool ans[N];
int main()
{
cin >> n >> m >> t;
memset(last, 0, sizeof last);
for(int i = 1; i <= m; i++)
{
int ts,id;
cin >> ts >> id;
a[i] = {ts, id};
}
sort(a+1, a+1+m, cmp);
int i = 1;
for(int j = 1; j <= t; j++)
{
for(; i <= m && a[i].ts == j; i++)
{
int k = a[i].id;
if(j - last[k] > 1) cnt[k] = max(0, cnt[k] - (j - last[k] - 1));
if(cnt[k] <= 3) ans[k] = false;
last[k] = j;
cnt[k] += 2;
if(cnt[k] > 5) ans[k] = true;
}
}
for(int k = 1; k <= n; k++)
{
if(t - last[k] > 0) cnt[k] = max(0, cnt[k] - (t - last[k]));
if(cnt[k] <= 3 && ans[k]) ans[k] = false;
}
int res = 0;
for(int k = 1; k <= n; k++)
if(ans[k]) res++;
cout << res;