{ }codelper
합계큰 정수(64비트)문자열 나누기P0268

소계가 적힌 영수증 검산

도매 시장의 영수증에는 산 물건 줄 사이사이에 소계 줄과 합계 줄이 적혀 있다. 그런데 적힌 소계와 합계가 틀린 곳이 있어서 검산하려 한다. 첫 줄에 영수증의 줄 수 n이 주어지고, 다음 n줄에 영수증이 위에서부터 한 줄씩 주어진다. 줄은 다음 세 가지 가운데 하나이고, 낱말과 수는 빈칸 하나로 띄워 있다. "ITEM p q"는 한 개에 p원인 물건을 q개 산 줄이고, 이 줄의 물건값은 p × q원이다. "SUB s"는 소계 줄이다.
바로 앞의 SUB 줄 다음부터(앞에 SUB 줄이 없으면 영수증 처음부터) 이 줄까지 나온 ITEM 줄의 물건값을 모두 더하면 s원이라고 적은 것이다. "TOTAL s"는 합계 줄이다.
영수증 처음부터 이 줄까지 나온 ITEM 줄의 물건값을 모두 더하면 s원이라고 적은 것이다. TOTAL 줄은 소계를 세는 구역을 끊지 않는다. SUB 줄과 TOTAL 줄에 적힌 수는 물건값이 아니므로 어떤 합에도 더하지 않는다. 영수증의 마지막 줄은 늘 TOTAL 줄이다. SUB 줄과 TOTAL 줄마다 위에서부터 한 줄씩 출력하라. 적힌 값이 실제 합과 같으면 "OK"를, 다르면 "FIX"와 실제 합을 빈칸 하나로 띄워 출력한다. 실제 합은 쉼표 없이 숫자만 쓴다.

입력
1 ≤ n ≤ 10,000, 1 ≤ p ≤ 10,000,000, 1 ≤ q ≤ 1,000, 0 ≤ s ≤ 10^15 (모두 정수, 앞에 0을 붙이지 않음)
출력
SUB·TOTAL 줄마다 한 줄: OK 또는 FIX 실제 합
예시 1 · stdin
6
ITEM 1200 3
ITEM 500 2
SUB 4600
ITEM 9900 1
SUB 9000
TOTAL 14500
stdout
OK
FIX 9900
OK
예시 2 · stdin
4
SUB 0
ITEM 10000000 1000
SUB 10000000000
TOTAL 1410065408
stdout
OK
OK
FIX 10000000000
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

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

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

합을 둘 두고 ITEM 줄마다 둘 다 더한 뒤, SUB 줄에서 소계만 0으로 돌리면 돼요.
첫째 함정은 크기예요.
한 줄의 물건값이 10^10까지, 합은 10^14까지라 C·C++ long long, Java·C# long이 필요해요.
합만 long으로 두고 int p, q를 곱하면 곱하는 순간 int에서 넘쳐요(예시 2의 1410065408이 10^10이 넘친 값이에요).
곱하기 전에 한쪽을 long으로 바꿔요.
Python의 int는 넘치지 않고, JS·TS·크레이콘의 수는 2^53(약 9×10^15)까지 정확해서 10^14는 괜찮아요.
둘째 함정은 줄을 나눈 조각이 문자열이라는 것이에요.
Python int(...), JS·TS Number(...), Java Long.parseLong, C# long.Parse, 크레이콘 .수로변환()으로 바꿔야 해요.
JS·TS에서 "5" === 5는 false라서 바꾸지 않고 견주면 모두 FIX가 되고, 크레이콘은 문자열끼리 곱하려 하면 멈춰요.
낱말 비교도 언어마다 달라요.
Java는 kind.equals("ITEM")(==는 같은 객체인지를 봐요), C는 strcmp(kind, "ITEM") == 0이고, 나머지는 ==(JS·TS ===)로 돼요.
C는 scanf("%7s", kind)처럼 낱말과 수를 한 번에 읽을 수 있어요.
셋째로, 적힌 소계를 합계에 더하거나 TOTAL 줄에서 소계를 0으로 돌리면 뒤의 검산이 모두 어긋나요.

