{ }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()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

열쇠를 정렬된 채로 두는 사전이 있는 언어와 없는 언어로 나뉘어요.
Java TreeMap은 subMap(lo, true, hi, true)로 양 끝을 포함한 범위를 바로 잘라 주고, C++ std::map은 lower_bound(lo)부터 upper_bound(hi) 앞까지 돌면 돼요.
C# SortedDictionary도 정렬해 두지만 범위 함수가 없어서 돌면서 걸러요.
Python dict, JS·TS Map, 크레이콘 사전은 넣은 차례라서 열쇠를 꺼내 정렬해야 해요: Python sorted(d), JS·TS [...m.keys()].sort(), 크레이콘 열쇠목록을 정렬().
이 문제의 함정은 '사전 순'이 언어마다 같은 뜻이 아니라는 거예요.
Python의 <·sorted, JS·TS의 <·sort(), Java compareTo, C++ std::string의 <, C strcmp, 크레이콘의 <·정렬()은 글자 코드 순이에요.
그런데 JS localeCompare는 사람이 읽는 순서라 "a7"이 "B10"보다 앞에 와요.
C#은 string.Compare와 기준 없는 SortedDictionary·List.Sort가 기본으로 문화권 규칙을 쓰기 때문에 StringComparer.Ordinal·string.CompareOrdinal을 꼭 줘야 해요(.NET을 문화권 데이터 없이 돌리는 InvariantGlobalization 환경에서만 우연히 글자 코드 순이 돼요).
대소문자를 무시하는 정렬(key=str.lower)도 틀려요.
그리고 범위는 양 끝을 포함하고, "AB"보다 "ABC"가 뒤라는 것도 잊지 말아요.

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){    콘솔.쓰기("없음");}