[AOJ] No. 0568 パスタ (Pasta)
問題
方針
\( 3 \) 日以上同じパスタを選んではいけないという制約がポイントです。\( i + 1 \) 日目の予定を決めるためには、\( i \) 日目と \( i – 1 \) 日目の予定が影響することを考えて動的計画法を行います。ここで、\( d(i, j, k) \) を \( i \) 日目にパスタ \( j \) を選び、\( i + 1 \) 日目にパスタ \( k \) を選ぶ時の場合の数とします。また、\( d \) は \( 0 \) で初期化します。
ここで、\( i \) 日目のパスタの予定を \( c_i \) とします。予定がないときは \( c_i = -1 \) とします。
初期値
\( c_1 = -1 \wedge c_2 = -1\) のとき
このとき、\( d(1, i, j) = 1 (1 \leq i \leq 3 \wedge 1 \leq j \leq 3)\) となります。これは、\( 1 \) 日目と \( 2 \) 日目に予定が入っていないことになります。
\( c_1 \neq -1 \wedge c_2 \neq -1\) のとき
このとき、\( d(1, c_1, c_2) = 1 \) となります。
\( c_1 = -1 \wedge c_2 \neq -1\) のとき
このとき、\( d(1, i, c_2) = 1 (1 \leq i \leq 3)\) となります。
\( c_1 \neq -1 \wedge c_2 = -1\) のとき
このとき、\( d(1, c_1, i) = 1 (1 \leq i \leq 3)\) となります。
更新式
\( c_i = -1 \wedge c_{i+1} = -1\) のとき
このとき、\( d(i, j, k) \gets d(i, j, k) + d(i – 1, l, j) \ (1 \leq i \leq 3 \wedge 1 \leq j \leq 3 \wedge 1 \leq l \leq 3 \wedge j \neq k \wedge k \neq l)\) となります。右辺の \( d(i, j, k)\) と \( d(i – 1, l, j) \) において、\( j \) が共通しているのは、\( i \) 日目の \( j \) を選択するという遷移は、\( i -1 \) 日目において、次の日に \( j \) を選択していなければならないからです。
\( c_i \neq -1 \wedge c_{i+1} \neq -1\) のとき
このとき、\( d(i, c_i, c_{i+1}) \gets d(i, c_i, c_{i+1}) + d(i – 1, j, c_i) \ (1 \leq j \leq 3 \wedge c_i \neq c_{i+1} \wedge j \neq c_i)\) となります。
\( c_i = -1 \wedge c_{i+1} \neq -1\) のとき
このとき、\( d(i, j, c_{i+1}) \gets d(i, j, c_{i+1}) + d(i – 1, k, j) \ (1 \leq i \leq 3 \wedge 1 \leq j \leq 3 \wedge j \neq c_{i+1} \wedge j \neq k)\) となります。
\( c_i \neq -1 \wedge c_{i+1} = -1\) のとき
このとき、\( d(i, c_i, j) \gets d(i, c_i, j) + d(i – 1, k, c_i) \ (1 \leq i \leq 3 \wedge 1 \leq j \leq 3 \wedge j \neq c_{i} \wedge j \neq k)\) となります。
コード
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll dp[101][3][3]{}; ll mod = 10000; void init(int a, int b) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (a == -1 && b == -1) { dp[1][i][j] = 1; } else if (a != -1 && b != -1) { dp[1][a][b] = 1; return; } else if (a == -1 && b != -1) { dp[1][i][b] = 1; } else if (a != -1 && b == -1) { dp[1][a][j] = 1; } } } } // d日目にa, d+1日目にb void solve(int d, int a, int b) { if (a == -1 && b == -1) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { if (i == j && i == k) continue; dp[d][i][j] += dp[d - 1][k][i]; dp[d][i][j] %= mod; } } } } else if (a != -1 && b != -1) { for (int i = 0; i < 3; i++) { if (i == a && a == b) continue; dp[d][a][b] += dp[d - 1][i][a]; dp[d][a][b] %= mod; } } else if (a == -1 && b != -1) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (b == i && i == j) continue; dp[d][i][b] += dp[d - 1][j][i]; dp[d][i][b] %= mod; } } } else if (a != -1 && b == -1) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (a == i && i == j) continue; dp[d][a][i] += dp[d - 1][j][a]; dp[d][a][i] %= mod; } } } } int main() { int N, K; cin >> N >> K; int A[N], B[N]; int C[N + 1]; fill(C, C + N + 1, -1); for (int i = 0; i < K; i++) { cin >> A[i] >> B[i]; B[i]--; C[A[i]] = B[i]; } // dp[i][j][k] i日目にj、i+1日目にkの個数 init(C[1], C[2]); for (int i = 2; i < N; i++) { solve(i, C[i], C[i + 1]); } ll ans = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { ans += dp[N - 1][i][j]; } } cout << ans % mod << "\n"; return 0; }
ディスカッション
コメント一覧
まだ、コメントがありません