yukicoder No.389 ロジックパズルの組み合わせ
解法
sum = H1+H2+...+HK とします。
すると, 塗られてないセルの数は M-sum になります。
K 個の要素を分割するので, K 個の要素の間に塗られていないセルがいくつか必要です。これで合計 K-1 個の塗られていないセルを消費するので, 実質的に利用できるセルの数は M-sum-K+1 個です。
これをどう分配するかですが, K 個の要素の間, および 左端と右端にセルの合計 K+1 種類の場所に入れる場所があります。これの分配の仕方は, 重複組み合わせのアレですね。
ll mod_pow(ll x, ll p, ll MOD) {
ll a = 1;
while (p) {
if (p%2) a = a*x%MOD;
x = x*x%MOD;
p/=2;
}
return a;
}
// mod_inverse
ll mod_inverse(ll a, ll m) {
return mod_pow(a, m-2, m);
}
const int MAXM = 1001000;
const int MOD = 1e9+7;
int H[MAXM];
ll fact[2*MAXM], rfact[2*MAXM];
int M, K;
ll nCr(int n, int r) {
ll ret = fact[n];
(ret *= rfact[r]) %= MOD;
(ret *= rfact[n-r]) %= MOD;
return ret;
}
int main() {
cin.tie(0);
ios::sync_with_stdio(false);
fact[0] = rfact[0] = 1;
for (int i = 1; i < 2*MAXM; i++) {
fact[i] = (fact[i-1]*i)%MOD;
rfact[i] = mod_inverse(fact[i], MOD);
}
cin >> M;
int sum = 0;
while (cin >> H[K]) {
sum += H[K++];
}
int rest = M-sum;
rest -= K-1;
if (rest < 0) {
cout << "NA" << endl;
return 0;
}
if (K == 1 && H[0] == 0) {
cout << 1 << endl;
return 0;
}
cout << nCr(rest+K, K) << endl;
return 0;
}