ARC067 E - Grouping
解法
dp[i + 1][j] := i 人以下のグループのみを用いて,あと j 人グループ分けされてない人がいるときの場合の数
という dp で解けます.
遷移は,use == 0 または C <= use <= D のとき
$$\displaystyle dp[i + 1][j - use \times i] = dp[i][j] \times \frac{_jC_i \times _{j-i}C_i \times \ldots \times _{j-(use-1)\times i}C_i}{(use)!}$$
になります.これは,j 人から i 人を選ぶ,という操作を use 回繰り返すが,グループ自体の区別はつけないので,グループの順列で割るということです.
ソースコード
#include <bits/stdc++.h> using namespace std; // mod は略 int main() { int N, A, B, C, D; cin >> N >> A >> B >> C >> D; vector<vector<mod>> dp(B + 2, vector<mod>(N + 1)); dp[A][N] = 1; for(int i = A; i <= B; ++i) { for(int j = 0; j <= N; ++j) { if(dp[i][j] == 0) { continue; } mod t = dp[i][j]; for(int use = 0; use * i <= j; ++use) { if(use == 0 || C <= use && use <= D) { dp[i + 1][j - use * i] += t * fact<MOD>(use, false); } t *= comb<MOD>(j - use * i, i); } } } cout << (int)dp[B + 1][0] << endl; }
感想
数え上げる問題が苦手すぎる.中学高校で訓練しておけばよかった….