徐老师的零食分享队列
【题目来源】
瑞学堂:徐老师的零食分享队列
【题目描述】
徐老师有 \(n\) 包零食,每包零食有一个美味值 \(a_i\)。他决定按照一个有趣的规则分享给排成一队的 \(k\) 个好朋友。
朋友们初始按 \(1\) 到 \(k\) 编号顺序排队。分享规则如下:
- 徐老师每次将当前队首的朋友叫到面前。
- 如果徐老师还有零食,就给这位朋友一包零食(从剩余零食里按顺序给,即第一包给第一个朋友,第二包给第二个朋友...),这位朋友拿到零食后,其编号会加上这包零食的美味值,然后重新排到队伍的末尾。
- 如果徐老师没有零食了,那么分享结束。
你的任务是,计算分享结束后,队伍中朋友们的编号(按从队首到队尾的顺序)。假设朋友数量足够多,分享过程中不会没有朋友。
【输入】
第一行两个整数 \(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
【核心思想】
-
问题分析:给定 \(n\) 包零食(每包美味值为 \(a_i\))和 \(k\) 个按 \(1\) 到 \(k\) 编号排队的朋友。按顺序将第 \(i\) 包零食给当前队首朋友,该朋友编号加上 \(a_i\) 后重新排到队尾,重复 \(n\) 次后输出最终队列。这是一个队列模拟问题,关键在于用队列维护"队首取出、修改后队尾插入"的循环顺序。
-
算法选择:
- 队列(Queue):利用 FIFO(先进先出) 特性,队首元素出队处理后立即入队到队尾,完美模拟循环排队过程
- 顺序遍历:按 \(i\) 从 \(1\) 到 \(n\) 的顺序依次分配零食,保证第 \(i\) 包零食的美味值 \(a_i\) 加到当前队首朋友上
-
关键步骤:
- 初始化队列:将朋友编号 \(1\) 到 \(k\) 依次 入队,形成初始排队顺序
- 模拟分配(遍历 \(i\) 从 \(1\) 到 \(n\)):
- 取出队首朋友编号 \(x\):
x = q.front(),并 出队q.pop() - 更新编号:\(x = x + a_i\)(加上第 \(i\) 包零食的美味值)
- 重新入队:
q.push(x)(排到队伍末尾)
- 取出队首朋友编号 \(x\):
- 输出结果:依次取出队首元素并输出,直到队列为空
-
时间/空间复杂度:
- 时间复杂度:\(O(n + k)\),初始化队列 \(O(k)\),\(n\) 次出队入队操作 \(O(n)\),输出 \(O(k)\)
- 空间复杂度:\(O(k)\),队列中始终最多存储 \(k\) 个朋友编号
-
队列模拟的核心思想:
- 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
浙公网安备 33010602011771号