mini notes

競技プログラミングの解法メモを残していきます。

ABC003 D - AtCoder社の冬

D - AtCoder社の冬

概要

R * CマスのうちのX * Yマス内にデスクをD個、サーバーラックをL個置く。
このとき、X * Yマス内の最も外側の4辺にはそれぞれ、デスクもしくはサーバーラックが置かれているものとする。
このような置き方(X * Yマスの選び方、デスク・サーバーラックの置き方)が何通りあるか答えよ。(mod 10^9 + 7)

制約

1 <= R, C <= 30
1 <= X <= R, 1 <= Y <= C
D, L >= 0
1 <= D+L <= X * Y

方針

X * Yマスをどこにするかは(R - X + 1) * (C - Y + 1)通り。
それぞれについて、デスクとサーバーラックの置き方を考える。

もしX * Y = D + L であれば、置き方はcomb(X * Y, D)通り。(部分点解法)

X * Y > D + L のときを考える。このとき必要な置き方は、外側4辺にそれぞれデスクもしくはサーバーラックを置くことである。
ここで包除原理を使う。すなわち以下の通り。

U:すべての場合
P:上辺にデスクとサーバーラックがない
Q:左辺にデスクとサーバーラックがない
R:下辺にデスクとサーバーラックがない
S:右辺にデスクとサーバーラックがない
とすると、求める事象は
U - (P | Q | R | S)
= U - (P + Q + R + S) + (P & Q + P & R + P & S + Q & R + Q & S + R & S)
- (P & Q & R + P & R & S + P & Q & S + Q & R & S) + P & Q & R & S
となる。

実装としては、4ビットの各桁について1桁目はP、2桁目はQ、のように対応付け、
16通りの事象の組み合わせをそれぞれ計算させる。

感想

下記を参考にしました。
tutuz.hateblo.jp

解答

Submission #4136198 - AtCoder Beginner Contest 003

#include <bits/stdc++.h>
#define rep(i,n) for(int i=(0);i<(n);i++)
using namespace std;
typedef long long ll;
 
const ll MOD = 1e9 + 7;
const ll max_n = 20000;
ll fact[max_n];
bool fact_init = false;
 
ll pow(ll a, ll b){
	if(b == 0) return 1;
	if(b % 2 == 1) return a * pow(a, b - 1) % MOD;
 
	ll d = pow(a, b / 2) % MOD;
	return d * d % MOD;
}
 
ll comb(ll n, ll k){
	if(!fact_init){
		fact[0] = 1;
		fact[1] = 1;
 
		for(ll i = 2; i <= max_n; i++){
			fact[i] = fact[i-1] * i;
			fact[i] %= MOD;
		}
 
		fact_init = true;
	}
 
	ll ret = fact[n];
	ret *= pow(fact[k],MOD-2);
	ret %= MOD;
	ret *= pow(fact[n-k],MOD-2);
	ret %= MOD;
	return ret;
 
	// X^(-1) = X^(p-2) (mod p) (Fermat's little theorem)
}
 
int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
 
	ll R, C;
	cin >> R >> C;
 
	ll X, Y;
	cin >> X >> Y;
 
	ll D, L;
	cin >> D >> L;
 
	ll ans = 0;
	rep(b, 1 << 4){
		ll tx = X;
		ll ty = Y;
 
		if((b >> 0) & 1) tx--;
		if((b >> 1) & 1) ty--;
		if((b >> 2) & 1) tx--;
		if((b >> 3) & 1) ty--;
 
		if(tx < 0 || ty < 0) continue;
		if(tx * ty < D + L) continue;
 
		int bsum = 0;
		rep(i, 4) if((b >> i) & 1) bsum++;
 
		if(bsum % 2 == 0){
			ans += comb(tx * ty, D + L) * comb(D + L, D);
			ans %= MOD;
		}else{
			ans += MOD;
			ans -= comb(tx * ty, D + L) * comb(D + L, D) % MOD;
			ans %= MOD;
		}
	}
 
	ans *= (R - X + 1) * (C - Y + 1);
	ans %= MOD;
 
	cout << ans << endl;
}