徐老师的零食分享队列

【题目来源】

瑞学堂:徐老师的零食分享队列

【题目描述】

徐老师有 \(n\) 包零食,每包零食有一个美味值 \(a_i\)。他决定按照一个有趣的规则分享给排成一队的 \(k\) 个好朋友。

朋友们初始按 \(1\) 到 \(k\) 编号顺序排队。分享规则如下:

  1. 徐老师每次将当前队首的朋友叫到面前。
  2. 如果徐老师还有零食,就给这位朋友一包零食(从剩余零食里按顺序给,即第一包给第一个朋友,第二包给第二个朋友...),这位朋友拿到零食后,其编号会加上这包零食的美味值,然后重新排到队伍的末尾
  3. 如果徐老师没有零食了,那么分享结束。

你的任务是,计算分享结束后,队伍中朋友们的编号(按从队首到队尾的顺序)。假设朋友数量足够多,分享过程中不会没有朋友。

【输入】

第一行两个整数 \(n\) 和 \(k (1≤n,k≤10^5)\),分别表示零食的数量和朋友的数量。
第二行包含 \(n\) 个整数 \(a_1,a_2,...,a_n (1≤a_i≤1000)\),表示每包零食的美味值。

【输出】

输出一行,包含 \(k\) 个整数,表示最终队伍中从队首到队尾的朋友编号,用空格隔开。

【输入样例】

5 3
2 5 1 3 4

【输出样例】

4 6 11

【核心思想】

  1. 问题分析:给定 \(n\) 包零食(每包美味值为 \(a_i\))和 \(k\) 个按 \(1\)\(k\) 编号排队的朋友。按顺序将第 \(i\) 包零食给当前队首朋友,该朋友编号加上 \(a_i\) 后重新排到队尾,重复 \(n\) 次后输出最终队列。这是一个队列模拟问题,关键在于用队列维护"队首取出、修改后队尾插入"的循环顺序。

  2. 算法选择

    • 队列(Queue):利用 FIFO(先进先出) 特性,队首元素出队处理后立即入队到队尾,完美模拟循环排队过程
    • 顺序遍历:按 \(i\)\(1\)\(n\) 的顺序依次分配零食,保证第 \(i\) 包零食的美味值 \(a_i\) 加到当前队首朋友上
  3. 关键步骤

    • 初始化队列:将朋友编号 \(1\)\(k\) 依次 入队,形成初始排队顺序
    • 模拟分配(遍历 \(i\)\(1\)\(n\)):
      • 取出队首朋友编号 \(x\)x = q.front(),并 出队 q.pop()
      • 更新编号:\(x = x + a_i\)(加上第 \(i\) 包零食的美味值)
      • 重新入队:q.push(x)(排到队伍末尾)
    • 输出结果:依次取出队首元素并输出,直到队列为空
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n + k)\),初始化队列 \(O(k)\)\(n\) 次出队入队操作 \(O(n)\),输出 \(O(k)\)
    • 空间复杂度:\(O(k)\),队列中始终最多存储 \(k\) 个朋友编号
  5. 队列模拟的核心思想

    • FIFO 模拟循环结构:队列天然支持"队首处理、队尾等待"的循环逻辑,无需手动维护循环数组或取模运算
    • 状态更新与重新排队:每次处理完一个元素后,将其更新后的状态放回队尾,保证所有元素按固定周期被处理
    • 顺序与轮次的解耦:第 \(i\) 包零食分配给"当前队首"而非"第 \(i\) 个朋友",由队列动态决定接收者,实现规则与数据的分离
    • 适用场景:适用于需要按固定规则循环处理元素、且处理顺序由当前状态动态决定的问题(如轮询调度、约瑟夫环变体等)

【算法标签】

队列

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;    // 定义数组最大容量为100005
int n, k;                // n为零食数量,k为朋友数量
int a[N];                // a[i]表示第i包零食的美味值
queue<int> q;            // 队列q存储当前排队的朋友编号(队首为下一个被叫到的朋友)

int main()
{
    cin >> n >> k;       // 读入零食数量n和朋友数量k
    for (int i = 1; i <= n; i++)  // 读入每包零食的美味值
        cin >> a[i];
    for (int i = 1; i <= k; i++)  // 初始化队列:朋友1到k按顺序排队
        q.push(i);                // 将朋友编号i入队

    // 模拟分享过程:依次处理n包零食
    for (int i = 1; i <= n; i++)  // 第i包零食分给当前队首的朋友
    {
        int x = q.front(); q.pop();  // 取出队首朋友x
        x += a[i];                   // 朋友x的编号加上第i包零食的美味值
        q.push(x);                   // 该朋友重新排到队伍末尾
    }
    // 输出分享结束后队列中朋友的编号(从队首到队尾)
    while (!q.empty())              // 当队列不为空时
    {
        cout << q.front() << " ";  // 输出队首朋友的编号
        q.pop();                    // 该朋友出队
    }
    cout << endl;                   // 输出结束后换行
    return 0;
}

【运行结果】

5 3
2 5 1 3 4
4 6 11
posted @ 2026-08-06 08:44  团爸讲算法  阅读(13)  评论(0)    收藏  举报