{ }codelper
수 여러 개 읽기큰 정수(64비트)P0231

줄이 아무 데서나 바뀌는 저울 기록

창고 저울이 상자에 담긴 물건의 무게를 종이 띠에 찍어 두었다. 종이 띠의 폭이 좁아서, 수가 끝날 때마다 아무 곳에서나 다음 줄로 넘어갈 수 있다. 수 사이에는 빈칸이 하나 이상 있을 수 있고, 줄의 앞뒤에 빈칸이 있거나 빈 줄이 끼어 있을 수도 있다. 수 하나가 두 줄로 나뉘어 끊기지는 않는다. 입력 전체를 처음부터 차례로 읽은 정수들은 다음과 같은 뜻이다. 맨 처음 수는 상자 수 k다. 그 뒤에 1번 상자부터 차례로, 상자마다 물건 수 m이 오고 이어서 그 상자 물건의 무게 m개가 온다. m이 0이면 빈 상자이고, 그 상자의 무게는 하나도 오지 않는다. 상자마다 한 줄에 무게의 합을 출력하라(빈 상자는 0). 마지막 줄에는 무게의 합이 가장 큰 상자의 번호를 출력하라. 합이 가장 큰 상자가 여럿이면 그중 번호가 가장 작은 것을 출력한다.

입력
1 ≤ k ≤ 1,000, 0 ≤ m ≤ 10,000, 모든 상자의 m을 더한 값은 20,000 이하, 1 ≤ 무게 ≤ 1,000,000,000(모두 정수), 한 줄에는 수가 100개 이하
출력
k줄: 상자마다 무게의 합 / 마지막 줄: 합이 가장 큰 상자의 번호
예시 1 · stdin
3 2 500
 700
0

4 100 200
   300 400
stdout
1200
0
1000
1
예시 2 · stdin
2
1
800
2 300
500
stdout
800
800
1
main.py
입력(stdin)

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

$ 준비됐어요

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

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

이 문제의 핵심은 입력을 줄이 아니라 수의 흐름으로 읽는 거예요.
C scanf("%d"), C++ std::cin >>, Java Scanner.nextInt()는 수 앞의 빈칸·줄바꿈을 모두 건너뛰고 다음 수 하나를 읽어서, 줄이 어디서 바뀌든 상관없어요.
반대로 Python input(), C# Console.ReadLine(), Java BufferedReader.readLine(), 크레이콘 콘솔.줄읽기()·콘솔.수들읽기()는 한 줄씩 읽어요.
상자 하나가 한 줄에 다 있다고 믿고 줄마다 상자를 하나씩 처리하면 틀려요.
그래서 Python은 sys.stdin.read().split(), JS·TS는 readFileSync(0, "utf8").trim().split(/\s+/), C#은 Console.In.ReadToEnd().Split(..., StringSplitOptions.RemoveEmptyEntries)로 입력 전체를 한 번에 나눠요.
Java로 빨리 읽으려면 StringTokenizer가 비었을 때 다음 줄을 읽는 작은 함수를 둬요.
크레이콘은 줄마다 줄.나누기()로 조각을 꺼내면서, 지금 기다리는 것이 상자 수인지 물건 수인지 무게인지를 변수로 기억해요.
나누는 기준도 함정이에요.
JS split(" ")는 빈칸 하나만 구분으로 봐서 "3\n2"나 "" 같은 조각이 생기고, Number가 그것을 NaN이나 0으로 바꿔요.
C#에서 RemoveEmptyEntries를 빼면 빈칸이 겹친 곳과 빈 줄에서 ""가 생겨 int.Parse가 FormatException을 내요.
Python split()과 크레이콘 나누기()는 기준을 주지 않으면 빈칸이 몇 개든 하나로 보고 빈 조각을 버려요(Python에서 split(" ")라고 쓰면 빈 조각이 생겨요).
무게의 합은 10^13까지 커져서 32비트 int를 넘으니 Java·C#은 long, C·C++은 long long을 써요.
JS·TS·크레이콘의 수는 2^53까지 정수가 정확하고, Python 정수는 크기 제한이 없어요.
가장 무거운 상자는 >=가 아니라 >로 바꿔야 같은 합일 때 앞 번호가 남아요.

Pythonmain.py · 13 줄
import sys # 줄과 상관없이 입력 전체를 빈칸·줄바꿈으로 나눈 수의 흐름으로 읽는다nums = iter(map(int, sys.stdin.read().split()))k = next(nums)best, best_total = 1, -1for box in range(1, k + 1):    m = next(nums)    total = sum(next(nums) for _ in range(m))    print(total)    if total > best_total:  # 같으면 앞의 상자를 그대로 둔다        best, best_total = box, totalprint(best)
JavaScriptmain.js · 19 줄
// 앞뒤 빈칸을 없앤 뒤 /\s+/로 나누면 여러 빈칸·줄바꿈·빈 줄이 모두 하나의 구분이 된다const nums = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let at = 0;const k = nums[at++];const out = [];let best = 1;let bestTotal = -1;for (let box = 1; box <= k; box++) {  const m = nums[at++];  let total = 0; // 최대 10^13: 2^53 안이라 정확하다  for (let i = 0; i < m; i++) total += nums[at++];  out.push(total);  if (total > bestTotal) {    best = box;    bestTotal = total;  }}out.push(best);console.log(out.join("\n"));
TypeScriptmain.ts · 21 줄
import { readFileSync } from "node:fs";// 앞뒤 빈칸을 없앤 뒤 /\s+/로 나누면 여러 빈칸·줄바꿈·빈 줄이 모두 하나의 구분이 된다const nums: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let at = 0;const next = (): number => nums[at++];const k = next();const out: number[] = [];let best = 1;let bestTotal = -1;for (let box = 1; box <= k; box++) {  const m = next();  let total = 0; // 최대 10^13: 2^53 안이라 정확하다  for (let i = 0; i < m; i++) total += next();  out.push(total);  if (total > bestTotal) {    best = box;    bestTotal = total;  }}out.push(best);console.log(out.join("\n"));
JavaMain.java · 34 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));    static StringTokenizer tok = new StringTokenizer("");     // 지금 줄의 수를 다 쓰면 다음 줄을 읽는다: 줄이 어디서 바뀌든 수만 차례로 나온다    static long next() throws IOException {        while (!tok.hasMoreTokens()) tok = new StringTokenizer(in.readLine());        return Long.parseLong(tok.nextToken());    }     public static void main(String[] args) throws IOException {        int k = (int) next();        StringBuilder out = new StringBuilder();        int best = 1;        long bestTotal = -1;        for (int box = 1; box <= k; box++) {            long m = next();            long total = 0; // 최대 10^13: int로는 넘친다            for (long i = 0; i < m; i++) total += next();            out.append(total).append('\n');            if (total > bestTotal) {                best = box;                bestTotal = total;            }        }        out.append(best).append('\n');        System.out.print(out);    }}
C#Main.cs · 30 줄
using System;using System.Text; class Program{    static void Main()    {        // 입력 전체를 읽고 빈칸·줄바꿈으로 나눈다. 빈 조각(빈칸이 겹친 곳, 빈 줄)은 버린다        string[] nums = Console.In.ReadToEnd().Split(new[] { ' ', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);        int at = 0;        int k = int.Parse(nums[at++]);        var out_ = new StringBuilder();        int best = 1;        long bestTotal = -1;        for (int box = 1; box <= k; box++)        {            int m = int.Parse(nums[at++]);            long total = 0; // 최대 10^13: int로는 넘친다            for (int i = 0; i < m; i++) total += long.Parse(nums[at++]);            out_.Append(total).Append('\n');            if (total > bestTotal)            {                best = box;                bestTotal = total;            }        }        out_.Append(best).Append('\n');        Console.Write(out_);    }}
C++main.cpp · 27 줄
#include <iostream> int main() {    std::ios::sync_with_stdio(false);    std::cin.tie(nullptr);    // >>는 빈칸·줄바꿈을 모두 건너뛰고 다음 수를 읽는다    int k;    std::cin >> k;    int best = 1;    long long bestTotal = -1;    for (int box = 1; box <= k; box++) {        int m;        std::cin >> m;        long long total = 0; // 최대 10^13: int로는 넘친다        for (int i = 0; i < m; i++) {            long long w;            std::cin >> w;            total += w;        }        std::cout << total << '\n';        if (total > bestTotal) {            best = box;            bestTotal = total;        }    }    std::cout << best << '\n';}
Cmain.c · 26 줄
#include <stdio.h> int main(void) {    /* scanf("%d")는 수 앞의 빈칸·줄바꿈을 모두 건너뛴다: 줄이 어디서 바뀌든 상관없다 */    int k;    scanf("%d", &k);    int best = 1;    long long best_total = -1;    for (int box = 1; box <= k; box++) {        int m;        scanf("%d", &m);        long long total = 0; /* 최대 10^13: int로는 넘친다 */        for (int i = 0; i < m; i++) {            long long w;            scanf("%lld", &w);            total += w;        }        printf("%lld\n", total);        if (total > best_total) {            best = box;            best_total = total;        }    }    printf("%d\n", best);    return 0;}
Craykonmain.cray · 44 줄
// 줄마다 수의 개수가 제각각이다. 줄을 읽어 수를 하나씩 꺼내며// "지금 무엇을 기다리는지"(상자 수 → 물건 수 → 무게)를 따라간다k = -1; // 아직 상자 수를 읽지 않았다box = 0; // 지금 상자 번호left = -1; // 이 상자에 남은 무게 수(-1이면 물건 수를 기다린다)total = 0;best = 1;bestTotal = -1;줄 = 콘솔.줄읽기();동안 (줄 != 빈값){    각각 (조각 에서 줄.나누기())    {        x = 조각.수로변환();        만약 (k == -1)        {            k = x;        }        아니면 만약 (left == -1)        {            box++;            left = x;            total = 0;        }        아니면        {            total += x;            left--;        }        // 무게를 다 읽었으면(빈 상자는 바로) 상자 하나가 끝난다        만약 (left == 0)        {            콘솔.쓰기(total);            만약 (total > bestTotal)            {                best = box;                bestTotal = total;            }            left = -1;        }    }    줄 = 콘솔.줄읽기();}콘솔.쓰기(best);