この問題の値には寿命が 3 種類あります。 遊びの間ずっと続く値(累計の得点、最も高い回戦、続いている回数)、回戦ごとに新しく始まる値(回戦の得点、最初のミスの位置)、次の回戦で 1 回だけ使う値(前の回戦がきれいだったか)。 変数をどこで宣言するかがそのまま寿命です。 C・C++・Java・C#・JS・TS(let)では、ループの中で宣言した変数は回戦ごとに新しく作られ、ブロックが終わると消えます。 罠 1(隠す): 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 の中で入れた値がそのまま外で見えます。 罠 2(ループ変数): 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 を使います。 罠 3: 回戦ごとに新しく始める値をループの外に置くと前の回戦の値が残り、遊びの間ずっと続く値をループの中に置くと回戦ごとに 0 になります。 罠 4: 「前の回戦がきれいだったか」はこの回戦の得点を計算したあとで変えます。 先に変えると、この回戦自身の結果で 2 倍になります。 罠 5: 続いている回数はミスのあった回戦で 0 に戻し、同じ得点なら先の回戦なので >= ではなく > で比べます。 初めの値も違います。 C・C++ のローカル変数は値を入れないまま読むと未定義動作で、どんな値が出るか分からず、Java(might not have been initialized)と C#(CS0165)はコンパイルエラーです。 Craykon には宣言が別になく、初めて値を入れた所で変数ができます。 ブロックや 繰り返す (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);