AcWing 1241.外卖店优先级

题目描述

原题链接:1241.外卖店优先级

解题思路

1.朴素做法

首先用一个结构体存储每一个订单的店铺号和时刻。
然后根据订单的时刻和店铺号按从小到大排序。
ac1241_0
可以看出,上述做法的时间复杂度为 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时刻之前
ac1241_1
这个时候我们需要判断j-last[k]是否大于1,如果大于1,那么说明两个时刻之间出现了空,需要进行衰减。

cnt[k] = max(0, cnt[k] - (j - last[k] - 1)); # 与0做比较,防止优先级小于0

情况2: 该段时间截止至在T时刻
ac1241_2
那么就需要判断最后接到订单的时间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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值