{ }codelper
キー順合計P0229

部品コードの範囲で在庫を探す

工場の倉庫に部品が入るたびに「部品コード 数量」が一行ずつ書かれる。
一行目に記録の数 n、続く n 行に記録が与えられ、最後の行に範囲の始め lo と終わり hi が空白一つで区切って与えられる。
同じ部品コードの数量はすべて足す。
部品コードは文字列のまま比べる。
だから "a7" と "A7" は別のコードである。
コードの順は文字コード(ASCII)順である。
先頭の文字から一つずつ比べ、最初に違う文字のコードが小さいほうが前で、一方がもう一方の先頭部分なら短いほうが前である。
文字コードは数字 0〜9 が 48〜57、大文字 A〜Z が 65〜90、小文字 a〜z が 97〜122 なので、"B10" は "B9" より前、"Z" は "a" より前である。
この順で lo 以上 hi 以下の部品コードを、順に一行に一つずつ「部品コード 数量の合計」で出力せよ。
lo と hi は記録にないコードのこともある。
そのようなコードが一つもなければ "なし" を出力せよ。

入力
1 ≤ n ≤ 5,000、1 ≤ 数量 ≤ 1,000(整数)。
部品コードと lo、hi は英大文字・英小文字・数字からなる 1〜6 文字で、上の順で lo は hi より後ではない
出力
範囲内のコードごとに一行(コード、数量の合計)、コードの順。
なければ none を一行
例 1 · stdin
6
B9 4
a7 2
B10 5
A3 1
B9 6
b1 3
B b
stdout
B10 5
B9 10
a7 2
main.py
入力(stdin)

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

$ 準備完了

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

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

キーを並べたまま持つ辞書がある言語とない言語に分かれます。
Java TreeMap は subMap(lo, true, hi, true) で両端を含む範囲をすぐ切り出してくれ、C++ std::map は lower_bound(lo) から upper_bound(hi) の手前まで回せば済みます。
C# SortedDictionary も並べて持ちますが範囲のメソッドがないので、回しながら絞ります。
Python dict、JS・TS Map、Craykon の辞書は入れた順なので、キーを取り出して並べ替えます:Python sorted(d)、JS・TS [...m.keys()].sort()、Craykon キー一覧 を 並べ替え()。
この問題の落とし穴は「辞書順」が言語ごとに同じ意味ではないことです。
Python の <・sorted、JS・TS の <・sort()、Java compareTo、C++ std::string の <、C strcmp、Craykon の <・並べ替え() は文字コード順です。
ところが JS localeCompare は人が読む順なので "a7" が "B10" より前に来ます。
C# は string.Compare と比較子なしの SortedDictionary・List.Sort が既定でカルチャの規則を使うので、StringComparer.Ordinal・string.CompareOrdinal を必ず渡します(.NET をカルチャのデータなしで動かす InvariantGlobalization 環境でだけ、偶然文字コード順になります)。
大文字小文字を無視する並べ替え(key=str.lower)も間違いです。
そして範囲は両端を含み、"ABC" は "AB" より後だということも忘れずに。

