{ }codelper
辞書の更新辞書の走査条件つき並べ替えP0109

リアルタイム上位 3 人

ゲームの得点表に得点の変化が一つずつ届く。
一行目に出来事の数 q、続く q 行に出来事 "名前 変化量" が空白一つで区切られて与えられる。
出来事ごとに、その名前の得点に変化量を足す。
初めて出た名前は 0 点から始まる。
変化量は 0 や負の数のこともあり、得点も負になりうる。
変化量が 0 でもその名前は得点表に載る。
出来事を一つ処理するたびに、得点表にいる人のうち上位三人を一行に "名前:得点" で空白一つずつ空けて出力する。
得点が高い人が上で、得点が同じなら名前が辞書順で前の人が上である。
辞書順では先頭から一文字ずつ比べて文字コード(ASCII)が小さいほうが前(数字は英小文字より前)で、一方が他方の先頭部分なら短いほうが前である。
得点表に三人いなければ、いる人をすべて出力する。

入力
1 ≤ q ≤ 2000、−100 ≤ 変化量 ≤ 100(整数)。
名前は英小文字・数字 1〜10 文字で、異なる名前は多くても 100 個
出力
q 行。
各行に上位から多くても三人の "名前:得点"
例 1 · stdin
6
mina 5
joon 3
mina -4
sora 3
dan 7
joon 1
stdout
mina:5
mina:5 joon:3
joon:3 mina:1
joon:3 sora:3 mina:1
dan:7 joon:3 sora:3
dan:7 joon:4 sora:3
例 2 · stdin
3
kai 0
ari -2
kai -5
stdout
kai:0
kai:0 ari:-2
ari:-2 kai:-5
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

辞書の更新は「なければ 0 から始めて足す」です。
言語によって一行での書き方と、ないキーを読んだときに何が起きるかが違います。
Python scores[name] += d は初めての名前で KeyError になるので、scores.get(name, 0) + d か defaultdict(int) を使います。
JS の Map.get はないと undefined なので、undefined + 5 がNaN になり、エラーも出ません(?? 0 を付けます)。
Java scores.get(name) + d は null を int に戻そうとして NullPointerException になるので merge(name, d, Integer::sum) を使い、C# scores[name] += d は KeyNotFoundException になるので TryGetValue で読みます(なければ 0)。
C++ scores[name] += d は [] が 0 を作ってくれるのでそのまま動きます。
Craykon はないキーを読むと止まるので、先に もし (!scores.含む(name)) { scores[name] = 0; }(韓国語 만약 (!scores.있나(name)) { … })をします。
C には辞書がありませんが、名前は 100 個だけなので名前の表を順に探し、上位を三回選びます。
順位は辞書を回って(名前、得点)の組を集めて並べます:Python sorted(scores.items(), key=lambda kv: (-kv[1], kv[0]))[:3]、Java comparingByValue().reversed().thenComparing(comparingByKey())、C# OrderByDescending(kv => kv.Value).ThenBy(kv => kv.Key)、C++ は partial_sort で先頭三つだけ。
落とし穴は二つ:(得点, 名前) を reverse=True で並べると、同点のとき名前まで z から逆になります。
JS の比較関数が b[1] > a[1] のように true/false を返すと負の数が出ないので並べ替えが崩れます。
b[1] - a[1] のように負・0・正を返しましょう。

