{ }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]));}