{ }codelper
シミュレーションP0350

一列に並んだホタル

ホタルが n 匹、一列に並んでいる。
列の状態は長さ n の文字列で表し、O(英大文字のオー)は光っているホタル、.(ピリオド)は光っていないホタルである。
1 秒たつごとに、すべてのホタルが今の状態を見て同時に変わる。
今光っているホタルは消える。
今消えているホタルは、すぐ隣のホタルのうち今光っているものがちょうど一匹のときだけ光る。
光っている隣がいないとき、または両隣がどちらも光っているときは、消えたままである。
すぐ隣とは左の一匹と右の一匹のことで、列の両端のホタルには隣が一匹しかいない(列の最初と最後は隣どうしではない)。
t 秒後の列の状態と、1 秒後から t 秒後までの各時点で光っていたホタルの数をすべて足した値を求めよ。
例の列は 1 秒後に O....O.、2 秒後に .O..O.O、3 秒後に O.OO...
になる。
光っている数は順に 2、3、3 なので、合計は 8 である。

入力
一行目に n と t(1 ≤ n ≤ 200、1 ≤ t ≤ 200)が空白一つで区切って与えられ、二行目に最初の状態を表す長さ n の文字列が与えられる。
文字列は O と .
だけからなる
出力
一行目に t 秒後の列の状態(長さ n の文字列)、二行目に光っていた数の合計
例 1 · stdin
7 3
.OO.O..
stdout
O.OO...
8
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

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

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

全員が「今」を見て同時に変わるので、次の状態は今の状態とは別の配列に書かなければなりません。
新しい配列の作り方は言語ごとに違います。
Python は [0] * n、JS・TS は new Array(n).fill(0)、Java・C# は new int[n]、C++ は vector<int> next(n, 0)、Craykon は 新リスト(n, 0) です。
C は配列を二つ用意して memcpy で移します(C の配列は = では移せません)。
罠その一:nxt = cur はコピーではありません。
Python のリスト、JS の配列、Java・C# の配列、Craykon のリストでは、= は同じ配列に名前をもう一つ付けるだけなので、次の状態を書いたとたんに今の状態が変わり、右のホタルはすでに変わった左隣を見ることになります。
例の答えが .O..... と 4 になります。
C++ の vector だけは cur = next で中身を丸ごとコピーします。
罠その二:列の端では隣が一匹しかいません。
i > 0 かどうかを確かめずに cur[i - 1] を読むと、Python は cur[-1] を最後のマスとして読むので、列の最初と最後が隣どうしになります。
例の答えが ..OO... と 7 になります。
同じコードは Java では ArrayIndexOutOfBoundsException、C# では IndexOutOfRangeException で止まり、Craykon もその位置はないと知らせて止まります。
JS は undefined を返すので足すと NaN になり、C と C++ では何が起こるか決まっていません。
罠その三:「ちょうど一匹」を「一匹以上」と読むと、両隣が光っているホタルまで光ります。
例の答えが O..O.O. と 10 になります。
この解法は光っている隣の数を数えて near == 1 かどうかを確かめます。

