0w1

ABC 3 D - AtCoder社の冬 ( DP )

D: AtCoder社の冬 - AtCoder Beginner Contest 003 | AtCoder
torus711さんの解き方( DPは想定解ではない模様 )が勉強になりました。ありがとうございます。
torus711.hatenablog.com
X * Y の小長方形をDPで方法数を求めます、その小長方形が条件を満たす様、一番上/左/下/右が埋まれているかどうかをバイナリでエンコードします。直接dとlの使われた数をそれぞれ状態に組み込んでしまうと900^3になりやばいです。なのでまとめて数えて、最後にコンビネーションと掛けます。

#include <bits/stdc++.h>
using namespace std;
const int MAXR = 30;
const int MAXC = 30;
const int MOD = 1e9 + 7;
typedef long long ll;
#define rep( i, a ) for(int i = 0; i < (int)( a ); ++i)

int r, c;
int x, y;
int d, l;

int C[ MAXR * MAXC + 1 ][ MAXR * MAXC + 1 ];
int nCk(int n, int k){
    C[ 0 ][ 0 ] = 1;
    rep( i, n ) rep( j, i + 1 )
        ( C[ i + 1 ][ j ] += C[ i ][ j ] ) %= MOD,
        ( C[ i + 1 ][ j + 1 ] += C[ i ][ j ] ) %= MOD;
    return C[ n ][ k ];
}

// pos / number of d + l / ( u, l, d, r )
int dp[ MAXR * MAXC + 1 ][ MAXR * MAXC + 1 ][ 1 << 4 ];

void solve(){
    memset( dp, 0, sizeof(dp) );
    dp[ 0 ][ 0 ][ 0 ] = 1;
    rep( i, x * y ) rep( j, x * y + 1 ) rep( k, ( 1 << 4 ) ){
        int nk = k;
        nk |= ( i / y == 0 ) << 0;
        nk |= ( i % y == 0 ) << 1;
        nk |= ( i / y == x - 1 ) << 2;
        nk |= ( i % y == y - 1 ) << 3;
        ( dp[ i + 1 ][ j ][ k ] += dp[ i ][ j ][ k ] ) %= MOD;
        ( dp[ i + 1 ][ j + 1 ][ nk ] += dp[ i ][ j ][ k ] ) %= MOD;
    }
    ll ans = (ll)dp[ x * y ][ d + l ][ ( 1 << 4 ) - 1 ] * nCk( d + l, d ) % MOD;
    ( ans *= r - x + 1 ) %= MOD; // 平行移動
    ( ans *= c - y + 1 ) %= MOD;
    printf("%lld\n", ans);
}

int main(){
    scanf("%d%d", &r, &c);
    scanf("%d%d", &x, &y);
    scanf("%d%d", &d, &l);
    solve();
    return 0;
}