{ }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){    控制台.输出("无");}