TopCoder SRM 553 Div1 Medium TwoConvexShapes
問題
HxWのグリッドを'B'または'W'の色で塗る。
既に色が塗られているところはB, Wの文字が書かれていて、
そうでないマスには'?'が書かれている。
このグリッドの?のマスを全てBまたはWの色で塗り、以下の条件を満たすようにしたい。
全ての同色のマスは、連結で、凸である。
すなわち、同じ列または行に二つの同色のマスがあった場合、
その間のマスは全て同じ色で塗られている。
条件を満たす塗り方は何通りあるか、求めよ。
制約条件
H, W≦50
方針
条件を満たす塗り方というのは結局、一色が階段状になっている塗り方である。
階段状になっている塗り方の場合の数は、動的計画法により求まる。
階段が四隅のどこになるかが4通りありうるので、回転して全部数える。
このとき、全部のマスが白、または黒である状態は4回数えているので3回分引く。
また、白と黒のマスのかたまりが、ひとつの直線で分割される場合も2度ずつ数えているので、1回分引く。
これで答えが出る。
ソースコード
const int mod = (int)1e9 + 7; vector<string> rot(vector<string> &g){ int h = g.size(), w = g[0].size(); vector<string> res(w, string(h, ' ')); rep(i, h) rep(j, w) res[j][h - i - 1] = g[i][j]; return res; } ll calc(const vector<string> &g){ int h = g.size(), w = g[0].size(); static ll dp[51][51]; memset(dp, 0, sizeof(dp)); dp[0][0] = 1; rep(i, h){ int mxb = -1, mnw = w; rep(j, w){ if(g[i][j] == 'B') mxb = j; if(g[i][j] == 'W') mnw = min(mnw, j); } if(mxb > mnw) break; rep(j, w + 1) if(dp[i][j]){ for(int k = max(j, mxb + 1); k <= min(mnw, w); k++){ (dp[i + 1][k] += dp[i][j]) %= mod; } } } ll res = 0; rep(i, w + 1) res += dp[h][i]; return res; } ll calc2(const vector<string> &g){ int h = g.size(), w = g[0].size(); ll res = 0; for(int i = 1; i < h; i++){ rep(j, w) if(g[i - 1][j] == 'W') goto END; for(int j = i; j < h; j++) rep(k, w) if(g[j][k] == 'B') goto FAIL; res++; FAIL:; } END: return res; } class TwoConvexShapes { public: int countWays(vector <string> grid) { ll ans = 0; rep(i, 4){ ans += calc(grid); ans -= calc2(grid); grid = rot(grid); } int white = 1, black = 1; rep(i, grid.size()) rep(j, grid[0].size()){ if(grid[i][j] == 'B') white = 0; if(grid[i][j] == 'W') black = 0; } ans -= white * 3 + black * 3; return (ans + mod) % mod; } };