Pythonmain.py · 14 줄
n = int(input())sub = 0    # 지난 SUB 뒤로 산 물건값의 합total = 0  # 처음부터 산 물건값의 합for _ in range(n):    kind, *nums = input().split()    if kind == "ITEM":        amount = int(nums[0]) * int(nums[1])        sub += amount        total += amount    else:        actual = sub if kind == "SUB" else total        print("OK" if int(nums[0]) == actual else f"FIX {actual}")        if kind == "SUB":            sub = 0  # 소계는 구역마다 다시 센다. TOTAL은 구역을 끊지 않는다
JavaScriptmain.js · 18 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);// 합계는 10^14까지: 2^53(약 9×10^15) 안이라 Number로 정확하다let sub = 0, total = 0;const out = [];for (let i = 1; i <= n; i++) {  const [kind, a, b] = lines[i].trim().split(/\s+/);  if (kind === "ITEM") {    const amount = Number(a) * Number(b);    sub += amount;    total += amount;  } else {    const actual = kind === "SUB" ? sub : total;    out.push(Number(a) === actual ? "OK" : `FIX ${actual}`); // 문자열 a와 수를 ===로 견주면 늘 false    if (kind === "SUB") sub = 0;  }}console.log(out.join("\n"));
TypeScriptmain.ts · 19 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);// 합계는 10^14까지: 2^53(약 9×10^15) 안이라 number로 정확하다let sub = 0, total = 0;const out: string[] = [];for (let i = 1; i <= n; i++) {  const [kind, a, b] = lines[i].trim().split(/\s+/);  if (kind === "ITEM") {    const amount: number = Number(a) * Number(b);    sub += amount;    total += amount;  } else {    const actual: number = kind === "SUB" ? sub : total;    out.push(Number(a) === actual ? "OK" : `FIX ${actual}`);    if (kind === "SUB") sub = 0;  }}console.log(out.join("\n"));
JavaMain.java · 29 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(in.readLine().trim());        long sub = 0, total = 0; // 합계는 10^14까지: int로는 넘친다        StringBuilder out = new StringBuilder();        for (int i = 0; i < n; i++) {            StringTokenizer st = new StringTokenizer(in.readLine());            String kind = st.nextToken();            if (kind.equals("ITEM")) { // 문자열은 ==가 아니라 equals로 견준다                // 값 × 개수도 10^10까지: 곱하기 전에 long으로                long amount = Long.parseLong(st.nextToken()) * Long.parseLong(st.nextToken());                sub += amount;                total += amount;            } else {                long actual = kind.equals("SUB") ? sub : total;                long claim = Long.parseLong(st.nextToken());                out.append(claim == actual ? "OK" : "FIX " + actual).append('\n');                if (kind.equals("SUB")) sub = 0;            }        }        System.out.print(out);    }}
C#Main.cs · 30 줄
using System;using System.Text; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine());        long sub = 0, total = 0; // 합계는 10^14까지: int로는 넘친다        var out_ = new StringBuilder();        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            if (p[0] == "ITEM")            {                // 값 × 개수도 10^10까지: 곱하기 전에 long으로                long amount = long.Parse(p[1]) * long.Parse(p[2]);                sub += amount;                total += amount;            }            else            {                long actual = p[0] == "SUB" ? sub : total;                out_.Append(long.Parse(p[1]) == actual ? "OK" : "FIX " + actual).Append('\n');                if (p[0] == "SUB") sub = 0;            }        }        Console.Write(out_);    }}
C++main.cpp · 26 줄
#include <iostream>#include <string> int main() {    std::ios::sync_with_stdio(false);    int n;    std::cin >> n;    long long sub = 0, total = 0; // 합계는 10^14까지: int로는 넘친다    for (int i = 0; i < n; i++) {        std::string kind;        std::cin >> kind;        if (kind == "ITEM") {            long long p, q; // 값 × 개수도 10^10까지            std::cin >> p >> q;            sub += p * q;            total += p * q;        } else {            long long claim;            std::cin >> claim;            long long actual = kind == "SUB" ? sub : total;            if (claim == actual) std::cout << "OK\n";            else std::cout << "FIX " << actual << '\n';            if (kind == "SUB") sub = 0;        }    }}
Cmain.c · 27 줄
#include <stdio.h>#include <string.h> int main(void) {    int n;    scanf("%d", &n);    long long sub = 0, total = 0; /* 합계는 10^14까지: int로는 넘친다 */    for (int i = 0; i < n; i++) {        char kind[8];        scanf("%7s", kind);        if (strcmp(kind, "ITEM") == 0) { /* 문자열은 ==가 아니라 strcmp로 견준다 */            long long p, q; /* 값 × 개수도 10^10까지 */            scanf("%lld %lld", &p, &q);            sub += p * q;            total += p * q;        } else {            long long claim;            scanf("%lld", &claim);            int is_sub = strcmp(kind, "SUB") == 0;            long long actual = is_sub ? sub : total;            if (claim == actual) puts("OK");            else printf("FIX %lld\n", actual);            if (is_sub) sub = 0;        }    }    return 0;}
Craykonmain.cray · 34 줄
n = 콘솔.줄읽기().수로변환();sub = 0; // 지난 SUB 뒤로 산 물건값의 합total = 0; // 처음부터 산 물건값의 합(10^14까지: 2^53 안이라 정확하다)반복 (i = 0; i < n; i++){    p = 콘솔.줄읽기().나누기();    만약 (p[0] == "ITEM")    {        // 나눈 조각은 문자열이다: 수로 바꾼 다음 곱한다        amount = p[1].수로변환() * p[2].수로변환();        sub += amount;        total += amount;    }    아니면    {        actual = total;        만약 (p[0] == "SUB")        {            actual = sub;        }        만약 (p[1].수로변환() == actual)        {            콘솔.쓰기("OK");        }        아니면        {            콘솔.쓰기("FIX " + actual);        }        만약 (p[0] == "SUB")        {            sub = 0;        }    }}