편지 n통이 한 파일에 이어 붙어 있다.
편지 하나는 머리 줄 한 줄, 본문 k줄, 첨부 a줄이 이 차례로 이어진 것이다.
머리 줄은 "이름 k a" 꼴이다. 이름은 보낸 사람이고, k는 본문 줄 수, a는 첨부 줄 수이다.
본문 줄은 쓴 그대로의 한 줄이다. 영어 글자, 숫자, 빈칸, 그리고 . , ! ? 로만 이루어지고 길이는 0자부터 80자까지이다.
본문 줄은 아무 글자도 없는 빈 줄일 수 있고, 빈칸으로 시작하거나 끝날 수 있고, 빈칸이 여러 개 이어질 수 있고, 빈칸만 있을 수도 있다.
본문 줄이 머리 줄이나 수처럼 생겼더라도 본문이다. 어디까지가 본문인지는 k로만 정해진다.
첨부 줄은 "파일이름 크기" 꼴이다.
본문에서 낱말은 빈칸이 아닌 글자가 이어진 한 덩어리를 말한다.
편지마다 다음 네 가지를 구하라.
첫째, 낱말이 하나라도 있는 본문 줄의 수.
둘째, 본문 전체의 낱말 수.
셋째, 가장 긴 본문 줄의 길이. 길이에는 앞뒤 빈칸을 포함해 그 줄의 모든 글자를 센다. 본문이 없으면 0이다.
넷째, 첨부 크기의 합. 첨부가 없으면 0이다.
편지가 주어진 차례대로 한 줄에 하나씩, 이름과 위의 네 수를 빈칸 하나로 띄워 출력하라.
입력
첫 줄에 n이 주어진다. 이어서 편지 n통이 차례로 주어진다. 머리 줄의 이름, k, a와 첨부 줄의 파일이름, 크기는 빈칸 하나로 나뉘고 줄 앞뒤에 빈칸이 없다. 1 ≤ n ≤ 1,000, 0 ≤ k ≤ 100, 0 ≤ a ≤ 20, 1 ≤ 크기 ≤ 1,000,000. 이름은 영어 소문자 1~10자, 파일이름은 영어 소문자·숫자·마침표로 된 1~20자이다. 입력은 모두 합쳐 10,000줄 이하이다
출력
편지마다 한 줄씩 n줄. 이름, 낱말이 있는 본문 줄 수, 낱말 수, 가장 긴 본문 줄의 길이, 첨부 크기의 합
예시 1 · stdin
3
kim 3 2
Hello there, team.
see you at 9
plan.txt 1200
map.png 30500
lee 0 0
park 2 1
lee 0 0
7
notes.md 8
stdout
kim 2 7 18 31700
lee 0 0 0 0
park 2 4 7 8
예시 2 · stdin
2
choi 3 0
a b c
ok
yun 1 1
12
photo.png 1000000
stdout
choi 2 4 8 0
yun 1 1 2 1000000
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
줄 수를 먼저 알려 주고 그만큼 줄을 읽게 하는 입력이 두 겹으로 겹쳐 있어요: n통을 돌면서 통마다 k줄, a줄을 읽어요. 입력을 빈칸으로 한꺼번에 쪼개면 안 돼요. 본문은 줄 그대로가 필요하고, 첫 예시의 lee 0 0처럼 머리 줄같이 생긴 본문도 있어서 세어 가며 읽어야만 구별돼요. 한 줄을 통째로 읽는 방법은 Python input(), Java BufferedReader.readLine(), C# Console.ReadLine(), C++ getline(cin, line), C fgets, 크레이콘 콘솔.줄읽기()예요. JavaScript·TypeScript는 입력 전체를 split("\n")으로 줄 배열로 만들고 자리 번호를 하나씩 올려요. 함정 하나: 수를 읽는 방법과 줄을 읽는 방법을 섞으면 줄이 밀려요. C의 scanf("%d"), C++의 cin >>, Java Scanner의 nextInt()는 수 뒤의 줄바꿈을 남겨서, 바로 다음 fgets·getline·nextLine()이 빈 줄을 읽어요. 그래서 수가 든 줄도 한 줄로 읽은 다음 sscanf, istringstream, split으로 꺼내요. 함정 둘: 빈 줄도 본문 한 줄이에요. 빈 줄을 걸러 내고 읽으면 그 뒤가 한 줄씩 밀려요. 함정 셋: JavaScript에서 입력 전체에 trim()을 하면 마지막 편지의 본문이 빈 줄로 끝날 때 그 줄이 사라져요. 함정 넷: 줄 길이에는 앞뒤 빈칸도 들어가요. Python strip(), JavaScript trim(), 크레이콘 공백제거()를 한 다음에 길이를 재면 짧아져요(첫 예시의 see you at 9는 14자예요). 함정 다섯: 낱말을 셀 때 빈칸 하나로 쪼개면 빈칸이 이어진 곳에서 빈 문자열이 나와요. JavaScript "a b".split(" ")는 3조각이고, C# Split(' ')도 그래서 StringSplitOptions.RemoveEmptyEntries를 줘요. Python split()과 크레이콘 나누기()는 기준을 주지 않으면 이어진 빈칸을 하나로 보고 낱말만 돌려줘요. Java는 StringTokenizer의 countTokens(), C++는 istringstream에서 >>로 꺼낸 횟수, C는 빈칸 다음에 글자가 오는 자리를 세요. 함정 여섯: 빈칸만 있는 줄은 빈 문자열이 아니지만 낱말이 없는 줄이에요. line != ""로 견주면 틀리고, 낱말 수가 0인지 봐야 해요. 함정 일곱: C의 fgets(line, 81, stdin)은 80자까지만 읽어요. 80자짜리 줄이면 줄바꿈이 남아 다음 fgets가 빈 줄을 읽으니, 배열에는 줄바꿈과 끝 표시 '\0'의 자리까지 있어야 해요.
Pythonmain.py · 18 줄
n = int(input())out = []for _ in range(n): # 머리 줄: 이름, 본문 줄 수 k, 첨부 줄 수 a name, k, a = input().split() filled = words = longest = 0 for _ in range(int(k)): line = input() # 줄 끝의 줄바꿈만 떼고 앞뒤 빈칸은 그대로 둔다 count = len(line.split()) # split()은 빈칸이 이어져도 낱말만 돌려준다 if count > 0: filled += 1 words += count longest = max(longest, len(line)) total = 0 for _ in range(int(a)): total += int(input().split()[1]) out.append(f"{name} {filled} {words} {longest} {total}")print("\n".join(out))
JavaScriptmain.js · 24 줄
// 줄 단위로 읽어야 하니 빈칸으로 쪼개지 않는다. 통째로 trim()하지도 않는다: 끝의 빈 줄도 본문일 수 있다const lines = require("fs").readFileSync(0, "utf8").split("\n");let at = 0;const n = Number(lines[at++]);const out = [];for (let i = 0; i < n; i++) { // 머리 줄: 이름, 본문 줄 수 k, 첨부 줄 수 a const [name, k, a] = lines[at++].split(" "); let filled = 0; let words = 0; let longest = 0; for (let j = 0; j < Number(k); j++) { const line = lines[at++]; // split(" ")은 빈칸이 이어지면 빈 문자열을 돌려주니 걸러 낸다 const count = line.split(" ").filter((w) => w !== "").length; if (count > 0) filled++; words += count; longest = Math.max(longest, line.length); } let total = 0; for (let j = 0; j < Number(a); j++) total += Number(lines[at++].split(" ")[1]); out.push(`${name} ${filled} ${words} ${longest} ${total}`);}console.log(out.join("\n"));
TypeScriptmain.ts · 26 줄
import { readFileSync } from "node:fs";// 줄 단위로 읽어야 하니 빈칸으로 쪼개지 않는다. 통째로 trim()하지도 않는다: 끝의 빈 줄도 본문일 수 있다const lines: string[] = readFileSync(0, "utf8").split("\n");let at = 0;const n = Number(lines[at++]);const out: string[] = [];for (let i = 0; i < n; i++) { // 머리 줄: 이름, 본문 줄 수 k, 첨부 줄 수 a const [name, k, a] = lines[at++].split(" "); let filled = 0; let words = 0; let longest = 0; for (let j = 0; j < Number(k); j++) { const line: string = lines[at++]; // split(" ")은 빈칸이 이어지면 빈 문자열을 돌려주니 걸러 낸다 const count = line.split(" ").filter((w) => w !== "").length; if (count > 0) filled++; words += count; longest = Math.max(longest, line.length); } let total = 0; for (let j = 0; j < Number(a); j++) total += Number(lines[at++].split(" ")[1]); out.push(`${name} ${filled} ${words} ${longest} ${total}`);}console.log(out.join("\n"));
JavaMain.java · 31 줄
import java.io.*;import java.util.*;public class Main { public static void main(String[] args) throws IOException { // readLine은 줄바꿈만 떼고 한 줄을 통째로 돌려준다: 앞뒤 빈칸도 빈 줄도 그대로다 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine()); StringBuilder sb = new StringBuilder(); for (int i = 0; i < n; i++) { // 머리 줄: 이름, 본문 줄 수 k, 첨부 줄 수 a String[] head = br.readLine().split(" "); int k = Integer.parseInt(head[1]); int a = Integer.parseInt(head[2]); int filled = 0, words = 0, longest = 0; for (int j = 0; j < k; j++) { String line = br.readLine(); // StringTokenizer는 빈칸이 이어져도 낱말만 센다 int count = new StringTokenizer(line).countTokens(); if (count > 0) filled++; words += count; longest = Math.max(longest, line.length()); } int total = 0; for (int j = 0; j < a; j++) total += Integer.parseInt(br.readLine().split(" ")[1]); sb.append(head[0]).append(' ').append(filled).append(' ').append(words).append(' ') .append(longest).append(' ').append(total).append('\n'); } System.out.print(sb); }}
C#Main.cs · 32 줄
using System;using System.Text;class Program{ static void Main() { // ReadLine은 줄바꿈만 떼고 한 줄을 통째로 돌려준다: 앞뒤 빈칸도 빈 줄도 그대로다 int n = int.Parse(Console.ReadLine()!); var sb = new StringBuilder(); for (int i = 0; i < n; i++) { // 머리 줄: 이름, 본문 줄 수 k, 첨부 줄 수 a string[] head = Console.ReadLine()!.Split(' '); int k = int.Parse(head[1]), a = int.Parse(head[2]); int filled = 0, words = 0, longest = 0; for (int j = 0; j < k; j++) { string line = Console.ReadLine()!; // RemoveEmptyEntries가 없으면 빈칸이 이어질 때 빈 문자열이 낱말로 세어진다 int count = line.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length; if (count > 0) filled++; words += count; longest = Math.Max(longest, line.Length); } int total = 0; for (int j = 0; j < a; j++) total += int.Parse(Console.ReadLine()!.Split(' ')[1]); sb.Append($"{head[0]} {filled} {words} {longest} {total}\n"); } Console.Write(sb); }}
C++main.cpp · 45 줄
#include <algorithm>#include <iostream>#include <sstream>#include <string>using namespace std;int main() { ios::sync_with_stdio(false); cin.tie(nullptr); // 모든 줄을 getline으로 읽는다: cin >> 와 섞으면 >> 가 남긴 줄바꿈 때문에 getline이 빈 줄을 읽는다 string line; getline(cin, line); int n = stoi(line); for (int i = 0; i < n; i++) { // 머리 줄: 이름, 본문 줄 수 k, 첨부 줄 수 a — 읽은 줄을 istringstream에 넣어 >> 로 꺼낸다 getline(cin, line); istringstream head(line); string name; int k, a; head >> name >> k >> a; int filled = 0, words = 0, longest = 0; for (int j = 0; j < k; j++) { getline(cin, line); // >> 는 빈칸이 이어져도 낱말만 하나씩 꺼낸다 istringstream body(line); string word; int count = 0; while (body >> word) count++; if (count > 0) filled++; words += count; longest = max(longest, (int)line.size()); } int total = 0; for (int j = 0; j < a; j++) { getline(cin, line); istringstream file(line); string fileName; int size; file >> fileName >> size; total += size; } cout << name << ' ' << filled << ' ' << words << ' ' << longest << ' ' << total << '\n'; } return 0;}
Cmain.c · 39 줄
#include <stdio.h>#include <string.h>int main(void) { // 한 줄은 80자까지지만 줄바꿈과 끝 표시('\0')까지 들어갈 자리가 있어야 한다 char line[128]; int n; // 수도 fgets로 한 줄을 통째로 읽고 sscanf로 꺼낸다: scanf("%d")는 줄바꿈을 남겨 다음 fgets가 빈 줄을 읽는다 if (!fgets(line, sizeof line, stdin)) return 0; sscanf(line, "%d", &n); for (int i = 0; i < n; i++) { // 머리 줄: 이름, 본문 줄 수 k, 첨부 줄 수 a char name[11]; int k = 0, a = 0; fgets(line, sizeof line, stdin); sscanf(line, "%10s %d %d", name, &k, &a); int filled = 0, words = 0, longest = 0; for (int j = 0; j < k; j++) { fgets(line, sizeof line, stdin); int len = (int)strcspn(line, "\n"); // 줄바꿈 앞까지의 길이: 앞뒤 빈칸은 그대로 센다 // 빈칸 다음에 빈칸이 아닌 글자가 나올 때마다 낱말 하나가 시작된다 int count = 0; for (int c = 0; c < len; c++) if (line[c] != ' ' && (c == 0 || line[c - 1] == ' ')) count++; if (count > 0) filled++; words += count; if (len > longest) longest = len; } int total = 0; for (int j = 0; j < a; j++) { int size = 0; fgets(line, sizeof line, stdin); sscanf(line, "%*s %d", &size); // %*s: 파일 이름은 읽고 버린다 total += size; } printf("%s %d %d %d %d\n", name, filled, words, longest, total); } return 0;}
Craykonmain.cray · 29 줄
// 줄읽기는 줄바꿈만 떼고 한 줄을 통째로 돌려준다: 앞뒤 빈칸도 빈 줄도 그대로다n = 콘솔.줄읽기().수로변환();반복 (i = 0; i < n; i++){ // 머리 줄: 이름, 본문 줄 수 k, 첨부 줄 수 a head = 콘솔.줄읽기().나누기(); k = head[1].수로변환(); a = head[2].수로변환(); filled = 0; words = 0; longest = 0; 반복 (j = 0; j < k; j++) { line = 콘솔.줄읽기(); count = line.나누기().개수; // 기준 없이 나누면 빈칸이 이어져도 낱말만 돌려준다 만약 (count > 0) { filled += 1; } words += count; longest = 수학.큰수(longest, line.길이); } total = 0; 반복 (j = 0; j < a; j++) { total += 콘솔.줄읽기().나누기()[1].수로변환(); } 콘솔.쓰기(head[0] + " " + filled + " " + words + " " + longest + " " + total);}