問題
http://yukicoder.me/problems/no/412
自然数B, C, Dがある。
N個の数列Eiもある。
Eiの部分集合は2^N通りあるが、「その中でB <= Eb, C <= Ec, D <= Edを満たす別々のb,c,dがある」組合せの個数は?
1 <= B,C,D <= 100
1 <= N <= 30
1 <= Ei <= 100
帰納的考察(解説見た)
1. 正直ぜんぜん分からんかった
――壁――
2. 大切な方針がある
3. BCDとEiをソートしておき、部分集合を数えるときにb < c < dとなるものだけ数える
4. 重複して数えないような工夫が必要。そのための方針
5. dpを使って数え上げる(典型らしいですよ)
dp[i][j] = i番目までのEiでj個目まで選択する組合せ Eiをj個目として選択できるなら dp[i + 1][j] += dp[i][j] dp[i + 1][j + 1] += dp[i][j] Eiをj個目として選択できないなら dp[i + 1][j] += dp[i][j] * 2
6. これを実装
実装
http://yukicoder.me/submissions/110728
int ABC[3]; int N; int E[30]; int dp[31][4]; //----------------------------------------------------------------- int main() { rep(i, 0, 3) cin >> ABC[i]; cin >> N; rep(i, 0, N) cin >> E[i]; sort(ABC, ABC + 3); sort(E, E + N); dp[0][0] = 1; rep(i, 0, N) { int cnt = 0; rep(j, 0, 3) if (ABC[j] <= E[i]) cnt++; rep(j, 0, 4) { if (cnt == j) { dp[i + 1][j] += dp[i][j] * 2; } else if (cnt > j) { dp[i + 1][j] += dp[i][j]; dp[i + 1][j + 1] += dp[i][j]; } } } cout << dp[N][3] << endl; }