📜  门|门 CS 1999 |第 36 题(1)

📅  最后修改于: 2023-12-03 14:58:35.402000             🧑  作者: Mango

题目描述

某大学每年都要评选“最受学生欢迎的老师”,一共有 $n(n \leq 1000)$ 个老师入围,投票采用一个人一票的投票方式。现在已经公布了前 $m(m \leq 50000)$ 个学生的投票记录,需要你写一个程序,输出目前票数排在前 $k(k \leq n)$ 位的老师编号(老师编号从 $1$ 开始)以及该老师的票数。

输入格式

第一行有三个整数 $n,m,k$,分别表示老师总数,已经投票的学生数目,需要输出的前 $k$ 名。

接下来 $m$ 行,每行一个非负整数,表示该学生所投老师的编号,保证投票的老师编号都不超过 $n$。

输出格式

输出 $k$ 行,每行两个整数,第 $i$ 行表示排名第 $i$ 的老师编号和票数,中间用一个空格隔开。

样例输入

10 10 3
1
2
3
4
5
6
7
8
9
10

样例输出

1 1
2 1
3 1

题解

这是一道典型的离线算法题目。因为前 $m$ 个学生的投票记录已经确定,我们可以对这 $m$ 个投票进行处理,统计每个老师获得的票数,最后再取前 $k$ 名。统计投票数可以用桶或者 map,把老师编号映射到桶或者 map 中,然后遍历每个学生的投票记录,对应的桶或者 map 中的值加一即可。时间复杂度为 $O(m+n)$。

代码实现:

#include <iostream>
#include <algorithm>
#include <map>

using namespace std;

typedef pair<int, int> PII;

const int N = 1010;

int n, m, k;
int a[N];
map<int, int> mp;

int main() {
    cin >> n >> m >> k;
    for (int i = 0; i < m; i++) {
        int x; cin >> x;
        if (mp.count(x)) mp[x]++;
        else mp[x] = 1;
    }
    vector<PII> v;
    for (auto it = mp.begin(); it != mp.end(); it++) {
        v.push_back({it->second, it->first});
    }
    sort(v.rbegin(), v.rend());
    for (int i = 0; i < k; i++) {
        cout << v[i].second << " " << v[i].first << endl;
    }
    return 0;
}

其中,$mp$ 保存每个老师的投票数,$it->first$ 表示老师编号,$it->second$ 表示对应老师的票数。最后对统计结果按票数从大到小排序,输出前 $k$ 名的编号和获得的票数。