Official

D - Hanjo Editorial by tatyam


\(HW \le 16\) と制約が小さいので、敷き詰め方を全探索することを考えましょう。
左上のマスから順に、半畳、右にはみ出す畳、下にはみ出す畳を置くことを試す DFS を行うと、敷き詰め方を全探索することができます。

計算量を見積もりましょう。
長方形の畳の左上となる場所を決め、そこから右か下かどちらに伸ばすかを選択することを考えると、答えは \(2^A\binom{HW}A\) で上から押さえられます。
\(HW2^A\binom{HW}A\) は最大でも \(5 \times 10^7\) 程度なので、十分高速であると分かります。
実際には、答えの最大値は \(3388\) であるので、見積もりよりずっと高速に動作します。

BONUS : \(HW ≤ 200\) で解いてみましょう!

回答例 (C++)

#include <iostream>
using namespace std;

int H, W, A, B, ans = 0;
void dfs(int i, int bit, int A, int B){
    if(i == H * W) return (void)ans++;
    if(bit & 1 << i) return dfs(i + 1, bit, A, B);
    if(B) dfs(i + 1, bit | 1 << i, A, B - 1);
    if(A){
        if(i % W != W - 1 && ~bit & 1 << (i + 1)) dfs(i + 1, bit | 1 << i | 1 << (i + 1), A - 1, B);
        if(i + W < H * W) dfs(i + 1, bit | 1 << i | 1 << (i + W), A - 1, B);
    }
}
int main(){
    cin >> H >> W >> A >> B;
    dfs(0, 0, A, B);
    cout << ans << endl;
}

回答例 (Python)

H, W, A, B = map(int, input().split())
ans = 0

def dfs(i, bit, A, B):
    if i == H * W:
        global ans
        ans += 1
        return
    if bit >> i & 1:
        dfs(i + 1, bit, A, B)
        return
    if B:
        dfs(i + 1, bit | 1 << i, A, B - 1)
    if A:
        if i % W != W - 1 and not bit & 1 << (i + 1):
            dfs(i + 1, bit | 1 << i | 1 << (i + 1), A - 1, B)
        if i + W < H * W:
            dfs(i + 1, bit | 1 << i | 1 << (i + W), A - 1, B)

dfs(0, 0, A, B)
print(ans)

posted:
last update: