n 行 "总累计 类别累计"(超过的那一刻末尾加 " over"),然后每个类别按字典序一行 "类别 花费 上限 剩余"
样例 1 · stdin
3
food 50000
rent 300000
book 20000
6
food 30000
rent 300000
food 25000
game 5000
food -10000
food 6000
stdout
30000 30000
330000 300000
355000 55000 over
360000 5000 over
350000 45000
356000 51000 over
book 0 20000 20000
food 51000 50000 -1000
game 5000 0 -5000
rent 300000 300000 0
样例 2 · stdin
1
bus 0
4
bus 0
bus -500
bus 500
bus 1
stdout
0 0
-500 -500
0 0
1 1 over
bus 1 0 -1
main.py
错误列表00F8 ↓ · ⇧F8 ↑
输入(stdin)
运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。
$ 就绪
请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。
其他语言怎么写?查看各语言题解 · 8 种语言题解
这道题同时维护两种累计:一个总的,以及字典里每个类别一个。 总累计可达 3,000 × 10亿 = 3万亿,C 的 int、Java/C# 的 int 会溢出。 C 用 long long,Java/C# 用 long;Python、JS、TS、Craykon 直接就行(3万亿小于 2^53)。 更新字典就是“没有就从 0 开始”:Python spent.get(name, 0),JS/TS spent.get(name) ?? 0,Java getOrDefault(name, 0L),C# GetValueOrDefault(name, 0),C++ spent[name](没有时会生成 0),Craykon 要先执行 如果 (!spent.包含(name)) { spent[name] = 0; }(韩文 있나)。 上限字典在 C++ 里用 limit[name] 读取会把不存在的类别新加进字典,所以先用 count(name) 查询。 C 没有字典,按顺序查名字表。 最后的表按键的顺序遍历:Python sorted(spent),JS/TS [...spent.keys()].sort(),Java TreeMap,C# SortedDictionary(StringComparer.Ordinal),C++ std::map(始终有序),Craykon 把 键列表 用 排序()(韩文 열쇠목록、정렬),C 用 qsort 加 strcmp。 陷阱一:JS 的 Map、Python 的 dict、Craykon 的字典按插入顺序遍历,不排序就会按预算行的顺序输出。 陷阱二:用 Python limit[name] 读取没有预算的类别会 KeyError,Java long cap = limit.get(name) 拆箱 null 时抛出 NullPointerException。 陷阱三:over 标记的是“超过的那一刻”而不是“超过期间”,所以条件是 before <= cap && after > cap。 陷阱四:总累计用 int,一超过约 21 亿就会绕成负数。
Pythonmain.py · 29 行
import syslines = sys.stdin.read().split("\n")c = int(lines[0])limit = {}spent = {}for line in lines[1:1 + c]: name, cap = line.split() limit[name] = int(cap) spent[name] = 0n = int(lines[1 + c])total = 0out = []for line in lines[2 + c:2 + c + n]: name, amount = line.split() amount = int(amount) cap = limit.get(name, 0) # 예산을 정하지 않은 항목은 한도 0 before = spent.get(name, 0) spent[name] = before + amount total += amount # 전체 누적 row = f"{total} {spent[name]}" if before <= cap < spent[name]: # 한도 안에서 밖으로 넘어간 순간만 row += " over" out.append(row)for name in sorted(spent): # 열쇠를 사전 순으로 cap = limit.get(name, 0) out.append(f"{name} {spent[name]} {cap} {cap - spent[name]}")print("\n".join(out))
JavaScriptmain.js · 30 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const c = Number(lines[0]);const limit = new Map();const spent = new Map();for (const line of lines.slice(1, 1 + c)) { const [name, cap] = line.trim().split(" "); limit.set(name, Number(cap)); spent.set(name, 0);}const n = Number(lines[1 + c]);let total = 0;const out = [];for (const line of lines.slice(2 + c, 2 + c + n)) { const [name, a] = line.trim().split(" "); const amount = Number(a); const cap = limit.get(name) ?? 0; // 예산을 정하지 않은 항목은 한도 0 const before = spent.get(name) ?? 0; const after = before + amount; spent.set(name, after); total += amount; out.push(`${total} ${after}` + (before <= cap && after > cap ? " over" : ""));}// Map은 넣은 차례를 지키므로 열쇠를 따로 정렬해야 사전 순이 된다for (const name of [...spent.keys()].sort()) { const cap = limit.get(name) ?? 0; const s = spent.get(name) ?? 0; out.push(`${name} ${s} ${cap} ${cap - s}`);}console.log(out.join("\n"));
TypeScriptmain.ts · 31 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const c = Number(lines[0]);const limit = new Map<string, number>();const spent = new Map<string, number>();for (const line of lines.slice(1, 1 + c)) { const [name, cap] = line.trim().split(" "); limit.set(name, Number(cap)); spent.set(name, 0);}const n = Number(lines[1 + c]);let total = 0;const out: string[] = [];for (const line of lines.slice(2 + c, 2 + c + n)) { const [name, a] = line.trim().split(" "); const amount = Number(a); const cap = limit.get(name) ?? 0; // 예산을 정하지 않은 항목은 한도 0 const before = spent.get(name) ?? 0; const after = before + amount; spent.set(name, after); total += amount; out.push(`${total} ${after}` + (before <= cap && after > cap ? " over" : ""));}// Map은 넣은 차례를 지키므로 열쇠를 따로 정렬해야 사전 순이 된다for (const name of [...spent.keys()].sort()) { const cap = limit.get(name) ?? 0; const s = spent.get(name) ?? 0; out.push(`${name} ${s} ${cap} ${cap - s}`);}console.log(out.join("\n"));
JavaMain.java · 37 行
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 c = Integer.parseInt(br.readLine().trim()); Map<String, Long> limit = new HashMap<>(); Map<String, Long> spent = new TreeMap<>(); // TreeMap은 열쇠를 사전 순으로 지킨다 for (int i = 0; i < c; i++) { String[] p = br.readLine().trim().split(" "); limit.put(p[0], Long.parseLong(p[1])); spent.put(p[0], 0L); } int n = Integer.parseInt(br.readLine().trim()); long total = 0; // 3,000 × 10억 = 3조라 int로는 넘친다 StringBuilder out = new StringBuilder(); for (int i = 0; i < n; i++) { String[] p = br.readLine().trim().split(" "); long amount = Long.parseLong(p[1]); long cap = limit.getOrDefault(p[0], 0L); // 예산을 정하지 않은 항목은 한도 0 long before = spent.getOrDefault(p[0], 0L); long after = before + amount; spent.put(p[0], after); total += amount; out.append(total).append(' ').append(after); if (before <= cap && after > cap) out.append(" over"); out.append('\n'); } for (Map.Entry<String, Long> e : spent.entrySet()) { long cap = limit.getOrDefault(e.getKey(), 0L); out.append(e.getKey()).append(' ').append(e.getValue()).append(' ') .append(cap).append(' ').append(cap - e.getValue()).append('\n'); } System.out.print(out); }}
C#Main.cs · 41 行
using System;using System.Collections.Generic;using System.Text;class Program{ static void Main() { int c = int.Parse(Console.ReadLine().Trim()); var limit = new Dictionary<string, long>(); var spent = new SortedDictionary<string, long>(StringComparer.Ordinal); // 열쇠를 글자 코드 순으로 for (int i = 0; i < c; i++) { string[] p = Console.ReadLine().Trim().Split(' '); limit[p[0]] = long.Parse(p[1]); spent[p[0]] = 0; } int n = int.Parse(Console.ReadLine().Trim()); long total = 0; // 3,000 × 10억 = 3조라 int로는 넘친다 var sb = new StringBuilder(); for (int i = 0; i < n; i++) { string[] p = Console.ReadLine().Trim().Split(' '); long amount = long.Parse(p[1]); long cap = limit.GetValueOrDefault(p[0], 0); // 예산을 정하지 않은 항목은 한도 0 long before = spent.GetValueOrDefault(p[0], 0); long after = before + amount; spent[p[0]] = after; total += amount; sb.Append(total).Append(' ').Append(after); if (before <= cap && after > cap) sb.Append(" over"); sb.Append('\n'); } foreach (var (name, s) in spent) { long cap = limit.GetValueOrDefault(name, 0); sb.Append($"{name} {s} {cap} {cap - s}\n"); } Console.Write(sb); }}
C++main.cpp · 38 行
#include <iostream>#include <map>#include <string>int main() { std::ios::sync_with_stdio(false); int c, n; std::cin >> c; std::map<std::string, long long> limit; std::map<std::string, long long> spent; // std::map은 열쇠를 정렬해 둔다 for (int i = 0; i < c; i++) { std::string name; long long cap; std::cin >> name >> cap; limit[name] = cap; spent[name] = 0; } std::cin >> n; long long total = 0; // 3,000 × 10억 = 3조라 int로는 넘친다 std::string out; for (int i = 0; i < n; i++) { std::string name; long long amount; std::cin >> name >> amount; // count로 먼저 묻는다: limit[name]이라고 읽으면 없는 열쇠가 0으로 새로 생긴다 long long cap = limit.count(name) ? limit[name] : 0; long long before = spent[name]; // 없으면 []가 0으로 만들어 준다 long long after = before + amount; spent[name] = after; total += amount; out += std::to_string(total) + " " + std::to_string(after) + (before <= cap && after > cap ? " over" : "") + "\n"; } for (const auto& [name, s] : spent) { long long cap = limit.count(name) ? limit[name] : 0; out += name + " " + std::to_string(s) + " " + std::to_string(cap) + " " + std::to_string(cap - s) + "\n"; } std::cout << out;}
Cmain.c · 50 行
#include <stdio.h>#include <stdlib.h>#include <string.h>/* C에는 사전이 없다: 항목은 많아야 100개라 이름 표를 차례로 찾는다 */typedef struct { char name[11]; long long limit, spent; /* 3,000 × 10억 = 3조라 int로는 넘친다 */} Item;static Item items[100];static int count = 0;static int find_or_add(const char* name) { for (int i = 0; i < count; i++) if (strcmp(items[i].name, name) == 0) return i; strcpy(items[count].name, name); items[count].limit = 0; /* 예산을 정하지 않은 항목은 한도 0 */ items[count].spent = 0; return count++;}static int by_name(const void* a, const void* b) { return strcmp(((const Item*)a)->name, ((const Item*)b)->name);}int main(void) { int c, n; char name[11]; long long x; scanf("%d", &c); for (int i = 0; i < c; i++) { scanf("%10s %lld", name, &x); items[find_or_add(name)].limit = x; } scanf("%d", &n); long long total = 0; for (int i = 0; i < n; i++) { scanf("%10s %lld", name, &x); Item* it = &items[find_or_add(name)]; long long before = it->spent; it->spent += x; total += x; printf("%lld %lld%s\n", total, it->spent, before <= it->limit && it->spent > it->limit ? " over" : ""); } qsort(items, count, sizeof items[0], by_name); for (int i = 0; i < count; i++) printf("%s %lld %lld %lld\n", items[i].name, items[i].spent, items[i].limit, items[i].limit - items[i].spent); return 0;}
Craykonmain.cray · 43 行
c = 控制台.读行().转数字();limit = 字典();spent = 字典();循环 (i = 0; i < c; i++){ p = 控制台.读行().去空白().分割(); limit[p[0]] = p[1].转数字(); spent[p[0]] = 0;}n = 控制台.读行().转数字();total = 0;循环 (i = 0; i < n; i++){ p = 控制台.读行().去空白().分割(); name = p[0]; amount = p[1].转数字(); // 없는 열쇠를 읽으면 멈추니 먼저 넣어 둔다(예산을 정하지 않은 항목은 한도 0) 如果 (!limit.包含(name)) { limit[name] = 0; } 如果 (!spent.包含(name)) { spent[name] = 0; } before = spent[name]; spent[name] = before + amount; total = total + amount; row = total + " " + spent[name]; 如果 (before <= limit[name] && spent[name] > limit[name]) { row = row + " over"; } 控制台.输出(row);}// 열쇠목록은 넣은 차례라 사전 순으로 정렬한다names = spent.键列表;names.排序();遍历 (name 在 names){ 控制台.输出(name + " " + spent[name] + " " + limit[name] + " " + (limit[name] - spent[name]));}