{ }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()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

一回の番が「まず振って、それからもっと振るかを聞く」形なので、do-while がぴったりです。
Java・C#・C・C++・JavaScript・TypeScript は do { 振る } while (face == 6 && count < 3); と書き、do-while のない Python は while True: の中で振ってから最後に if not (...): break、Craykon は 間 (真) { … もし (!(…)) { 抜ける; } }(韓国語で 동안 (참) { … 만약 (!(…)) { 그만; } })と書きます。
落とし穴は四つ:① 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・Craykon の数は 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;    }    コンソール.書く(이긴사람 + " " + 차례수 + " " + 굴린수);    コンソール.書く(점수.つなぐ(" "));}