I - Yet Another Grid Task Editorial
by
physics0523
ひとまず、入力を整理することを考えます。
入力のうち、あるマス \((i,j)\) が 黒 である場合、完成した美しいグリッドでは マス \((i+1,j)\) 、マス \((i+1,j+1)\) も 黒 である必要があります。
なので、この条件に従って入力を改変してしまいましょう。下の例では左の入力を右のものに改変します。
....#. ....#.
...... ....##
.#.... -> .#..##
...... .##.##
...... .#####
改変した後にできたグリッドは必ず美しくなることがわかります。
いくつかの入力に対してこの改変を試せば、解法が見えやすくなるかもしれません。
結局、美しいグリッドとはどのようなものでしょうか?
以下が美しいグリッドである必要十分条件です。
- 全ての \(c\) について、 \(i-j=c\) を満たすマス \((i,j)\) を \(i\) の昇順に並べることを考える。
- このとき、先頭のいくつか ( \(0\) 個でもよい ) のマスが白であり、残りのマスが黒である。
- 黒マスの中で最も \(j\) が小さいもの (最も左にあるもの) に着目し、そのマスの \(j\) の値を \(L_c\) とすると、 \(L = (L_{-M+1},L_{-M+2},\dots,L_{N-1})\) は広義単調減少となる。
言葉では少し分かりづらいですが、直感的には左上から右下の方向に斜めに見ることにして、この斜線を上から下に降ろしていく時に、白と黒との境界線が右から左に移動していくような感じです。
ここに元々黒いマスの条件を追加し、動的計画法で解くことを考えましょう。
\(c = -M+1, -M+2 , \dots, N-1\) の順に以下の DP テーブルを作ります。
\(dp[c][j] = \) ( \(i-j=c\) を満たすマスに着目した際、マス\((j+c,j)\) とそれより右のマスが 黒 である時のグリッドの種類数 ) を考えます。
なお、便宜上グリッドは右方向と下方向には無限に広いものとし、 \(i \ge N+1\) または \(j \ge M+1\) を満たすマス \((i,j)\) は全て 黒 であるとして取り扱います。このようにしても答えは変化しません。 また、便宜上 \(dp[-M][M+1]=1, dp[-M][j]=0\) ( \(1 \le j \le M\) ) と初期化します。
- まず、 \(dp[c][j] = \sum^{M+1}_{k=j} dp[c-1][k]\) とする。これは、累積和により \(j\) 全体で時間計算量 \(O(M)\) で実行可能である。
- 次に、マス \((j+c,j)\) が存在しない ( \(j+c \le 0\) である場合) 場合、 \(dp[c][j]=0\) とする。
- 最後に、改変した入力においてマス \((i,j)\) が 黒 なら \(dp[c][j+1]=0\) とする。
答えは \(\sum^{M+1}_{j=1} dp[N-1][j]\) です。
この解法により、この問題を時間計算量 \(O(NM)\) で解くことができます。
実装例 (C++):
#include<bits/stdc++.h>
#define mod 998244353
using namespace std;
int main(){
long long n,m;
cin >> n >> m;
vector<string> s(n);
for(auto &nx : s){cin >> nx;}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(s[i][j]=='#'){
if(i!=(n-1)){s[i+1][j]='#';}
if(i!=(n-1) && j!=(m-1)){s[i+1][j+1]='#';}
}
}
}
vector<long long> dp(m+1,0);
dp[m]=1;
for(int c=-m+1;c<=n-1;c++){
for(int j=m-1;j>=0;j--){
dp[j]+=dp[j+1];
dp[j]%=mod;
}
for(int j=0;j<m;j++){
int i=j+c;
if(i<0){dp[j]=0;}
else if(i>=n || s[i][j]=='#'){dp[j+1]=0;}
}
}
long long res=0;
for(auto &nx : dp){res+=nx;res%=mod;}
cout << res << "\n";
return 0;
}
posted:
last update: