{ }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()/标准输入传入(运行中不会等待输入)。

$ 就绪

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

其他语言怎么写?查看各语言题解 · 8 种语言题解

这道题的关键是把输入当作数的流来读,而不是按行读。
C scanf("%d")、C++ std::cin >>、Java Scanner.nextInt() 会跳过数前面所有的空格和换行再读下一个数,所以在哪里换行都没关系。
相反,Python input()、C# Console.ReadLine()、Java BufferedReader.readLine()、Craykon 控制台.读行()・控制台.读数字() 都是一次读一行。
如果以为一个箱子都在一行里,每行处理一个箱子,就会出错。
所以 Python 用 sys.stdin.read().split(),JS/TS 用 readFileSync(0, "utf8").trim().split(/\s+/),C# 用 Console.In.ReadToEnd().Split(..., StringSplitOptions.RemoveEmptyEntries) 一次切分整个输入。
Java 想读得快,可以写一个小函数:StringTokenizer 用完时读下一行。
Craykon 每行用 行.分割() 取出片段,并用变量记住现在等的是箱子数、物品数还是重量。
分隔方式也是陷阱。
JS split(" ") 只把单个空格当分隔符,会出现 "3\n2" 或 "" 这样的片段,Number 会把它们变成 NaN 或 0。
C# 去掉 RemoveEmptyEntries 的话,空格连续处和空行会产生 "",int.Parse 抛出 FormatException。
Python split() 和 Craykon 分割() 不给分隔符时,把任意多个空格当作一个并丢掉空片段(Python 写成 split(" ") 就会产生空片段)。
重量之和可达 10^13,超出 32 位 int,所以 Java、C# 用 long,C、C++ 用 long long。
JS、TS、Craykon 的数在 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);