Official

F - Sierpinski carpet Editorial by mechanicalpenciI


  • 解法 \(1\): 定義に従って順にカーペットを構成する

\(k=0,1,\ldots,N\) について、レベル \(i\) のカーペットに対応する文字列を順に構成していくことを考えます。
また、以下では、レベル \(k\) のカーペットに対応する \(S_i\)\(j\) 文字目を \(S^k_{i,j}\) \((1\leq i,j\leq 3^k)\) で表します。

レベル \(0\) のカーペットは \(S^0_{0,0}=\)# とすればよいです。
\(k\geq 0\) についてレベル \((k+1)\) のカーペットを構成するためには定義より \(0\) 以上 \(2\) 以下の整数の組 \((x,y)\) それぞれについて次のようにすれば良いです。

  • \((x,y)\neq (1,1)\) のとき、\(1\leq i,j\leq 3^k\) に対して、\(S^{k+1}_{x\cdot 3^k+i,y\cdot 3^k+j}=S^k_{i,j}\) とする。
  • \((x,y)=(1,1)\) のとき、\(1\leq i,j\leq 3^k\) に対して、\(S^{k+1}_{x\cdot 3^k+i,y\cdot 3^k+j}=\). とする。

このようにして、レベル \(k\) のカーペットを構成することができます。計算量は \(O(3^{2N})\) であり、十分高速です。

よって、この問題を解くことができました。

  • 解法 \(2\): カーペットのマスの色が白となる条件を整理する。

問題の条件を整理すると、レベル \(N\) のカーペットについて、上から \(i\) 行目かつ左から \(j\) 列目のマスが白色となる必要十分条件は、
\(1\leq k\leq N\) をみたすいずれかの整数 \(k\) について、 \((i-1)\)\(3\) 進法で表した時の\(k\) 桁目と \((j-1)\)\(3\) 進法で表した時の\(k\) 桁目がともに \(1\) になることであるとわかります。
そのため、各 \(1\leq i,j\leq 3^N\) についてその判定を行えば良いです。 計算量は \(O(N\cdot 3^{2N})\) であり、十分高速です。

c++ による実装例:

#include <bits/stdc++.h>

using namespace std;

int main() {
	int n,l=1;
    char a[729][730];
    for(int i=0;i<729;i++)for(int j=0;j<730;j++)a[i][j]=0;

    cin>>n;
    a[0][0]='#';
    for(int k=0;k<n;k++){
        for(int x=0;x<3;x++){
            for(int y=0;y<3;y++){
                if((x==0)&&(y==0))continue;
                if((x==1)&&(y==1)){
                    for(int i=0;i<l;i++)for(int j=0;j<l;j++)a[x*l+i][y*l+j]='.';
                }
                else{
                    for(int i=0;i<l;i++){
                        for(int j=0;j<l;j++){
                            a[x*l+i][y*l+j]=a[i][j];
                        }
                    }
                }
            }
        }
        l*=3;
    }

    for(int i=0;i<l;i++)cout<<a[i]<<endl;

    return 0;
}

posted:
last update: