{ }codelper
do-while 반복그대로 따라 하기넘침(오버플로)P0264

6이 나오면 한 번 더 굴리는 주사위 놀이

주사위 놀이를 여러 판 한다. 한 판에는 n명이 있고, 1번부터 n번까지 차례로 돌아가며 한 차례씩 한다(n번 다음은 다시 1번이다).
모두 점수 0에서 시작한다. 주사위는 정해진 규칙으로 수를 만드는 장치이고, 한 판의 모든 사람이 하나를 함께 쓴다. 주사위에는 지금 값 x가 들어 있다.
굴릴 때마다 x를 (a × x + c)를 m으로 나눈 나머지로 바꾸고, 바뀐 x를 6으로 나눈 나머지에 1을 더한 것이 나온 눈이다. 한 사람의 차례에는 다음을 한다. 1.
주사위를 한 번 굴리고, 나온 눈을 이번 차례의 합에 더한다. 2.
나온 눈이 6이고 이번 차례에 굴린 횟수가 3보다 작으면 1로 돌아간다. 3.
이번 차례에 6이 세 번 나왔으면(굴린 세 번이 모두 6이면) 이번 차례의 합은 0이 된다. 4.
이번 차례의 합을 그 사람의 점수에 더한다.
점수가 G 이상이 되면 그 사람이 이기고 그 판이 끝난다. 이기는지는 차례가 끝난 뒤에만 본다.
그러므로 차례에는 적어도 한 번 굴린다. T번째 차례가 끝나도 이긴 사람이 없으면 그 판은 이긴 사람 없이 끝난다. 첫 줄에 판의 수 t, 다음 t줄에 판마다 n, G, T, 처음 x, a, c, m이 빈칸 하나씩을 사이에 두고 주어진다. 판마다 두 줄을 출력하라. 첫 줄에는 이긴 사람의 번호(이긴 사람이 없으면 0), 지난 차례의 수, 주사위를 굴린 횟수를 빈칸 하나씩 띄워 쓴다. 둘째 줄에는 1번부터 n번까지의 점수를 빈칸 하나씩 띄워 쓴다.

입력
1 ≤ t ≤ 50, 1 ≤ n ≤ 8, 1 ≤ G ≤ 10,000, 1 ≤ T ≤ 10,000, 모든 판의 T의 합 ≤ 100,000.
1 ≤ m ≤ 1,000,000, 0 ≤ 처음 x, a, c < m(정수)
출력
판마다 두 줄
예시 1 · stdin
2
2 15 20 1 9 10 19
1 5 3 5 1 0 7
stdout
1 11 15
15 10
0 3 9
0
main.py
입력(stdin)

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

$ 준비됐어요

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

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

한 차례가 '먼저 굴리고, 그다음 더 굴릴지 묻는' 모양이라 do-while이 꼭 맞아요.
Java·C#·C·C++·JavaScript·TypeScript는 do { 굴리기 } while (face == 6 && count < 3);로 쓰고, do-while이 없는 Python은 while True: 안에서 굴린 뒤 끝에서 if not (...): break로, 크레이콘은 동안 (참) { … 만약 (!(…)) { 그만; } }으로 써요.
함정 넷: ① do-while을 보통 while (face == 6 && count < 3)로 바꾸면 들어가기 전에 먼저 물어서, 아직 굴리지 않은 face(0)로는 한 번도 굴리지 않아요.
② a × x는 10^12까지 커져요.
C·C++·Java·C#에서 int로 곱하면 넘쳐서(C·C++는 정의되지 않은 동작, Java·C#은 조용히 음수가 되기도 해요) 눈이 엉뚱해져요.
long long·long으로 곱해요.
Python int는 끝이 없고, JS·TS·크레이콘의 수는 2^53(약 9×10^15)까지 정확해서 10^12는 괜찮아요.
③ 6이 세 번 나오면 거기서 멈추고 0점이에요.
count <= 3이면 네 번째를 굴리고, 0점 처리를 빠뜨리면 18점을 더해요.
반복이 끝난 뒤 마지막 눈이 6이면 세 번 모두 6이었다는 뜻이라 if (face == 6) 한 줄로 알 수 있어요.
④ 이겼는지는 차례가 끝난 뒤에만 봐요.
굴릴 때마다 점수와 합을 더해 G와 비교하면, 6·6·6으로 0점이 될 차례에도 이긴 것으로 쳐요.

