けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 357 C - Sierpinski carpet (4Q, 灰色, 250 点)

いろんな方法で実装できそう!

問題概要

非負整数  K に対して、レベル  K のカーペットを再帰的に定義する。

  • レベル  0 のカーペットは、"#" からなる 1 × 1 のグリッドである
  •  K \gt 0 に対して、レベル  K のカーペットは  3^{K} \times 3^{K} のグリッドであり、 このグリッドを  3^{K-1} \times 3^{K-1} のブロック 9 個に分割したとき、
    • 中央のブロックはすべて白いマスからなる
    • 他の 8 個のブロックは、レベル  K−1 のカーペットである

レベル  N のカーペットを出力せよ。

制約

  •  1 \le N \le 6

考えたこと

「与えられたカーペットのレベルを 1 段階上げたカーペットを出力する」ような関数を実装しよう!

それが実装できれば、その関数を  N 回呼び出せばよい。

コード

#include <bits/stdc++.h>
using namespace std;

int main() {
    int N;
    cin >> N;
    
    // 入力されたカーペットに対して、レベルが 1 段階上のカーペットを出力する関数
    auto conv = [&](const vector<string> &fi) -> vector<string> {
        int N = fi.size();
        vector<string> res(N * 3);
        for (int i = 0; i < N * 3; ++i) {
            for (int j = 0; j < N * 3; ++j) {
                if (i >= N && i < N * 2 && j >= N && j < N * 2) {
                    // 真ん中はすべて "."
                    res[i] += ".";
                } else {
                    // 1 つ前のカーペットをコピー
                    res[i] += fi[i % N][j % N];
                }
            }
        }
        return res;
    };
    
    // N 回レベルアップさせる
    vector<string> res(1, "#");
    for (int i = 0; i < N; ++i) {
        res = conv(res);
    }
    for (auto s : res) cout << s << endl;
}