{ }codelper
求和64 位整数分割字符串P0268

核对写有小计的收据

批发市场的收据在所买物品的行之间写有小计行和合计行。
但写下的小计和合计有错,所以要核对。
第一行给出收据的行数 n,接下来 n 行从上到下每行给出收据的一行。
每行是下面三种之一,单词和数字之间用一个空格分开。
"ITEM p q" 表示买了 q 个单价 p 元的物品,这一行的金额是 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()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 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、Craykon 的数在 2^53(约 9×10^15)以内是精确的,所以 10^14 没问题。
第二个陷阱是拆开一行得到的片段是字符串。
要用 Python int(...)、JS/TS Number(...)、Java Long.parseLong、C# long.Parse、Craykon .转数字() 转换。
JS/TS 里 "5" === 5 是 false,不转换就比较会全部变成 FIX;Craykon 试图把字符串相乘会停下来。
比较单词的方法也因语言而异。
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;        }    }}