Pythonmain.py · 34 줄
import sys lines = sys.stdin.read().split("\n")t = int(lines[0])out = []for line in lines[1 : t + 1]:    n, goal, max_turns, x, a, c, m = map(int, line.split())    scores = [0] * n    winner = 0    turns = 0    rolls = 0    player = 0    while turns < max_turns and winner == 0:        turns += 1        turn_sum = 0        count = 0        # Python에는 do-while이 없다: while True로 들어가 끝에서 멈출지 묻는다(첫 굴림은 언제나 한다)        while True:            x = (a * x + c) % m            face = x % 6 + 1            rolls += 1            count += 1            turn_sum += face            if not (face == 6 and count < 3):                break        if face == 6:  # 세 번 모두 6이면 이번 차례는 0점            turn_sum = 0        scores[player] += turn_sum        if scores[player] >= goal:            winner = player + 1        player = (player + 1) % n    out.append(f"{winner} {turns} {rolls}")    out.append(" ".join(map(str, scores)))print("\n".join(out))
JavaScriptmain.js · 27 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const t = Number(lines[0]);const out = [];for (let g = 1; g <= t; g++) {  // a * x는 10^12까지라 number(2^53까지 정확)로 충분하다  let [n, goal, maxTurns, x, a, c, m] = lines[g].trim().split(" ").map(Number);  const scores = new Array(n).fill(0);  let winner = 0, turns = 0, rolls = 0, player = 0;  while (turns < maxTurns && winner === 0) {    turns++;    let turnSum = 0, count = 0, face;    do {      // 첫 굴림은 언제나 한다      x = (a * x + c) % m;      face = (x % 6) + 1;      rolls++;      count++;      turnSum += face;    } while (face === 6 && count < 3);    if (face === 6) turnSum = 0; // 세 번 모두 6    scores[player] += turnSum;    if (scores[player] >= goal) winner = player + 1;    player = (player + 1) % n;  }  out.push(`${winner} ${turns} ${rolls}`, scores.join(" "));}console.log(out.join("\n"));
TypeScriptmain.ts · 30 줄
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split("\n");const t: number = Number(lines[0]);const out: string[] = [];for (let g = 1; g <= t; g++) {  // a * x는 10^12까지라 number(2^53까지 정확)로 충분하다  const [n, goal, maxTurns, x0, a, c, m] = lines[g].trim().split(" ").map(Number);  let x: number = x0;  const scores: number[] = new Array<number>(n).fill(0);  let winner = 0, turns = 0, rolls = 0, player = 0;  while (turns < maxTurns && winner === 0) {    turns++;    let turnSum = 0, count = 0, face: number;    do {      // 첫 굴림은 언제나 한다      x = (a * x + c) % m;      face = (x % 6) + 1;      rolls++;      count++;      turnSum += face;    } while (face === 6 && count < 3);    if (face === 6) turnSum = 0; // 세 번 모두 6    scores[player] += turnSum;    if (scores[player] >= goal) winner = player + 1;    player = (player + 1) % n;  }  out.push(`${winner} ${turns} ${rolls}`, scores.join(" "));}console.log(out.join("\n"));
JavaMain.java · 36 줄
import java.io.BufferedReader;import java.io.InputStreamReader; public class Main {    public static void main(String[] args) throws Exception {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int t = Integer.parseInt(in.readLine().trim());        StringBuilder out = new StringBuilder();        for (int g = 0; g < t; g++) {            String[] p = in.readLine().trim().split(" ");            int n = Integer.parseInt(p[0]), goal = Integer.parseInt(p[1]), maxTurns = Integer.parseInt(p[2]);            long x = Long.parseLong(p[3]), a = Long.parseLong(p[4]), c = Long.parseLong(p[5]), m = Long.parseLong(p[6]); // a * x는 int를 넘친다            int[] scores = new int[n];            int winner = 0, turns = 0, rolls = 0, player = 0;            while (turns < maxTurns && winner == 0) {                turns++;                int turnSum = 0, count = 0, face;                do { // 첫 굴림은 언제나 한다                    x = (a * x + c) % m;                    face = (int) (x % 6) + 1;                    rolls++;                    count++;                    turnSum += face;                } while (face == 6 && count < 3);                if (face == 6) turnSum = 0; // 세 번 모두 6                scores[player] += turnSum;                if (scores[player] >= goal) winner = player + 1;                player = (player + 1) % n;            }            out.append(winner).append(' ').append(turns).append(' ').append(rolls).append('\n');            for (int i = 0; i < n; i++) out.append(i > 0 ? " " : "").append(scores[i]);            out.append('\n');        }        System.out.print(out);    }}
C#Main.cs · 39 줄
using System;using System.Text; class Program{    static void Main()    {        int t = int.Parse(Console.ReadLine()!.Trim());        var sb = new StringBuilder();        for (int g = 0; g < t; g++)        {            string[] p = Console.ReadLine()!.Trim().Split(' ');            int n = int.Parse(p[0]), goal = int.Parse(p[1]), maxTurns = int.Parse(p[2]);            long x = long.Parse(p[3]), a = long.Parse(p[4]), c = long.Parse(p[5]), m = long.Parse(p[6]); // a * x는 int를 넘친다            int[] scores = new int[n];            int winner = 0, turns = 0, rolls = 0, player = 0;            while (turns < maxTurns && winner == 0)            {                turns++;                int turnSum = 0, count = 0, face;                do // 첫 굴림은 언제나 한다                {                    x = (a * x + c) % m;                    face = (int)(x % 6) + 1;                    rolls++;                    count++;                    turnSum += face;                } while (face == 6 && count < 3);                if (face == 6) turnSum = 0; // 세 번 모두 6                scores[player] += turnSum;                if (scores[player] >= goal) winner = player + 1;                player = (player + 1) % n;            }            sb.Append($"{winner} {turns} {rolls}\n");            sb.Append(string.Join(" ", scores)).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 33 줄
#include <iostream>#include <vector> int main() {    std::ios::sync_with_stdio(false);    int t;    std::cin >> t;    while (t--) {        int n, goal, maxTurns;        long long x, a, c, m; // a * x는 10^12까지 커져서 int로는 넘친다        std::cin >> n >> goal >> maxTurns >> x >> a >> c >> m;        std::vector<int> scores(n, 0);        int winner = 0, turns = 0, rolls = 0, player = 0;        while (turns < maxTurns && winner == 0) {            turns++;            int turnSum = 0, count = 0, face;            do { // 첫 굴림은 언제나 한다                x = (a * x + c) % m;                face = static_cast<int>(x % 6) + 1;                rolls++;                count++;                turnSum += face;            } while (face == 6 && count < 3);            if (face == 6) turnSum = 0; // 세 번 모두 6            scores[player] += turnSum;            if (scores[player] >= goal) winner = player + 1;            player = (player + 1) % n;        }        std::cout << winner << ' ' << turns << ' ' << rolls << '\n';        for (int i = 0; i < n; i++) std::cout << (i ? " " : "") << scores[i];        std::cout << '\n';    }}
Cmain.c · 32 줄
#include <stdio.h> int main(void) {    int t;    scanf("%d", &t);    while (t--) {        int n, goal, maxTurns;        long long x, a, c, m; /* a * x는 10^12까지 커져서 int(약 21억)로는 넘친다 */        scanf("%d %d %d %lld %lld %lld %lld", &n, &goal, &maxTurns, &x, &a, &c, &m);        int scores[8] = {0};        int winner = 0, turns = 0, rolls = 0, player = 0;        while (turns < maxTurns && winner == 0) {            turns++;            int turnSum = 0, count = 0, face;            do { /* 첫 굴림은 언제나 한다 */                x = (a * x + c) % m;                face = (int)(x % 6) + 1;                rolls++;                count++;                turnSum += face;            } while (face == 6 && count < 3);            if (face == 6) turnSum = 0; /* 세 번 모두 6 */            scores[player] += turnSum;            if (scores[player] >= goal) winner = player + 1;            player = (player + 1) % n;        }        printf("%d %d %d\n", winner, turns, rolls);        for (int i = 0; i < n; i++) printf(i ? " %d" : "%d", scores[i]);        putchar('\n');    }    return 0;}
Craykonmain.cray · 49 줄
t = 콘솔.줄읽기().수로변환();반복 (g = 0; g < t; g++){    p = 콘솔.줄읽기().공백제거().나누기();    n = p[0].수로변환();    목표 = p[1].수로변환();    최대차례 = p[2].수로변환();    x = p[3].수로변환();    a = p[4].수로변환();    c = p[5].수로변환();    m = p[6].수로변환();    점수 = 새목록(n, 0);    이긴사람 = 0;    차례수 = 0;    굴린수 = 0;    사람 = 0;    동안 (차례수 < 최대차례 && 이긴사람 == 0)    {        차례수++;        합 = 0;        번 = 0;        눈 = 0;        // 크레이콘에는 do-while이 없다: 동안 (참)으로 들어가 끝에서 멈출지 묻는다(첫 굴림은 언제나 한다)        동안 (참)        {            x = (a * x + c) % m; // 10^12까지라 정확하다            눈 = x % 6 + 1;            굴린수++;            번++;            합 += 눈;            만약 (!(눈 == 6 && 번 < 3))            {                그만;            }        }        만약 (눈 == 6)        {            합 = 0;        }        점수[사람] += 합;        만약 (점수[사람] >= 목표)        {            이긴사람 = 사람 + 1;        }        사람 = (사람 + 1) % n;    }    콘솔.쓰기(이긴사람 + " " + 차례수 + " " + 굴린수);    콘솔.쓰기(점수.잇기(" "));}