{ }codelper
队列模拟P0071

售票处排队

n 个人从前往后按 1 号到 n 号在售票处排队。
i 号想买 tᵢ 张票。
售票处每次给队首的一个人最多卖 m 张票(若还需要的张数少于 m,就只卖那么多)。
买完后如果还需要,这个人就回到队尾重新排队;买齐了就离开队伍。
重复直到队伍为空,按离开队伍的顺序把编号用空格隔开输出在一行。

输入
第一行 n 和 m,第二行 t₁ … tₙ。
1 ≤ n ≤ 1,000,1 ≤ m ≤ 1,000,1 ≤ tᵢ ≤ 1,000
输出
按离开顺序的 n 个编号(一行,空格隔开)
样例 1 · stdin
3 3
4 3 1
stdout
2 3 1
样例 2 · stdin
5 2
5 1 4 2 3
stdout
2 4 3 5 1
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

队伍是从前面取、往后面放的队列。
最多一百万轮,直接照着模拟就行。
各语言使用队列的方式不同:Python 用 collections.deque 的 popleft()(列表的 pop(0) 要把后面的全部前移,很慢),Java ArrayDeque 的 pollFirst()/addLast(),C# Queue<int> 的 Dequeue()/Enqueue(),C++ std::queue 的 front()/pop()/push()。
JavaScript/TypeScript 没有内置队列,容易用 shift(),但它也要前移后面的元素——改成只往数组里 push,并移动队首下标(head)。
C 把大小为 n 的数组当作循环队列(head = (head + 1) % n);队伍里始终不超过 n 人,n 格就够。
Craykon 的解答用 新列表(n, 0) 做循环队列。
按位置移除(0) 也要前移后面的元素,但像这里队伍不超过 1,000 人时,一百万次也足够快。
两个陷阱:从队尾而不是队首取(栈)会让顺序颠倒。
另外是否重新排队要在卖完之后看剩余张数是否大于 0——在卖之前问「需要 m 张以上就重新排队」,正好需要 m 张的人会多绕一圈。

Pythonmain.py · 16 行
from collections import deque n, m = map(int, input().split())need = list(map(int, input().split())) line = deque(range(n))  # 줄에 선 사람의 번호(0부터)left = need[:]          # 아직 사야 할 표order = []while line:    person = line.popleft()    left[person] -= min(m, left[person])    if left[person] > 0:        line.append(person)  # 더 필요하면 맨 뒤로    else:        order.append(person + 1)print(*order)
JavaScriptmain.js · 15 行
const [n, m, ...need] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number); // 배열 + 앞 자리(head)로 큐를 만든다. shift()는 뒤의 것을 모두 당겨서 느릴 수 있다.const line = [];for (let i = 0; i < n; i++) line.push(i);let head = 0;const left = need.slice();const order = [];while (head < line.length) {  const person = line[head++];  left[person] -= Math.min(m, left[person]);  if (left[person] > 0) line.push(person); // 더 필요하면 맨 뒤로  else order.push(person + 1);}console.log(order.join(" "));
TypeScriptmain.ts · 17 行
import { readFileSync } from "node:fs"; const [n, m, ...need]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number); // 배열 + 앞 자리(head)로 큐를 만든다. shift()는 뒤의 것을 모두 당겨서 느릴 수 있다.const line: number[] = [];for (let i = 0; i < n; i++) line.push(i);let head = 0;const left: number[] = need.slice();const order: number[] = [];while (head < line.length) {  const person = line[head++];  left[person] -= Math.min(m, left[person]);  if (left[person] > 0) line.push(person); // 더 필요하면 맨 뒤로  else order.push(person + 1);}console.log(order.join(" "));
JavaMain.java · 30 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayDeque;import java.util.StringJoiner;import java.util.StringTokenizer; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(in.readLine());        int n = Integer.parseInt(st.nextToken());        int m = Integer.parseInt(st.nextToken());        int[] left = new int[n];        ArrayDeque<Integer> line = new ArrayDeque<>();        st = new StringTokenizer(in.readLine());        for (int i = 0; i < n; i++) {            left[i] = Integer.parseInt(st.nextToken());            line.addLast(i);        }        StringJoiner order = new StringJoiner(" ");        while (!line.isEmpty()) {            int person = line.pollFirst();            left[person] -= Math.min(m, left[person]);            if (left[person] > 0) line.addLast(person); // 더 필요하면 맨 뒤로            else order.add(String.valueOf(person + 1));        }        System.out.println(order);    }}
C#Main.cs · 22 行
using System;using System.Collections.Generic;using System.Linq; class Program{    static void Main()    {        int m = int.Parse(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries)[1]);        int[] left = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();        var line = new Queue<int>(Enumerable.Range(0, left.Length));        var order = new List<int>();        while (line.Count > 0)        {            int person = line.Dequeue();            left[person] -= Math.Min(m, left[person]);            if (left[person] > 0) line.Enqueue(person); // 더 필요하면 맨 뒤로            else order.Add(person + 1);        }        Console.WriteLine(string.Join(" ", order));    }}
C++main.cpp · 28 行
#include <algorithm>#include <iostream>#include <queue>#include <vector> int main() {    int n, m;    std::cin >> n >> m;    std::vector<int> left(n);    std::queue<int> line;    for (int i = 0; i < n; i++) {        std::cin >> left[i];        line.push(i);    }    bool first = true;    while (!line.empty()) {        int person = line.front();        line.pop();        left[person] -= std::min(m, left[person]);        if (left[person] > 0) {            line.push(person); // 더 필요하면 맨 뒤로        } else {            std::cout << (first ? "" : " ") << person + 1;            first = false;        }    }    std::cout << "\n";}
Cmain.c · 31 行
#include <stdio.h> #define MAXN 1000 /* 크기 MAXN인 원형 큐: 줄에는 많아야 n명만 있다 */static int queue[MAXN];static int left[MAXN]; int main(void) {    int n, m;    scanf("%d %d", &n, &m);    for (int i = 0; i < n; i++) {        scanf("%d", &left[i]);        queue[i] = i;    }    int head = 0, size = n, printed = 0;    while (size > 0) {        int person = queue[head];        head = (head + 1) % MAXN;        size--;        left[person] -= left[person] < m ? left[person] : m;        if (left[person] > 0) {            queue[(head + size) % MAXN] = person; /* 더 필요하면 맨 뒤로 */            size++;        } else {            printf(printed++ ? " %d" : "%d", person + 1);        }    }    putchar('\n');    return 0;}
Craykonmain.cray · 32 行
첫줄 = 控制台.读数字();n = 첫줄[0];m = 첫줄[1];left = 控制台.读数字(); // 원형 큐: 줄에는 많아야 n명이라 n칸이면 된다. head는 맨 앞 자리, size는 줄 길이.line = 新列表(n, 0);循环 (i = 0; i < n; i++){    line[i] = i;}head = 0;size = n;order = [];当 (size > 0){    person = line[head];    head = (head + 1) % n;    size -= 1;    left[person] -= 数学.较小值(m, left[person]);    如果 (left[person] > 0)    {        // 더 필요하면 맨 뒤로        line[(head + size) % n] = person;        size += 1;    }    否则    {        order.添加(person + 1);    }}控制台.输出(order);