{ }codelper
模拟P0350

坐成一排的萤火虫

n 只萤火虫坐成一排。
这一排的状态用长度为 n 的字符串表示,O(大写英文字母 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);