Pythonmain.py · 13 行
import sys lines = sys.stdin.read().split("\n")q = int(lines[0])scores = {}out = []for line in lines[1:q + 1]:    name, delta = line.split()    scores[name] = scores.get(name, 0) + int(delta)   # 처음 나온 이름은 0점부터    # 점수가 높은 사람 먼저, 같으면 이름 사전 순    top = sorted(scores.items(), key=lambda kv: (-kv[1], kv[0]))[:3]    out.append(" ".join(f"{n}:{s}" for n, s in top))print("\n".join(out))
JavaScriptmain.js · 13 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const scores = new Map();const out = [];for (const line of lines.slice(1, q + 1)) {  const [name, delta] = line.trim().split(" ");  scores.set(name, (scores.get(name) ?? 0) + Number(delta)); // 없으면 undefined + 수 = NaN  const top = [...scores.entries()]    .sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1)) // 점수 높은 사람 먼저, 같으면 이름 순    .slice(0, 3);  out.push(top.map(([n, s]) => `${n}:${s}`).join(" "));}console.log(out.join("\n"));
TypeScriptmain.ts · 14 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const scores = new Map<string, number>();const out: string[] = [];for (const line of lines.slice(1, q + 1)) {  const [name, delta] = line.trim().split(" ");  scores.set(name, (scores.get(name) ?? 0) + Number(delta)); // 없으면 undefined + 수 = NaN  const top: [string, number][] = [...scores.entries()]    .sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1)) // 점수 높은 사람 먼저, 같으면 이름 순    .slice(0, 3);  out.push(top.map(([n, s]) => `${n}:${s}`).join(" "));}console.log(out.join("\n"));
JavaMain.java · 25 行
import java.io.*;import java.util.*; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int q = Integer.parseInt(br.readLine().trim());        Map<String, Integer> scores = new HashMap<>();        StringBuilder out = new StringBuilder();        Comparator<Map.Entry<String, Integer>> order =            Map.Entry.<String, Integer>comparingByValue().reversed().thenComparing(Map.Entry.comparingByKey());         for (int i = 0; i < q; i++) {            String[] p = br.readLine().trim().split(" ");            scores.merge(p[0], Integer.parseInt(p[1]), Integer::sum); // 없으면 그 값을, 있으면 더한 값을 넣는다             List<Map.Entry<String, Integer>> all = new ArrayList<>(scores.entrySet());            all.sort(order);            StringJoiner sj = new StringJoiner(" ");            for (int j = 0; j < Math.min(3, all.size()); j++) sj.add(all.get(j).getKey() + ":" + all.get(j).getValue());            out.append(sj).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 28 行
using System;using System.Collections.Generic;using System.Linq;using System.Text; class Program{    static void Main()    {        int q = int.Parse(Console.ReadLine().Trim());        var scores = new Dictionary<string, int>();        var sb = new StringBuilder();        for (int i = 0; i < q; i++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            scores.TryGetValue(p[0], out int now); // 없으면 now = 0            scores[p[0]] = now + int.Parse(p[1]);             var top = scores                .OrderByDescending(kv => kv.Value)                .ThenBy(kv => kv.Key, StringComparer.Ordinal)                .Take(3)                .Select(kv => $"{kv.Key}:{kv.Value}");            sb.Append(string.Join(" ", top)).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 29 行
#include <algorithm>#include <iostream>#include <map>#include <string>#include <vector> int main() {    int q;    std::cin >> q;    std::map<std::string, int> scores;    std::string out;    for (int i = 0; i < q; i++) {        std::string name;        int delta;        std::cin >> name >> delta;        scores[name] += delta; // 없는 열쇠는 []가 0으로 만들어 준다         std::vector<std::pair<std::string, int>> all(scores.begin(), scores.end());        // 셋만 필요하니 partial_sort로 앞 세 자리만 맞춘다        size_t k = std::min<size_t>(3, all.size());        std::partial_sort(all.begin(), all.begin() + k, all.end(), [](const auto& a, const auto& b) {            if (a.second != b.second) return a.second > b.second;            return a.first < b.first;        });        for (size_t j = 0; j < k; j++) out += (j ? " " : "") + all[j].first + ":" + std::to_string(all[j].second);        out += "\n";    }    std::cout << out;}
Cmain.c · 46 行
#include <stdio.h>#include <string.h> /* C에는 사전이 없다: 이름은 많아야 100개라 이름 표를 차례로 찾는다 */static char names[100][11];static int score[100];static int count = 0; /* i가 j보다 앞서야 하나: 점수가 높거나, 같으면 이름이 사전 순으로 앞선다 */static int before(int i, int j) {    if (score[i] != score[j]) return score[i] > score[j];    return strcmp(names[i], names[j]) < 0;} int main(void) {    int q;    scanf("%d", &q);    for (int e = 0; e < q; e++) {        char name[11];        int delta, at = -1;        scanf("%10s %d", name, &delta);        for (int i = 0; i < count; i++)            if (strcmp(names[i], name) == 0) { at = i; break; }        if (at < 0) { /* 처음 나온 이름은 0점부터 */            at = count++;            strcpy(names[at], name);            score[at] = 0;        }        score[at] += delta;         /* 세 번 돌며 아직 뽑지 않은 사람 중 가장 앞서는 사람을 고른다 */        int top[3], k = count < 3 ? count : 3;        for (int t = 0; t < k; t++) {            int best = -1;            for (int i = 0; i < count; i++) {                int used = 0;                for (int u = 0; u < t; u++) used |= top[u] == i;                if (!used && (best < 0 || before(i, best))) best = i;            }            top[t] = best;            printf(t ? " %s:%d" : "%s:%d", names[best], score[best]);        }        printf("\n");    }    return 0;}
Craykonmain.cray · 35 行
q = コンソール.行読み().数に();scores = 辞書();繰り返す (e = 0; e < q; e++){    p = コンソール.行読み().空白除去().分ける();    name = p[0];    もし (!scores.含む(name))    {        scores[name] = 0; // 없는 열쇠를 읽으면 멈추니 먼저 0점으로 넣는다    }    scores[name] = scores[name] + p[1].数に();     names = scores.キー一覧;    names.並べ替え(앞선사람먼저);    top = [];    繰り返す (i = 0; i < names.個数 && i < 3; i++)    {        top.追加(names[i] + ":" + scores[names[i]]);    }    コンソール.書く(top.つなぐ(" "));} // 점수가 높은 사람 먼저, 같으면 이름 사전 순앞선사람먼저(앞, 뒤){    もし (scores[앞] != scores[뒤])    {        返す scores[뒤] - scores[앞];    }    もし (앞 < 뒤)    {        返す -1;    }    返す 1;}