【深基9.例1】选举学生会

GitHub跳转原题关系图返回列表

候选人编号范围很小,用计数数组统计每个编号票数,再按编号升序展开输出。

OJ: luogu

题目 ID: P1271

难度:入门

标签:排序计数python

日期: 2026-07-15 22:10

题意

给出 m 张选票,每张票是 1..n 之间的候选人编号。要求把所有选票编号从小到大输出。

思路

虽然票数最多有 2,000,000,但候选人编号最多只有 999。可以使用计数排序:

  1. count[x] 记录编号 x 出现次数;
  2. 1n 枚举候选人编号;
  3. 每个编号输出 count[x] 次。

这比直接排序更能体现“值域小”的优势。

Python 知识

  • /home/rainboy/mycode/hugo-blog/content/program_language/python/collections_toolkit.md:计数数组适合值域较小的频率统计。
  • /home/rainboy/mycode/hugo-blog/content/program_language/python/oj_input_output_cheatsheet.md:大量输入用 sys.stdin.buffer.read() 更稳。
  • answer.extend([str(candidate)] * count[candidate]) 批量追加重复编号。
  • "\n".join(...)" ".join(...) 适合集中输出。

代码

python
import sys


data = list(map(int, sys.stdin.buffer.read().split()))
n = data[0]
m = data[1]
votes = data[2:]

count = [0] * (n + 1)
for vote in votes:
    count[vote] += 1

answer = []
for candidate in range(1, n + 1):
    answer.extend([str(candidate)] * count[candidate])

print(" ".join(answer))
cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-27 00:00
 * update_at: 2026-07-27 00:00
 */
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005; // 候选人编号最大值

int n, m;
int cnt[MAXN]; // 计数数组,cnt[x] 表示编号 x 获得的票数

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

    cin >> n >> m;

    // 统计每张票
    for (int i = 0; i < m; i++) {
        int vote;
        cin >> vote;
        cnt[vote]++;
    }

    // 按编号从小到大展开输出
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < cnt[i]; j++) {
            cout << i << " ";
        }
    }
    cout << "\n";

    return 0;
}

复杂度

统计 m 张票,展开 m 个结果,时间复杂度是 O(n+m)O(n+m),空间复杂度是 O(n+m)O(n+m)

总结

当待排序元素值域很小、数量很大时,计数排序比比较排序更直接。