跳转至

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

题目描述

学校正在选举学生会成员,有 \(n\)\(1 \le n\le 999\))名候选人,每名候选人编号分别从 \(1\)\(n\),现在收集到了 \(m\)\(1 \le m \le 2000000\))张选票,每张选票都写了一个候选人编号。现在想把这些堆积如山的选票按照投票数字从小到大排序。设第 \(i\)\(1 \le i \le m\))张选票上的数字为 \(a_i\),则保证有 \(1 \le a_i \le n\)

输入格式

输入 \(n\)\(m\) 以及 \(m\) 个选票上的数字。

输出格式

求出排序后的选票编号。

输入输出样例 #1

输入 #1

5 10
2 5 2 2 5 2 2 2 1 2

输出 #1

1 2 2 2 2 2 2 2 5 5

快排完全没问题(虽然这题更优是计数排序,但你现在练快排是对的 👍)


📌 题目分析

👉 本质: 对数组进行:

排序(升序)

👉 类型: 快速排序(大数据量)


🧠 解题思路(快排版)

1️⃣ 核心建模

输入:

m 个数字(候选人编号)

目标:

从小到大排序输出

2️⃣ 为什么可以用快排

  • m ≤ 2,000,000(很大)
  • 快排平均复杂度:
O(n log n)

👉 在优化 IO + 合理 pivot 情况下可以通过

3️⃣ 快排核心

① 选 pivot
② 分区
③ 递归

4️⃣ 优化点(这题必须注意‼️)

✅ 1. 快速 IO

ios::sync_with_stdio(false);
cin.tie(nullptr);

✅ 2. pivot 选中间

pivot = a[(l + r) >> 1];

避免退化

✅ 3. 尽量用数组(不要 vector 慢扩容)

5️⃣ 时间复杂度

平均:O(n log n)

💻 C++代码(快排)

#include <bits/stdc++.h>
using namespace std;

const int N = 2000005;
int a[N];
int n, m;

void quick_sort(int l, int r) {
    if (l >= r) return;

    int i = l, j = r;
    int pivot = a[(l + r) >> 1];

    while (i <= j) {
        while (a[i] < pivot) i++;
        while (a[j] > pivot) j--;
        if (i <= j) {
            swap(a[i], a[j]);
            i++, j--;
        }
    }

    if (l < j) quick_sort(l, j);
    if (i < r) quick_sort(i, r);
}

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

    cin >> n >> m;

    for (int i = 0; i < m; i++) cin >> a[i];

    quick_sort(0, m - 1);

    for (int i = 0; i < m; i++) {
        cout << a[i] << " ";
    }

    return 0;
}

⚠️ 易错点(这题用快排容易翻车)

❌ 1. 爆栈(递归太深)

👉 数据极端时可能:

O(n^2) → 栈爆

👉 解决(进阶):

  • 随机 pivot(高级)
  • 或改用 sort

❌ 2. IO 太慢

👉 一定要:

ios::sync_with_stdio(false);
cin.tie(nullptr);

❌ 3. 数组开小

const int N = 2e6 + 5;

🚀 一句话总结

大数据排序 → 快排能做,但不是最优(计数排序更优)