結果

問題 No.584 赤、緑、青の色塗り
ユーザー qwewe
提出日時 2025-05-14 13:01:26
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
実行時間 -
コード長 7,504 bytes
コンパイル時間 793 ms
コンパイル使用メモリ 86,152 KB
実行使用メモリ 7,844 KB
最終ジャッジ日時 2025-05-14 13:03:42
合計ジャッジ時間 5,580 ms
ジャッジサーバーID
(参考情報)
judge3 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 6
other AC * 7 TLE * 1 -- * 6
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <map>

// Define a structure for the state key to be used in the map.
// This improves readability and organization compared to using tuples or vectors directly.
struct StateKey {
    int r, g, b; // Counts of Red, Green, Blue colors used so far
    int p1;      // Color of the last cell (cell i)
    int p2;      // Color of the second to last cell (cell i-1)

    // Colors are represented as integers: 0:Red, 1:Green, 2:Blue, 3:Empty

    // Define the less than operator '<'. This is required for std::map keys 
    // to maintain order and allow efficient lookups.
    bool operator<(const StateKey& other) const {
        // Compare components in a fixed order. If any component differs,
        // the comparison result is determined. If all components match up to the last one,
        // compare the last component.
        if (r != other.r) return r < other.r;
        if (g != other.g) return g < other.g;
        if (b != other.b) return b < other.b;
        if (p1 != other.p1) return p1 < other.p1;
        return p2 < other.p2;
    }
};

// Use std::map to store the DP states. The key is the StateKey struct, 
// and the value is the count of ways to reach that state (long long for potentially large counts).
// We use two maps, `dp[0]` and `dp[1]`, to represent the DP states for the current step (i)
// and the next step (i+1). This technique is often called "ping-pong" or double buffering.
std::map<StateKey, long long> dp[2]; 

// Define the modulus for calculations, as required by the problem statement.
long long MOD = 1000000007;


int main() {
    // Use faster I/O operations by disabling synchronization with C stdio
    // and unlinking cin from cout.
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int N, R, G, B; // Grid size N, target counts R, G, B
    std::cin >> N >> R >> G >> B;

    // Basic feasibility check: The total number of required colored cells
    // cannot exceed the total number of cells in the grid.
    // If R+G+B > N, it's impossible to satisfy the requirements.
    if (R + G + B > N) {
        std::cout << 0 << std::endl;
        return 0;
    }

    // Initialize the DP. The state before processing the first cell (at index 0) is:
    // 0 Red, 0 Green, 0 Blue cells used.
    // We assume the two fictitious cells before the grid start (-1 and 0) were Empty (color code 3).
    // There is 1 way to reach this initial state.
    dp[0][{0, 0, 0, 3, 3}] = 1; 

    int current_dp_idx = 0; // Index (0 or 1) to access the current DP table
    // The main DP loop iterates N times, corresponding to processing cells 1 through N.
    for (int i = 0; i < N; ++i) { 
        int next_dp_idx = 1 - current_dp_idx; // Index for the DP table for the next step
        dp[next_dp_idx].clear(); // Clear the map for the next state calculation to ensure it's fresh.

        // Optimization: If the current DP table is empty, it means no valid states were reached
        // in the previous step. Thus, no further states can be reached. We can break early.
        if (dp[current_dp_idx].empty()) { 
             break;
        }
        
        // Iterate through all reachable states ending at cell i (stored in dp[current_dp_idx])
        for (auto const& [current_state, count] : dp[current_dp_idx]) {
            // `current_state` contains {r, g, b, p1, p2} information after processing cell i.
            // `count` is the number of ways to reach this state.

            // Unpack state variables from the key for easier access
            int r = current_state.r;
            int g = current_state.g;
            int b = current_state.b;
            int p1 = current_state.p1; // Color of cell i
            int p2 = current_state.p2; // Color of cell i-1

            // Try placing each possible color (R, G, B, E) at the next cell, i+1
            for (int new_p1 = 0; new_p1 < 4; ++new_p1) { // Loop through colors 0:R, 1:G, 2:B, 3:E
                int next_r = r, next_g = g, next_b = b; // Initialize counts for the next state
                bool is_new_cell_colored = (new_p1 != 3); // Check if the new cell is colored or empty

                // Update color counts based on the color being placed at cell i+1
                // Also check if the target count for that color has already been reached.
                if (new_p1 == 0) { // Placing Red
                    if (r >= R) continue; // Cannot place Red if R count is already met/exceeded
                    next_r++;
                } else if (new_p1 == 1) { // Placing Green
                    if (g >= G) continue; // Cannot place Green if G count is already met/exceeded
                    next_g++;
                } else if (new_p1 == 2) { // Placing Blue
                    if (b >= B) continue; // Cannot place Blue if B count is already met/exceeded
                    next_b++;
                }
                // No count change needed if placing an Empty cell (new_p1 == 3)

                // Check rule constraints before adding the state transition:

                // Constraint 1: No adjacent identical colors.
                // Compare the color of cell i+1 (new_p1) with the color of cell i (p1).
                // This check only applies if the new cell is colored.
                if (is_new_cell_colored && new_p1 == p1) {
                    continue; // Invalid transition: results in RR, GG, or BB pattern
                }

                // Constraint 2: No three consecutive colored cells.
                // Check if placing `new_p1` at cell i+1 would create a sequence of three colored cells.
                // This happens if cell i+1, cell i, and cell i-1 are all colored.
                bool is_p1_colored = (p1 != 3); // Was cell i colored?
                bool is_p2_colored = (p2 != 3); // Was cell i-1 colored?

                if (is_new_cell_colored && is_p1_colored && is_p2_colored) {
                     continue; // Invalid transition: results in a CCC pattern
                }
                
                // If all constraints are satisfied, this transition is valid.
                // Construct the StateKey for the resulting state after placing `new_p1` at cell i+1.
                // The new state has updated counts {next_r, next_g, next_b}.
                // The last color is `new_p1`. The second to last color is the previous last color `p1`.
                StateKey next_state = {next_r, next_g, next_b, new_p1, p1};
                
                // Add the number of ways (`count`) from the current path to the total count
                // for the `next_state` in the `next_dp_idx` table. Perform addition modulo MOD.
                dp[next_dp_idx][next_state] = (dp[next_dp_idx][next_state] + count) % MOD;
            }
        }
        // After processing all states in the current DP table, switch context for the next iteration.
        current_dp_idx = next_dp_idx; 
    }

    // After the loop finishes (N iterations), dp[current_dp_idx] contains states for the full grid of size N.
    long long total_ways = 0;
    // Sum up the counts for all final states that exactly match the target R, G, B counts.
    for (auto const& [final_state, count] : dp[current_dp_idx]) {
        if (final_state.r == R && final_state.g == G && final_state.b == B) {
            total_ways = (total_ways + count) % MOD;
        }
    }

    // Output the final answer.
    std::cout << total_ways << std::endl; 

    return 0;
}
0