Pythonmain.py · 13 行
n = int(input())total = {}for _ in range(n):    code, qty = input().split()    total[code] = total.get(code, 0) + int(qty)lo, hi = input().split()# 문자열의 <, sorted는 글자 코드 순이다(숫자 < 대문자 < 소문자)found = [code for code in sorted(total) if lo <= code <= hi]if found:    for code in found:        print(code, total[code])else:    print("なし")
JavaScriptmain.js · 11 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const total = new Map();for (let i = 1; i <= n; i++) {  const [code, qty] = lines[i].trim().split(" ");  total.set(code, (total.get(code) ?? 0) + Number(qty));}const [lo, hi] = lines[n + 1].trim().split(" ");// sort()는 기준 없이 쓰면 글자 코드 순이다. localeCompare는 사람이 읽는 순(a < B)이라 쓰지 않는다const found = [...total.keys()].filter((code) => lo <= code && code <= hi).sort();console.log(found.length ? found.map((code) => `${code} ${total.get(code)}`).join("\n") : "なし");
TypeScriptmain.ts · 12 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);const total = new Map<string, number>();for (let i = 1; i <= n; i++) {  const [code, qty]: string[] = lines[i].trim().split(" ");  total.set(code, (total.get(code) ?? 0) + Number(qty));}const [lo, hi]: string[] = lines[n + 1].trim().split(" ");// sort()는 기준 없이 쓰면 글자 코드 순이다const found: string[] = [...total.keys()].filter((code) => lo <= code && code <= hi).sort();console.log(found.length ? found.map((code) => `${code} ${total.get(code)}`).join("\n") : "なし");
JavaMain.java · 29 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.Map;import java.util.NavigableMap;import java.util.StringTokenizer;import java.util.TreeMap; public class Main {    public static void main(String[] args) throws Exception {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        // TreeMap은 열쇠를 compareTo 순(글자 코드 순)으로 늘 정렬해 둔다        TreeMap<String, Integer> total = new TreeMap<>();        for (int i = 0; i < n; i++) {            StringTokenizer st = new StringTokenizer(br.readLine());            total.merge(st.nextToken(), Integer.parseInt(st.nextToken()), Integer::sum);        }        StringTokenizer st = new StringTokenizer(br.readLine());        String lo = st.nextToken();        String hi = st.nextToken();        // 양 끝을 포함하는 범위        NavigableMap<String, Integer> range = total.subMap(lo, true, hi, true);        StringBuilder out = new StringBuilder();        for (Map.Entry<String, Integer> e : range.entrySet()) {            out.append(e.getKey()).append(' ').append(e.getValue()).append('\n');        }        System.out.print(range.isEmpty() ? "なし\n" : out);    }}
C#Main.cs · 28 行
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine().Trim());        // 문자열 비교는 문화권 규칙(a < B)이 기본이라, 글자 코드 순인 Ordinal을 꼭 준다        var total = new SortedDictionary<string, int>(StringComparer.Ordinal);        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            total.TryGetValue(p[0], out int t);            total[p[0]] = t + int.Parse(p[1]);        }        string[] r = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        string lo = r[0], hi = r[1];        var sb = new StringBuilder();        foreach (var e in total)        {            if (string.CompareOrdinal(e.Key, lo) >= 0 && string.CompareOrdinal(e.Key, hi) <= 0)                sb.Append(e.Key).Append(' ').Append(e.Value).Append('\n');        }        Console.Write(sb.Length > 0 ? sb.ToString() : "なし\n");    }}
C++main.cpp · 24 行
#include <iostream>#include <map>#include <string> int main() {    std::ios::sync_with_stdio(false);    int n;    std::cin >> n;    // std::map은 열쇠를 글자 코드 순으로 정렬해 둔다    std::map<std::string, int> total;    for (int i = 0; i < n; i++) {        std::string code;        int qty;        std::cin >> code >> qty;        total[code] += qty;    }    std::string lo, hi;    std::cin >> lo >> hi;    // lower_bound(lo): lo 이상인 첫 열쇠, upper_bound(hi): hi보다 큰 첫 열쇠    auto first = total.lower_bound(lo);    auto last = total.upper_bound(hi);    if (first == last) std::cout << "なし\n";    for (auto it = first; it != last; ++it) std::cout << it->first << ' ' << it->second << '\n';}
Cmain.c · 45 行
#include <stdio.h>#include <stdlib.h>#include <string.h> /* C에는 사전이 없다. 코드와 합계를 배열에 모으고, strcmp(글자 코드 순)로 정렬한다 */typedef struct {    char code[8];    int total;} Item; static Item items[5000]; static int by_code(const void *a, const void *b) {    return strcmp(((const Item *)a)->code, ((const Item *)b)->code);} int main(void) {    int n, m = 0;    scanf("%d", &n);    for (int i = 0; i < n; i++) {        char code[16];        int qty;        scanf("%15s %d", code, &qty);        int j = 0;        while (j < m && strcmp(items[j].code, code) != 0) j++;        if (j == m) {            strcpy(items[m].code, code);            items[m].total = 0;            m++;        }        items[j].total += qty;    }    char lo[16], hi[16];    scanf("%15s %15s", lo, hi);    qsort(items, m, sizeof(Item), by_code);    int shown = 0;    for (int j = 0; j < m; j++) {        if (strcmp(items[j].code, lo) >= 0 && strcmp(items[j].code, hi) <= 0) {            printf("%s %d\n", items[j].code, items[j].total);            shown++;        }    }    if (shown == 0) puts("なし");    return 0;}
Craykonmain.cray · 30 行
n = コンソール.行読み().数に();total = 辞書();繰り返す (i = 0; i < n; i++){    p = コンソール.行読み().空白除去().分ける(" ");    もし (!total.含む(p[0]))    {        total[p[0]] = 0;    }    total[p[0]] = total[p[0]] + p[1].数に();}r = コンソール.行読み().空白除去().分ける(" ");lo = r[0];hi = r[1];// 열쇠목록은 넣은 차례다. 정렬()은 문자열을 글자 코드 순으로 늘어놓는다codes = total.キー一覧;codes.並べ替え();shown = 0;それぞれ (code の中 codes){    もし (lo <= code && code <= hi)    {        コンソール.書く(code + " " + total[code]);        shown++;    }}もし (shown == 0){    コンソール.書く("なし");}