鱼C论坛

 找回密码
 立即注册
查看: 326|回复: 1

发红包问题的时间复杂度

[复制链接]
发表于 2024-1-18 17:00:03 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
问题如下:
链接:https://ac.nowcoder.com/acm/contest/73762/B
来源:牛客网

在公司的年会上,有
N个人排着队准备毛红包,这些人按照从前到后的顺序排成一列,编号为1到N。
在活动期间,发生了Q次以下事件:
在时间Ti ,装有M i块钱的红包从空中飘下,站在队头的人得到该红包内的所有钱(如果队列中没有人,则没有人得到该红包)。然后,该人离开队列,并在时间T i+D i返回到原来的位置。

在所有Q次事件之后,请输出每个人获得的总金额数。

下面是我的代码,求大佬改进时间复杂度!

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;

  4. int main() {
  5.     ios::sync_with_stdio(0);
  6.     cin.tie(0);

  7.     long n, q;
  8.     ll time, money, dtime;

  9.     cin >> n >> q;

  10.     vector<ll> m(n, 1), dp(n, 1), rmb(n, 0); // Using vectors instead of maps for better performance.

  11.     for (ll i = 0; i < q; i++) {
  12.         cin >> time >> money >> dtime;

  13.         // Finding the first available position to perform the operation.
  14.         for (ll j = 0; j < n; j++) {
  15.             if (m[j] == 0) {
  16.                 if (dp[j] == time) {
  17.                     m[j] = 1;
  18.                 }
  19.                 else {
  20.                     continue;
  21.                 }
  22.             }

  23.             m[j] = 0;
  24.             dp[j] = time + dtime;
  25.             rmb[j] += money;

  26.             break; // Break after finding the first available position.
  27.         }
  28.     }

  29.     for (ll i = 0; i < n; i++) {
  30.         cout << rmb[i] << '\n';
  31.     }

  32.     return 0;
  33. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-1-18 17:08:03 | 显示全部楼层
你的代码的时间复杂度是O(n*q),其中n是人数,q是事件次数。因为在每次事件中,你都需要遍历所有人来找到第一个可用的位置进行操作。

我给你提供一个改进时间复杂度的思路:
1. 首先,我们需要记录每个人的当前位置和他们上一次返回的时间。
2. 然后,我们按照事件发生的时间顺序处理每个事件。对于每个事件,我们需要找到第一个可用的位置,并更新该人的位置和返回时间,并将红包金额加到该人的总金额中。
3. 为了寻找第一个可用的位置,我们可以使用一个队列来存储每个人。当有人收到红包离开队列时,我们将他们的位置和返回时间入队。
4. 在处理每个事件时,我们只需要检查队列头部的人是否可以参与当前事件。如果队列为空或队列头部的人无法参与当前事件(即他的返回时间晚于当前事件的发生时间),那么该事件就没有人能够参与,直接跳过。
5. 如果队列头部的人可以参与当前事件,我们将其位置和返回时间出队,并将红包金额加到该人的总金额中。然后,根据当前事件的发生时间和持续时间,计算该人下一次返回的时间,并将他的位置和返回时间入队。
6. 最后,我们遍历每个人,输出他们获得的总金额。

下面是一个改进时间复杂度的示例代码:

#include <iostream>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;

struct Person {
    ll position;
    ll returnTime;
    ll totalMoney;

    Person(ll p, ll rt, ll tm) : position(p), returnTime(rt), totalMoney(tm) {}
};

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    long n, q;
    ll time, money, dtime;

    cin >> n >> q;

    vector<Person> people;

    for (ll i = 0; i < q; i++) {
        cin >> time >> money >> dtime;

        // Check if the event has no one to receive the red packet
        if (people.empty() || people.front().returnTime > time) {
            continue;
        }

        Person p = people.front();
        people.pop();

        p.totalMoney += money;
        p.returnTime = time + dtime;

        people.push(p);
    }

    for (auto p : people) {
        cout << p.totalMoney << " ";
    }

    return 0;
}
这段代码的时间复杂度是O(q),其中q是事件次数。我们将每个人的信息存储在一个队列中,按照事件发生的顺序进行处理。只有队列头部的人才能参与当前事件,这减少了不必要的遍历,提高了效率。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-1 23:40

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表