다트 놀이를 n판 한다.
한 판에서는 다트를 k번 던지고, 던질 때마다 0점부터 10점까지 얻는다.
0점이 나온 던지기를 '실수'라 하고, 실수가 한 번도 없는 판을 '깨끗한 판'이라 한다.
판마다 값 세 개를 구한다.
판 점수는 그 판의 던지기 점수를 모두 더한 값이다. 다만 바로 앞 판이 깨끗한 판이었으면 그 합의 두 배이다.
첫 판에는 앞 판이 없으므로 두 배가 되지 않는다.
누적 점수는 첫 판부터 그 판까지의 판 점수를 모두 더한 값이다.
첫 실수 자리는 그 판에서 처음으로 0점이 나온 던지기가 몇 번째인지이다(첫 던지기가 1번째). 그 판에 실수가 없으면 0이다.
놀이가 끝나면 값 세 개를 더 구한다.
판 점수가 가장 높은 판의 번호(그런 판이 여럿이면 가장 먼저 한 판), 그 판의 판 점수, 그리고 깨끗한 판이 끊기지 않고 가장 길게 이어진 판 수이다(깨끗한 판이 없으면 0).
예제에서 2번 판은 깨끗하지만 1번 판에 실수가 있었으므로 판 점수는 8 그대로이다.
3번 판은 2번 판이 깨끗했으므로 6의 두 배인 12이다.
4번 판은 자기에게 실수가 있어도 3번 판이 깨끗했으므로 6의 두 배인 12이다.
판 점수 12가 두 번 나왔으므로 가장 높은 판은 먼저 한 3번 판이고, 깨끗한 판은 2번과 3번이 이어져 2판이다.
입력
첫 줄에 n이 주어진다. 다음 n줄에 한 판씩, 던진 횟수 k와 던지기 점수 k개가 던진 차례대로 빈칸 하나로 나뉘어 주어진다. 1 ≤ n ≤ 1,000, 1 ≤ k ≤ 20, 점수는 0 이상 10 이하의 정수
출력
판마다 한 줄에 판 점수, 누적 점수, 첫 실수 자리를 이 차례대로 빈칸 하나로 띄워 출력한다. 마지막 줄에 판 점수가 가장 높은 판의 번호, 그 판의 판 점수, 깨끗한 판이 가장 길게 이어진 판 수를 빈칸 하나로 띄워 출력한다
예시 1 · stdin
4
3 5 0 2
2 4 4
3 1 2 3
2 0 6
stdout
7 7 2
8 15 0
12 27 0
12 39 1
3 12 2
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
이 문제의 값은 수명이 세 가지예요. 놀이 내내 이어지는 값(누적 점수, 가장 높은 판, 이어진 판 수), 판마다 새로 시작하는 값(판 점수, 첫 실수 자리), 다음 판에서 한 번 쓰이는 값(앞 판이 깨끗했는가). 변수를 어디에 선언하느냐가 곧 수명이에요. C·C++·Java·C#·JS·TS(let)는 반복문 안에 선언한 변수가 판마다 새로 생기고 블록이 끝나면 사라져요. 함정 하나(가리기): if 안에서 같은 이름을 또 선언하면 C·C++·JS·TS(let)는 바깥 변수를 가리는 새 변수가 조용히 생겨요. if (prev) { int score = raw * 2; }는 바깥 score를 바꾸지 못해 예제의 3번 판이 6으로 나와요. Java는 variable score is already defined, C#은 CS0136으로 컴파일이 안 돼서 이 실수를 막아 줘요. JS의 var는 블록이 아니라 함수 전체가 범위라서 if 안의 var v = 6이 바깥 v를 바꿔요. Python에는 블록 범위도 선언도 없어서 if 안에서 넣은 값이 그대로 바깥에 보여요. 함정 둘(반복 변수): for (int i …)의 i는 C·C++·Java·C#·TS에서 반복문 밖에서 쓰면 컴파일 오류이고, JS let은 ReferenceError예요. Python은 for i in range(k) 뒤에도 i가 남지만 끝까지 돌았을 때 값이 k가 아니라 k - 1이에요. 그래서 C식으로 'i == k이면 못 찾음'이라고 쓰면 깨끗한 판의 첫 실수 자리가 0이 아니라 k로 나와요(예제의 2번 판이 2). 찾은 자리에서 바로 적거나 for … else를 써요. 함정 셋: 판마다 새로 시작할 값을 반복문 밖에 두면 앞 판의 값이 남고, 놀이 내내 이어질 값을 반복문 안에 두면 판마다 0이 돼요. 함정 넷: '앞 판이 깨끗했는가'는 이 판 점수를 계산한 뒤에 바꿔요. 먼저 바꾸면 이 판 자신의 결과로 두 배가 돼요. 함정 다섯: 이어진 판 수는 실수가 나온 판에서 0으로 되돌리고, 같은 점수면 먼저 한 판이므로 >=가 아니라 >로 견줘요. 처음 값도 달라요. C·C++의 지역 변수는 값을 넣지 않고 읽으면 정의되지 않은 동작이라 어떤 값이 나올지 알 수 없고, Java(might not have been initialized)와 C#(CS0165)은 컴파일 오류예요. 크레이콘에는 선언이 따로 없고 처음 값을 넣는 곳에서 변수가 생겨요. 블록이나 반복 (i = 1; …) 안에서 처음 만든 변수는 그 블록이 끝나면 사라져서 밖에서 쓰면 '아직 만들지 않은 이름'이라며 실행 전에 멈춰요. 그래서 놀이 내내 쓸 값은 반복문 앞에서 total = 0;처럼 먼저 만들어요. 이미 있는 이름에 값을 넣으면 언제나 그 바깥 변수가 바뀌므로 가리기 실수는 생기지 않아요.
Pythonmain.py · 45 줄
import sysdef main(): lines = sys.stdin.read().split("\n") n = int(lines[0]) # 놀이 내내 살아 있는 값 total = 0 best_round = 0 best_score = -1 streak = 0 # 지금 이어지는 깨끗한 판 수 longest = 0 prev_clean = False # 바로 앞 판이 깨끗했는가 (다음 판에서 한 번 쓰고 바뀐다) out = [] for r in range(1, n + 1): throws = [int(v) for v in lines[r].split()][1:] # 이 판에서만 쓰는 값: 판마다 새로 시작한다 miss = 0 for i, s in enumerate(throws): if s == 0: miss = i + 1 # 반복이 끝난 뒤의 i에 기대지 않고, 찾은 그 자리에서 적는다 break score = sum(throws) if prev_clean: score *= 2 # if 안에서 바꿔도 같은 score다 (Python에는 블록 범위가 없다) total += score if score > best_score: best_score = score best_round = r clean = miss == 0 if clean: streak += 1 longest = max(longest, streak) else: streak = 0 prev_clean = clean # 이 판의 결과를 다 쓴 뒤에 넘긴다 out.append(f"{score} {total} {miss}") out.append(f"{best_round} {best_score} {longest}") print("\n".join(out))main()
JavaScriptmain.js · 46 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);// 놀이 내내 살아 있는 값: 반복문 밖에 let으로let total = 0;let bestRound = 0;let bestScore = -1;let streak = 0; // 지금 이어지는 깨끗한 판 수let longest = 0;let prevClean = false; // 바로 앞 판이 깨끗했는가const out = [];for (let r = 1; r <= n; r++) { const throws = lines[r].trim().split(/\s+/).map(Number).slice(1); // 이 판에서만 쓰는 값: 반복문 안에서 선언하면 판마다 새로 생긴다 let miss = 0; for (let i = 0; i < throws.length; i++) { if (throws[i] === 0) { miss = i + 1; // i는 이 for 안에서만 보이므로, 찾은 그 자리에서 적는다 break; } } let score = 0; for (const s of throws) score += s; if (prevClean) { score *= 2; // 여기서 let score를 또 쓰면 바깥 score와 다른 새 변수가 된다 } total += score; if (score > bestScore) { bestScore = score; bestRound = r; } const clean = miss === 0; if (clean) { streak++; if (streak > longest) longest = streak; } else { streak = 0; } prevClean = clean; // 이 판의 결과를 다 쓴 뒤에 넘긴다 out.push(`${score} ${total} ${miss}`);}out.push(`${bestRound} ${bestScore} ${longest}`);console.log(out.join("\n"));
TypeScriptmain.ts · 47 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);// 놀이 내내 살아 있는 값: 반복문 밖에 let으로let total = 0;let bestRound = 0;let bestScore = -1;let streak = 0; // 지금 이어지는 깨끗한 판 수let longest = 0;let prevClean = false; // 바로 앞 판이 깨끗했는가const out: string[] = [];for (let r = 1; r <= n; r++) { const throws: number[] = lines[r].trim().split(/\s+/).map(Number).slice(1); // 이 판에서만 쓰는 값: 반복문 안에서 선언하면 판마다 새로 생긴다 let miss = 0; for (let i = 0; i < throws.length; i++) { if (throws[i] === 0) { miss = i + 1; // i는 이 for 안에서만 보이므로, 찾은 그 자리에서 적는다 break; } } let score = 0; for (const s of throws) score += s; if (prevClean) { score *= 2; // 여기서 let score를 또 쓰면 바깥 score와 다른 새 변수가 된다 } total += score; if (score > bestScore) { bestScore = score; bestRound = r; } const clean: boolean = miss === 0; if (clean) { streak++; if (streak > longest) longest = streak; } else { streak = 0; } prevClean = clean; // 이 판의 결과를 다 쓴 뒤에 넘긴다 out.push(`${score} ${total} ${miss}`);}out.push(`${bestRound} ${bestScore} ${longest}`);console.log(out.join("\n"));
JavaMain.java · 53 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.StringTokenizer;public class Main { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine().trim()); // 놀이 내내 살아 있는 값: 반복문 밖에 선언한다 int total = 0; int bestRound = 0; int bestScore = -1; int streak = 0; // 지금 이어지는 깨끗한 판 수 int longest = 0; boolean prevClean = false; // 바로 앞 판이 깨끗했는가 StringBuilder out = new StringBuilder(); for (int r = 1; r <= n; r++) { StringTokenizer st = new StringTokenizer(br.readLine()); int k = Integer.parseInt(st.nextToken()); // 이 판에서만 쓰는 값: 반복문 안에 선언하면 판마다 새로 생긴다 int miss = 0; int score = 0; for (int i = 1; i <= k; i++) { int s = Integer.parseInt(st.nextToken()); score += s; if (s == 0 && miss == 0) miss = i; // i는 이 for 안에서만 보인다 } if (prevClean) { score *= 2; // 여기에 int score를 또 쓰면 Java는 컴파일 오류다 } total += score; if (score > bestScore) { bestScore = score; bestRound = r; } boolean clean = miss == 0; if (clean) { streak++; longest = Math.max(longest, streak); } else { streak = 0; } prevClean = clean; // 이 판의 결과를 다 쓴 뒤에 넘긴다 out.append(score).append(' ').append(total).append(' ').append(miss).append('\n'); } out.append(bestRound).append(' ').append(bestScore).append(' ').append(longest).append('\n'); System.out.print(out); }}
C#Main.cs · 60 줄
using System;using System.Text;class Program{ static void Main() { int n = int.Parse(Console.ReadLine().Trim()); // 놀이 내내 살아 있는 값: 반복문 밖에 선언한다 int total = 0; int bestRound = 0; int bestScore = -1; int streak = 0; // 지금 이어지는 깨끗한 판 수 int longest = 0; bool prevClean = false; // 바로 앞 판이 깨끗했는가 var sb = new StringBuilder(); for (int r = 1; r <= n; r++) { string[] parts = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); int k = int.Parse(parts[0]); // 이 판에서만 쓰는 값: 반복문 안에 선언하면 판마다 새로 생긴다 int miss = 0; int score = 0; for (int i = 1; i <= k; i++) { int s = int.Parse(parts[i]); score += s; if (s == 0 && miss == 0) miss = i; // i는 이 for 안에서만 보인다 } if (prevClean) { score *= 2; // 여기에 int score를 또 쓰면 C#은 컴파일 오류다 (CS0136) } total += score; if (score > bestScore) { bestScore = score; bestRound = r; } bool clean = miss == 0; if (clean) { streak++; longest = Math.Max(longest, streak); } else { streak = 0; } prevClean = clean; // 이 판의 결과를 다 쓴 뒤에 넘긴다 sb.Append(score).Append(' ').Append(total).Append(' ').Append(miss).Append('\n'); } sb.Append(bestRound).Append(' ').Append(bestScore).Append(' ').Append(longest).Append('\n'); Console.Write(sb); }}
C++main.cpp · 51 줄
#include <algorithm>#include <iostream>int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n; std::cin >> n; // 놀이 내내 살아 있는 값: 반복문 밖에 선언하고 처음 값을 꼭 넣는다 int total = 0; int bestRound = 0; int bestScore = -1; int streak = 0; // 지금 이어지는 깨끗한 판 수 int longest = 0; bool prevClean = false; // 바로 앞 판이 깨끗했는가 for (int r = 1; r <= n; r++) { int k; std::cin >> k; // 이 판에서만 쓰는 값: 반복문 안에 선언하면 판마다 새로 시작한다 int miss = 0; int score = 0; for (int i = 1; i <= k; i++) { int s; std::cin >> s; score += s; if (s == 0 && miss == 0) miss = i; // i는 이 for 안에서만 보인다 } if (prevClean) { score *= 2; // 여기에 int score를 또 쓰면 바깥 score를 가리는 새 변수가 된다 } total += score; if (score > bestScore) { bestScore = score; bestRound = r; } const bool clean = miss == 0; if (clean) { streak++; longest = std::max(longest, streak); } else { streak = 0; } prevClean = clean; // 이 판의 결과를 다 쓴 뒤에 넘긴다 std::cout << score << ' ' << total << ' ' << miss << '\n'; } std::cout << bestRound << ' ' << bestScore << ' ' << longest << '\n';}
Cmain.c · 49 줄
#include <stdio.h>int main(void) { int n; scanf("%d", &n); /* 놀이 내내 살아 있는 값: 반복문 밖에 선언하고 처음 값을 꼭 넣는다 */ int total = 0; int best_round = 0; int best_score = -1; int streak = 0; /* 지금 이어지는 깨끗한 판 수 */ int longest = 0; int prev_clean = 0; /* 바로 앞 판이 깨끗했는가 */ for (int r = 1; r <= n; r++) { int k; scanf("%d", &k); /* 이 판에서만 쓰는 값: 반복문 안에 선언하면 판마다 새로 시작한다 */ int miss = 0; int score = 0; for (int i = 1; i <= k; i++) { int s; scanf("%d", &s); score += s; if (s == 0 && miss == 0) miss = i; /* i는 이 for 안에서만 보인다 */ } if (prev_clean) { score *= 2; /* 여기에 int score를 또 쓰면 바깥 score를 가리는 새 변수가 된다 */ } total += score; if (score > best_score) { best_score = score; best_round = r; } int clean = miss == 0; if (clean) { streak++; if (streak > longest) longest = streak; } else { streak = 0; } prev_clean = clean; /* 이 판의 결과를 다 쓴 뒤에 넘긴다 */ printf("%d %d %d\n", score, total, miss); } printf("%d %d %d\n", best_round, best_score, longest); return 0;}
Craykonmain.cray · 50 줄
n = 콘솔.줄읽기().수로변환();// 놀이 내내 살아 있는 값: 반복문 앞에서 먼저 만든다total = 0;bestRound = 0;bestScore = -1;streak = 0; // 지금 이어지는 깨끗한 판 수longest = 0;prevClean = 거짓; // 바로 앞 판이 깨끗했는가반복 (r = 1; r <= n; r++){ 줄 = 콘솔.수들읽기(); // 이 판에서만 쓰는 값: 반복문 안에서 처음 만들면 판마다 새로 시작한다 miss = 0; score = 0; 반복 (i = 1; i <= 줄[0]; i++) { score = score + 줄[i]; 만약 (줄[i] == 0 && miss == 0) { miss = i; // i는 이 반복 안에서만 보인다 } } 만약 (prevClean) { score = score * 2; // 이미 있는 이름에 넣으면 바깥 score가 바뀐다 } total = total + score; 만약 (score > bestScore) { bestScore = score; bestRound = r; } clean = miss == 0; 만약 (clean) { streak = streak + 1; longest = 수학.큰수(longest, streak); } 아니면 { streak = 0; } prevClean = clean; // 이 판의 결과를 다 쓴 뒤에 넘긴다 콘솔.쓰기(score + " " + total + " " + miss);}콘솔.쓰기(bestRound + " " + bestScore + " " + longest);