top1编程
← 返回题目
题解

选领诵

1 条题解

  • 0
    @ 2026-8-6 2:22:20

    P4841 选领诵(提高)

    解题思路

    **第一步,理解这个报数游戏。**同学们围成一圈,从第1个同学开始数数,从1数到m,数到m的那个同学就要处理一下:男生数到m直接出局;女生有2次机会,第一次数到m只是“警告”,记下来,第二次数到m才出局。处理完以后,从下一位同学重新开始数。

    **第二步,用什么数据结构?**题目要求用循环队列。我们用数组模拟一个“圆环”:用 pos 记录当前从谁开始报数,用 alive 数组记录每个人还在不在场,用 cnts 数组记录每个女生已经“警告”过几次。报数时一圈一圈往前走,遇到已经出局的人就直接跳过。

    **第三步,按步骤模拟。**每一轮从 pos 开始,让在场的人报数,报到第m个人的时候停下来,这个人就是本轮的“倒霉蛋”。如果他是男生,直接标记出局;如果是女生,把他的警告次数加1,警告满2次才出局。无论出局还是警告,下一轮都从下一位开始。

    **第四步,注意边界情况。**m可以是1,那样每个人报的数都是1,马上就到m;女生出局需要2次,所以哪怕m=1,女生也要等两轮才出局。还要注意报数时跳过已出局的人,不然会数到空位。

    **举例子验证。**比如 n=5,性别是 男男男女女男,m=3。第一轮报到3号女生,警告一次;第二轮报到1号男生,男生出局;第三轮报到4号女生,警告一次;第四轮3号女生警告满2次出局;第五轮2号男生出局;第六轮4号女生警告满2次出局;最后只剩5号男生,他数到m后出局,5号就是领诵,和样例一致。

    参考代码

    // P4841 选领诵:循环报数淘汰,男生1次出局,女生有2次机会(第2次数到m才出局)
    #include <iostream>
    #include <cstdio>
    using namespace std;
    int n, m;
    int sex[25];    // 1男 0女
    int cnts[25];   // 被数到m的次数
    int alive[25];  // 是否在场
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", &sex[i]);
        scanf("%d", &m);
        for (int i = 1; i <= n; i++) alive[i] = 1;
        int rest = n;   // 在场人数
        int pos = 1;    // 从第pos位开始报数
        while (rest > 1) {
            int c = 0;
            while (c < m) {  // 报数1~m
                if (alive[pos]) c++;
                if (c == m) break;
                pos++;
                if (pos > n) pos = 1;
            }
            if (sex[pos] == 1) {  // 男生出局
                alive[pos] = 0;
                rest--;
            } else {              // 女生:第2次数到m才出局
                cnts[pos]++;
                if (cnts[pos] >= 2) {
                    alive[pos] = 0;
                    rest--;
                }
            }
            pos++;  // 从下一位重新报数
            if (pos > n) pos = 1;
            while (rest > 1 && !alive[pos]) {  // 跳过已出局的人
                pos++;
                if (pos > n) pos = 1;
            }
        }
        for (int i = 1; i <= n; i++)
            if (alive[i]) printf("%d\n", i);
        return 0;
    }
    

    复杂度分析

    每淘汰一个人,最坏要把一圈同学都数一遍,人数是n,所以一次淘汰约O(n)步。总共有n-1个人要被淘汰(剩下最后一个当领诵),因此总时间是O(n²·m)。不过题目说n<20,这个规模非常小,即使最坏情况也只要几百步,瞬间就能算完。空间上只用了3个长度n的小数组,是O(n)。

    • 1