Pythonmain.py · 16 行
n, t = map(int, input().split())cur = [1 if c == "O" else 0 for c in input()]total = 0for _ in range(t):    nxt = [0] * n  # 다음 순간은 새 리스트에 적는다: 모두가 '지금'을 보고 한꺼번에 바뀐다    for i in range(n):        near = 0  # 켜진 이웃의 수        if i > 0:            near += cur[i - 1]        if i < n - 1:            near += cur[i + 1]        nxt[i] = 1 if cur[i] == 0 and near == 1 else 0    cur = nxt    total += sum(cur)print("".join("O" if x else "." for x in cur))print(total)
JavaScriptmain.js · 18 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [n, t] = lines[0].split(" ").map(Number);let cur = [];for (let i = 0; i < n; i++) cur.push(lines[1][i] === "O" ? 1 : 0);let total = 0;for (let s = 0; s < t; s++) {  const next = new Array(n).fill(0); // 다음 순간은 새 배열에 적는다  for (let i = 0; i < n; i++) {    let near = 0; // 켜진 이웃의 수    if (i > 0) near += cur[i - 1];    if (i < n - 1) near += cur[i + 1];    next[i] = cur[i] === 0 && near === 1 ? 1 : 0;    total += next[i];  }  cur = next;}console.log(cur.map((x) => (x ? "O" : ".")).join(""));console.log(total);
TypeScriptmain.ts · 20 行
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split("\n");const [n, t] = lines[0].split(" ").map(Number);let cur: number[] = [];for (let i = 0; i < n; i++) cur.push(lines[1][i] === "O" ? 1 : 0);let total = 0;for (let s = 0; s < t; s++) {  const next: number[] = new Array<number>(n).fill(0); // 다음 순간은 새 배열에 적는다  for (let i = 0; i < n; i++) {    let near = 0; // 켜진 이웃의 수    if (i > 0) near += cur[i - 1];    if (i < n - 1) near += cur[i + 1];    next[i] = cur[i] === 0 && near === 1 ? 1 : 0;    total += next[i];  }  cur = next;}console.log(cur.map((x) => (x ? "O" : ".")).join(""));console.log(total);
JavaMain.java · 30 行
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));        String[] first = br.readLine().split(" ");        int n = Integer.parseInt(first[0]), t = Integer.parseInt(first[1]);        String row = br.readLine();        int[] cur = new int[n];        for (int i = 0; i < n; i++) cur[i] = row.charAt(i) == 'O' ? 1 : 0;        int total = 0;        for (int s = 0; s < t; s++) {            int[] next = new int[n]; // 다음 순간은 새 배열에 적는다            for (int i = 0; i < n; i++) {                int near = 0; // 켜진 이웃의 수                if (i > 0) near += cur[i - 1];                if (i < n - 1) near += cur[i + 1];                next[i] = cur[i] == 0 && near == 1 ? 1 : 0;                total += next[i];            }            cur = next;        }        StringBuilder sb = new StringBuilder();        for (int x : cur) sb.append(x == 1 ? 'O' : '.');        System.out.println(sb);        System.out.println(total);    }}
C#Main.cs · 32 行
using System;using System.Text; class Program{    static void Main()    {        string[] first = Console.ReadLine()!.Split(' ');        int n = int.Parse(first[0]), t = int.Parse(first[1]);        string row = Console.ReadLine()!;        int[] cur = new int[n];        for (int i = 0; i < n; i++) cur[i] = row[i] == 'O' ? 1 : 0;        int total = 0;        for (int s = 0; s < t; s++)        {            int[] next = new int[n]; // 다음 순간은 새 배열에 적는다            for (int i = 0; i < n; i++)            {                int near = 0; // 켜진 이웃의 수                if (i > 0) near += cur[i - 1];                if (i < n - 1) near += cur[i + 1];                next[i] = cur[i] == 0 && near == 1 ? 1 : 0;                total += next[i];            }            cur = next;        }        var sb = new StringBuilder();        foreach (int x in cur) sb.Append(x == 1 ? 'O' : '.');        Console.WriteLine(sb);        Console.WriteLine(total);    }}
C++main.cpp · 27 行
#include <iostream>#include <string>#include <vector>using namespace std; int main() {    int n, t;    string row;    cin >> n >> t >> row;    vector<int> cur(n);    for (int i = 0; i < n; i++) cur[i] = row[i] == 'O';    int total = 0;    for (int s = 0; s < t; s++) {        vector<int> next(n, 0); // 다음 순간은 새 vector에 적는다        for (int i = 0; i < n; i++) {            int near = 0; // 켜진 이웃의 수            if (i > 0) near += cur[i - 1];            if (i < n - 1) near += cur[i + 1];            next[i] = cur[i] == 0 && near == 1;            total += next[i];        }        cur = next; // vector의 = 는 내용을 통째로 복사한다    }    for (int x : cur) cout << (x ? 'O' : '.');    cout << '\n' << total << '\n';    return 0;}
Cmain.c · 24 行
#include <stdio.h>#include <string.h> int main(void) {    int n, t;    char row[201];    int cur[200], next[200];    if (scanf("%d %d %200s", &n, &t, row) != 3) return 0;    for (int i = 0; i < n; i++) cur[i] = row[i] == 'O';    int total = 0;    for (int s = 0; s < t; s++) {        for (int i = 0; i < n; i++) {            int near = 0; /* 켜진 이웃의 수 */            if (i > 0) near += cur[i - 1];            if (i < n - 1) near += cur[i + 1];            next[i] = cur[i] == 0 && near == 1; /* 다음 순간은 다른 배열에 적는다 */            total += next[i];        }        memcpy(cur, next, sizeof(int) * n); /* C 배열은 = 로 옮길 수 없다 */    }    for (int i = 0; i < n; i++) putchar(cur[i] ? 'O' : '.');    printf("\n%d\n", total);    return 0;}
Craykonmain.cray · 53 行
첫줄 = コンソール.数読み();n = 첫줄[0];t = 첫줄[1];row = コンソール.行読み();cur = [];繰り返す (i = 0; i < n; i++){    もし (row[i] == "O")    {        cur.追加(1);    }    でなければ    {        cur.追加(0);    }}total = 0;繰り返す (s = 0; s < t; s++){    next = 新リスト(n, 0); // 다음 순간은 새 목록에 적는다    繰り返す (i = 0; i < n; i++)    {        near = 0; // 켜진 이웃의 수        もし (i > 0)        {            near += cur[i - 1];        }        もし (i < n - 1)        {            near += cur[i + 1];        }        もし (cur[i] == 0 && near == 1)        {            next[i] = 1;            total += 1;        }    }    cur = next;}result = "";それぞれ (x の中 cur){    もし (x == 1)    {        result += "O";    }    でなければ    {        result += ".";    }}コンソール.書く(result);コンソール.書く(total);