サーバーに要求を送るプログラムは、要求が失敗すると少し待ってから送り直す。 作業ごとに最初の待ち時間 b、最大待ち時間 c、最大試行回数 a、待ち時間の予算 T と結果の文字列 s が与えられる。 s の i 番目の文字は i 回目の試行の結果である。 S は成功、F は一時的な失敗(送り直せる)、X は永久的な失敗(送り直さない)である。 作業ごとに、最初は待ち時間 w = b、これまでに待った時間の合計 W = 0 である。 作業ごとに下の 1〜5 を繰り返す。 1. 要求を一回送る(最初の要求は T に関係なく必ず送る)。 2. 結果が S なら "ok" で、X なら "fatal" で終わる。 3. 結果が F で、これまでに a 回送っていれば "exhausted" で終わる。 4. そうでなければ w だけ待つ。 ただし W + w が T より大きければ待たずに "timeout" で終わる(W + w が T と等しければ待つ)。 5. 待ったあと W に w を足し、w を二倍にする。 ただし二倍が c より大きければ w = c とする。 そして 1 に戻る。 一行目に作業の数 q が与えられ、続く q 行に作業ごとの b、c、a、T、s が空白一つずつを挟んで与えられる。 作業ごとに一行に、終わった状態(ok、fatal、exhausted、timeout のいずれかを引用符なしで)、要求を送った回数、W を空白一つずつ区切って、入力の順に出力せよ。
入力
1 ≤ q ≤ 1,000、1 ≤ b ≤ c ≤ 2,000,000,000、1 ≤ a ≤ s の長さ ≤ 100、0 ≤ T ≤ 10^12、s は S・F・X だけからなる
ok 3 300
exhausted 4 550
timeout 2 500
ok 1 0
fatal 2 10
main.py
エラー一覧00F8 ↓ · ⇧F8 ↑
入力(stdin)
実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。
$ 準備完了
コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。
ほかの言語では?言語別の解答を見る · 8 言語の解答
「まず一回送って、最後にもう一度送るか聞く」流れなので do-while がぴったりです:C・C++・Java・C#・JS・TS do { … } while (status == null);。 Python と Craykon には do-while がないので、while True: … break(Craykon 間 (真) … 抜ける;)で「少なくとも一回」を作ります。 落とし穴は while (W + w <= T) { … } のように条件を先に聞くことです。 すると予算が最初の待ち時間より小さいとき(例の四行目 T = 0)、要求を一度も送りません。 上限は三項演算子一行で:C 系・JS・TS w = w * 2 > c ? c : w * 2;、Craykon も同じ形 待ち * 2 > 上限 ? 上限 : 待ち * 2、Python だけ順序が違って c if w * 2 > c else w * 2 です。 見かけは int で足りそうですが、c は 20 億までなので w * 2 は 40 億になり得て、待った合計は 99 × 20 億まで大きくなります。 C・C++ の int はあふれると未定義動作(たいてい負の数に回り込む)で、Java・C# の int は黙って負の数に回り込むので、w * 2 > c が偽になり待ち時間が負になります。 そこで C・C++ は long long、Java・C# は long で受け取ります。 Python の整数は大きさに制限がなく、JS・TS・Craykon は double なので 2^53 以内のこれらの値を正確に扱えます。 3(回数)と 4(予算)を聞く順を入れ替えると、最後の試行のあとで予算を調べてしまい "exhausted" が "timeout" に変わります。
Pythonmain.py · 31 行
import syslines = sys.stdin.read().split("\n")q = int(lines[0])out = []for line in lines[1:q + 1]: b, c, a, t, s = line.split() c, a, t = int(c), int(a), int(t) wait = int(b) # 다음에 기다릴 시간 waited = 0 # 지금까지 기다린 시간의 합 tries = 0 # Python에는 do-while이 없다: while True로 들어가 끝에서 멈출지 정한다(첫 시도는 언제나 한다) while True: result = s[tries] tries += 1 if result == "S": status = "ok" break if result == "X": status = "fatal" break if tries == a: status = "exhausted" break if waited + wait > t: status = "timeout" break waited += wait wait = c if wait * 2 > c else wait * 2 out.append(f"{status} {tries} {waited}")print("\n".join(out))
JavaScriptmain.js · 28 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const out = [];for (let j = 1; j <= q; j++) { const [b, c, a, t, s] = lines[j].trim().split(/\s+/); const cap = Number(c); const maxTries = Number(a); const budget = Number(t); let wait = Number(b); // 다음에 기다릴 시간 let waited = 0; // 지금까지 기다린 시간의 합 let tries = 0; let status = null; // 첫 시도는 언제나 한다: 몸통을 먼저 돌고 끝에서 계속할지 묻는다 do { const result = s[tries]; tries++; if (result === "S") status = "ok"; else if (result === "X") status = "fatal"; else if (tries === maxTries) status = "exhausted"; else if (waited + wait > budget) status = "timeout"; else { waited += wait; wait = wait * 2 > cap ? cap : wait * 2; } } while (status === null); out.push(`${status} ${tries} ${waited}`);}console.log(out.join("\n"));
TypeScriptmain.ts · 29 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const q: number = Number(lines[0]);const out: string[] = [];for (let j = 1; j <= q; j++) { const [b, c, a, t, s] = lines[j].trim().split(/\s+/); const cap: number = Number(c); const maxTries: number = Number(a); const budget: number = Number(t); let wait: number = Number(b); // 다음에 기다릴 시간 let waited = 0; // 지금까지 기다린 시간의 합 let tries = 0; let status: string | null = null; // 첫 시도는 언제나 한다: 몸통을 먼저 돌고 끝에서 계속할지 묻는다 do { const result: string = s[tries]; tries++; if (result === "S") status = "ok"; else if (result === "X") status = "fatal"; else if (tries === maxTries) status = "exhausted"; else if (waited + wait > budget) status = "timeout"; else { waited += wait; wait = wait * 2 > cap ? cap : wait * 2; } } while (status === null); out.push(`${status} ${tries} ${waited}`);}console.log(out.join("\n"));
JavaMain.java · 37 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int q = Integer.parseInt(br.readLine().trim()); StringBuilder out = new StringBuilder(); for (int j = 0; j < q; j++) { String[] p = br.readLine().trim().split("\\s+"); long wait = Long.parseLong(p[0]); // 다음에 기다릴 시간(2배가 int를 넘을 수 있다) long cap = Long.parseLong(p[1]); int maxTries = Integer.parseInt(p[2]); long budget = Long.parseLong(p[3]); String s = p[4]; long waited = 0; // 지금까지 기다린 시간의 합 int tries = 0; String status = null; // 첫 시도는 언제나 한다: 몸통을 먼저 돌고 끝에서 계속할지 묻는다 do { char result = s.charAt(tries); tries++; if (result == 'S') status = "ok"; else if (result == 'X') status = "fatal"; else if (tries == maxTries) status = "exhausted"; else if (waited + wait > budget) status = "timeout"; else { waited += wait; wait = wait * 2 > cap ? cap : wait * 2; } } while (status == null); out.append(status).append(' ').append(tries).append(' ').append(waited).append('\n'); } System.out.print(out); }}
C#Main.cs · 40 行
using System;using System.Text;class Program{ static void Main() { int q = int.Parse(Console.ReadLine().Trim()); var sb = new StringBuilder(); for (int j = 0; j < q; j++) { string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); long wait = long.Parse(p[0]); // 다음에 기다릴 시간(2배가 int를 넘을 수 있다) long cap = long.Parse(p[1]); int maxTries = int.Parse(p[2]); long budget = long.Parse(p[3]); string s = p[4]; long waited = 0; // 지금까지 기다린 시간의 합 int tries = 0; string? status = null; // 첫 시도는 언제나 한다: 몸통을 먼저 돌고 끝에서 계속할지 묻는다 do { char result = s[tries]; tries++; if (result == 'S') status = "ok"; else if (result == 'X') status = "fatal"; else if (tries == maxTries) status = "exhausted"; else if (waited + wait > budget) status = "timeout"; else { waited += wait; wait = wait * 2 > cap ? cap : wait * 2; } } while (status == null); sb.Append(status).Append(' ').Append(tries).Append(' ').Append(waited).Append('\n'); } Console.Write(sb); }}
C++main.cpp · 30 行
#include <iostream>#include <string>int main() { int q; std::cin >> q; for (int j = 0; j < q; j++) { long long wait, cap, budget; // 2배가 int(약 21억)를 넘을 수 있다 int maxTries; std::string s; std::cin >> wait >> cap >> maxTries >> budget >> s; long long waited = 0; // 지금까지 기다린 시간의 합 int tries = 0; std::string status; // 첫 시도는 언제나 한다: 몸통을 먼저 돌고 끝에서 계속할지 묻는다 do { char result = s[tries]; tries++; if (result == 'S') status = "ok"; else if (result == 'X') status = "fatal"; else if (tries == maxTries) status = "exhausted"; else if (waited + wait > budget) status = "timeout"; else { waited += wait; wait = wait * 2 > cap ? cap : wait * 2; } } while (status.empty()); std::cout << status << ' ' << tries << ' ' << waited << '\n'; }}
Cmain.c · 30 行
#include <stdio.h>int main(void) { int q; scanf("%d", &q); for (int j = 0; j < q; j++) { long long wait, cap, budget; /* 2배가 int(약 21억)를 넘을 수 있다 */ int max_tries; char s[128]; scanf("%lld %lld %d %lld %127s", &wait, &cap, &max_tries, &budget, s); long long waited = 0; /* 지금까지 기다린 시간의 합 */ int tries = 0; const char *status = NULL; /* 첫 시도는 언제나 한다: 몸통을 먼저 돌고 끝에서 계속할지 묻는다 */ do { char result = s[tries]; tries++; if (result == 'S') status = "ok"; else if (result == 'X') status = "fatal"; else if (tries == max_tries) status = "exhausted"; else if (waited + wait > budget) status = "timeout"; else { waited += wait; wait = wait * 2 > cap ? cap : wait * 2; } } while (status == NULL); printf("%s %d %lld\n", status, tries, waited); } return 0;}
Craykonmain.cray · 45 行
q = コンソール.行読み().数に();繰り返す (j = 0; j < q; j++){ p = コンソール.行読み().空白除去().分ける(); 대기 = p[0].数に(); // 다음에 기다릴 시간 상한 = p[1].数に(); 최대시도 = p[2].数に(); 예산 = p[3].数に(); 결과들 = p[4]; 기다린합 = 0; 시도 = 0; 상태 = ""; // 크레이콘에는 do-while이 없다: 동안 (참)으로 들어가서 끝에서 멈출지 묻는다(첫 시도는 언제나 한다) 間 (真) { 결과 = 결과들[시도]; 시도++; もし (결과 == "S") { 상태 = "ok"; } でなければ もし (결과 == "X") { 상태 = "fatal"; } でなければ もし (시도 == 최대시도) { 상태 = "exhausted"; } でなければ もし (기다린합 + 대기 > 예산) { 상태 = "timeout"; } でなければ { 기다린합 += 대기; 대기 = 대기 * 2 > 상한 ? 상한 : 대기 * 2; } もし (상태 != "") { 抜ける; } } コンソール.書く(상태 + " " + 시도 + " " + 기다린합);}