Official
H - Cを探せ! / Find C! Editorial
by
H - Cを探せ! / Find C! Editorial
by
physics0523
上から \(i\) 行目、左から \(j\) 列目を \((i,j)\) と表現します。
また、 \(l \times m\) の領域は縦 \(l\) マス、横 \(m\) マスの領域を指します。
\(x,y,l\) を決め打ったとき、左上が \((x,y)\) である \((l+2) \times (l+2)\) の領域がレベル \(l\) の C であるかどうかを効率よく判定することを考えましょう。
左上が \((x,y)\) である \((l+2) \times (l+2)\) の領域がレベル \(l\) の C であることは、以下と同値です。
- 左上が \((x+1,y+1)\) である \(l \times (l+1)\) の領域が全て
.である (#が丁度 \(0\) 個含まれる )。 - 左上が \((x,y)\) である \((l+2) \times (l+2)\) の領域に
#が丁度 \(4+3l\) 個含まれる。
この判定は、二次元累積和を用いて \(O(1)\) で解くことができます。
二次元累積和についての参考資料をいくつか挙げます。
累積和を何も考えずに書けるようにする!
2次元累積和をまなぶ
二次元での区間和を求めるアルゴリズム(区間の更新なし)
2次元累積和 | アルゴリズムビジュアル大事典
実装例 (C++):
#include<bits/stdc++.h>
using namespace std;
//2D-Ruisekiwa Simple
int bsum[305][305]={0};
int cbz(int fx,int fy,int tx,int ty){
if(fx>tx || fy>ty){return 0;}
if(fx==0 && fy == 0){return bsum[tx][ty];}
else if(fx==0){
return bsum[tx][ty]-bsum[tx][fy-1];
}
else if(fy==0){
return bsum[tx][ty]-bsum[fx-1][ty];
}
else{
return bsum[tx][ty]-bsum[tx][fy-1]-bsum[fx-1][ty]+bsum[fx-1][fy-1];
}
}
int main(){
int n;
cin >> n;
for(int i=0;i<n;i++){
string s;
cin >> s;
for(int j=0;j<n;j++){
if(s[j]=='.'){bsum[i][j]=0;}
else if(s[j]=='#'){bsum[i][j]=1;}
}
}
for(int i=1;i<n;i++){
for(int j=0;j<n;j++){
bsum[i][j]+=bsum[i-1][j];
}
}
for(int i=0;i<n;i++){
for(int j=1;j<n;j++){
bsum[i][j]+=bsum[i][j-1];
}
}
int res=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
for(int l=3;i+l<=n && j+l<=n;l++){
int w=cbz(i,j,i+l-1,j+l-1);
int c=cbz(i+1,j+1,i+l-2,j+l-1);
if(c!=0){continue;}
if(w==3*(l-1)+1){res=max(res,l-2);}
}
}
}
cout << res << "\n";
return 0;
}
posted:
last update:
