{ }codelper
平均值分组自定义排序P0195

观测站平均气温排名

把多个气象观测站发来的气温记录按观测站汇总并排名。
第一行给出记录数 n,接下来 n 行每行给出观测站名称和气温(整数,单位为度),用一个空格隔开。
一个观测站的平均气温是它所有记录的气温之和除以记录数。
比较时连小数部分一起精确比较。
从平均气温最高的观测站开始,每行输出一个。
平均气温完全相同的观测站按名称的字典序排列(小写英文字母的字母顺序,前面部分相同时短的名称在前)。
每行输出观测站名称、记录数、平均气温向下取整后的整数,用一个空格隔开。
向下取整是指不大于平均值的最大整数。
例如 7.5 为 7,-2.5 为 -3,-3 为 -3。

输入
1 ≤ n ≤ 10,000,观测站名称为 1 到 10 个小写英文字母,-50 ≤ 气温 ≤ 50
输出
每个观测站一行:名称、记录数、向下取整的平均值
样例 1 · stdin
9
seoul 3
busan 8
seoul -2
jeju 9
busan 7
daegu -3
incheon 7
daegu -2
incheon 8
stdout
jeju 1 9
busan 2 7
incheon 2 7
seoul 2 0
daegu 2 -3
main.py
输入(stdin)

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

$ 就绪

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

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

这道题的陷阱是用哪种除法求平均值。
在 Java、C#、C、C++ 中整数之间用 / 相除只留下商,7.5 和 7 都变成 7,排名就按名称顺序颠倒了。
Python 的 // 也是商,结果一样。
JS、TS、Craykon 的 / 总是除到小数。
要精确比较,可以用浮点数相除(相同的分数 1/3 和 2/6 会得到完全相同的浮点数),或者交叉相乘,用整数比较 和A × 数B 与 和B × 数A。
向下取整也因语言而异。
Python 的 // 和 math.floor、JS/TS 的 Math.floor、Java 的 Math.floorDiv、C# 的 Math.Floor、Craykon 的 数学.向下取整 都往小的方向取,-2.5 得 -3。
C、C++、Java、C# 的整数 /,JS 的 Math.trunc,Craykon 的 数学.商 向 0 截断,得 -2。
在 C、C++ 中,a / b 有余数且 a 为负数时要减 1。
排序方向相反:"平均值大的在前,名称小的在前"。
在 Python 中按 (平均, 名称) 加 reverse=True 排序会连名称也反过来,所以要用 (-平均, 名称) 作键。
其他语言在比较函数里分别比较这两部分。
Craykon 用 字典() 分组,用 列表.排序(比较函数) 排序。

Pythonmain.py · 15 行
import sys lines = sys.stdin.read().split("\n")n = int(lines[0])total = {}   # 관측소 → 기온 합count = {}   # 관측소 → 기록 수for line in lines[1:n + 1]:    name, t = line.split()    total[name] = total.get(name, 0) + int(t)    count[name] = count.get(name, 0) + 1 # 평균은 나눗셈으로(소수까지) — 평균이 큰 것부터, 같으면 이름 차례order = sorted(total, key=lambda s: (-total[s] / count[s], s))for s in order:    print(s, count[s], total[s] // count[s])  # //는 내림이라 -2.5 → -3
JavaScriptmain.js · 13 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const total = new Map(); // 관측소 → 기온 합const count = new Map(); // 관측소 → 기록 수for (let i = 1; i <= n; i++) {  const [name, t] = lines[i].trim().split(" ");  total.set(name, (total.get(name) ?? 0) + Number(t));  count.set(name, (count.get(name) ?? 0) + 1);}const avg = (s) => total.get(s) / count.get(s);const order = [...total.keys()].sort((x, y) => avg(y) - avg(x) || (x < y ? -1 : x > y ? 1 : 0));// Math.floor는 내림(-2.5 → -3), Math.trunc는 0 쪽으로(-2)console.log(order.map((s) => `${s} ${count.get(s)} ${Math.floor(avg(s))}`).join("\n"));
TypeScriptmain.ts · 14 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const total = new Map<string, number>(); // 관측소 → 기온 합const count = new Map<string, number>(); // 관측소 → 기록 수for (let i = 1; i <= n; i++) {  const [name, t] = lines[i].trim().split(" ");  total.set(name, (total.get(name) ?? 0) + Number(t));  count.set(name, (count.get(name) ?? 0) + 1);}const avg = (s: string): number => total.get(s)! / count.get(s)!;const order: string[] = [...total.keys()].sort((x, y) => avg(y) - avg(x) || (x < y ? -1 : x > y ? 1 : 0));// Math.floor는 내림(-2.5 → -3), Math.trunc는 0 쪽으로(-2)console.log(order.map((s) => `${s} ${count.get(s)} ${Math.floor(avg(s))}`).join("\n"));
JavaMain.java · 35 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map; public class Main {    public static void main(String[] args) throws Exception {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(in.readLine().trim());        Map<String, Integer> total = new HashMap<>(); // 관측소 → 기온 합        Map<String, Integer> count = new HashMap<>(); // 관측소 → 기록 수        for (int i = 0; i < n; i++) {            String[] p = in.readLine().trim().split(" ");            total.merge(p[0], Integer.parseInt(p[1]), Integer::sum);            count.merge(p[0], 1, Integer::sum);        }        List<String> order = new ArrayList<>(total.keySet());        // 정수끼리 나누면 몫만 남는다 → 엇갈려 곱해 정확히 비교한다(a/b > c/d ⇔ a·d > c·b, b·d > 0)        order.sort((x, y) -> {            long left = (long) total.get(y) * count.get(x);            long right = (long) total.get(x) * count.get(y);            if (left != right) return Long.compare(left, right);            return x.compareTo(y);        });        StringBuilder out = new StringBuilder();        for (String s : order) {            // Math.floorDiv는 내림(-5, 2 → -3), / 는 0 쪽으로(-2)            out.append(s).append(' ').append(count.get(s)).append(' ')               .append(Math.floorDiv(total.get(s), count.get(s))).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 36 行
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine());        var total = new Dictionary<string, int>(); // 관측소 → 기온 합        var count = new Dictionary<string, int>(); // 관측소 → 기록 수        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            total[p[0]] = total.GetValueOrDefault(p[0]) + int.Parse(p[1]);            count[p[0]] = count.GetValueOrDefault(p[0]) + 1;        }        var order = new List<string>(total.Keys);        // 정수끼리 나누면 몫만 남는다 → 엇갈려 곱해 정확히 비교한다        order.Sort((x, y) =>        {            long left = (long)total[y] * count[x];            long right = (long)total[x] * count[y];            if (left != right) return left.CompareTo(right);            return string.CompareOrdinal(x, y);        });        var sb = new StringBuilder();        foreach (string s in order)        {            // (int)Math.Floor는 내림(-2.5 → -3), 정수 / 는 0 쪽으로(-2)            int floorAvg = (int)Math.Floor((double)total[s] / count[s]);            sb.Append(s).Append(' ').Append(count[s]).Append(' ').Append(floorAvg).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 31 行
#include <algorithm>#include <iostream>#include <map>#include <string>#include <vector> int main() {    std::ios::sync_with_stdio(false);    int n;    std::cin >> n;    std::map<std::string, std::pair<long long, long long>> st; // 관측소 → (합, 수)    for (int i = 0; i < n; i++) {        std::string name;        int t;        std::cin >> name >> t;        st[name].first += t;        st[name].second++;    }    std::vector<std::pair<std::string, std::pair<long long, long long>>> v(st.begin(), st.end());    // 엇갈려 곱해 정확히 비교한다: a/b > c/d ⇔ a·d > c·b    std::sort(v.begin(), v.end(), [](const auto& x, const auto& y) {        long long left = x.second.first * y.second.second, right = y.second.first * x.second.second;        if (left != right) return left > right;        return x.first < y.first;    });    for (const auto& [name, sc] : v) {        long long q = sc.first / sc.second;            // 0 쪽으로 버린 몫        if (sc.first % sc.second != 0 && sc.first < 0) q--; // 음수는 하나 더 내린다        std::cout << name << ' ' << sc.second << ' ' << q << '\n';    }}
Cmain.c · 59 行
#include <stdio.h>#include <stdlib.h>#include <string.h> typedef struct {    char name[11];    int t;} Rec; typedef struct {    const char *name;    long long sum;    long long cnt;} Station; static Rec recs[10000];static Station st[10000]; static int by_name(const void *a, const void *b) {    return strcmp(((const Rec *)a)->name, ((const Rec *)b)->name);} /* 평균이 큰 것부터: a/b > c/d ⇔ a·d > c·b (b, d > 0) — 정수 나눗셈 없이 정확히 */static int by_avg(const void *pa, const void *pb) {    const Station *x = pa, *y = pb;    long long left = y->sum * x->cnt, right = x->sum * y->cnt;    if (left != right) return left < right ? -1 : 1;    return strcmp(x->name, y->name);} /* 내림: C의 / 는 0 쪽으로 버리므로(-5 / 2 == -2) 음수에서 하나 더 내린다 */static long long floor_div(long long a, long long b) {    long long q = a / b;    if (a % b != 0 && a < 0) q--;    return q;} int main(void) {    int n;    scanf("%d", &n);    for (int i = 0; i < n; i++) scanf("%10s %d", recs[i].name, &recs[i].t);    qsort(recs, n, sizeof recs[0], by_name); /* 같은 이름끼리 붙여 묶는다 */    int k = 0;    for (int i = 0; i < n; i++) {        if (k == 0 || strcmp(st[k - 1].name, recs[i].name) != 0) {            st[k].name = recs[i].name;            st[k].sum = 0;            st[k].cnt = 0;            k++;        }        st[k - 1].sum += recs[i].t;        st[k - 1].cnt++;    }    qsort(st, k, sizeof st[0], by_avg);    for (int i = 0; i < k; i++) {        printf("%s %lld %lld\n", st[i].name, st[i].cnt, floor_div(st[i].sum, st[i].cnt));    }    return 0;}
Craykonmain.cray · 43 行
n = 控制台.读行().转数字();total = 字典(); // 관측소 → 기온 합count = 字典(); // 관측소 → 기록 수循环 (i = 0; i < n; i++){    p = 控制台.读行().去空白().分割();    name = p[0];    如果 (!total.包含(name))    {        total[name] = 0;        count[name] = 0;    }    total[name] += p[1].转数字();    count[name] += 1;} // 평균이 큰 것부터, 같으면 이름 차례평균순(x, y){    ax = total[x] / count[x];    ay = total[y] / count[y];    如果 (ax != ay)    {        返回 ay - ax;    }    如果 (x < y)    {        返回 -1;    }    如果 (x > y)    {        返回 1;    }    返回 0;} order = total.键列表;order.排序(평균순);遍历 (s 在 order){    // 수학.내림은 작은 쪽으로(-2.5 → -3), 수학.몫은 0 쪽으로(-5, 2 → -2)    控制台.输出(s + " " + count[s] + " " + 数学.向下取整(total[s] / count[s]));}