結果

問題 No.281 門松と魔法(1)
ユーザー qwewe
提出日時 2025-05-14 13:07:13
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
実行時間 -
コード長 7,335 bytes
コンパイル時間 984 ms
コンパイル使用メモリ 99,208 KB
実行使用メモリ 91,772 KB
最終ジャッジ日時 2025-05-14 13:08:58
合計ジャッジ時間 4,137 ms
ジャッジサーバーID
(参考情報)
judge3 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 15 TLE * 1 -- * 41
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <queue>
#include <tuple>
#include <map>
#include <algorithm>
#include <vector> // Ensure vector is included

using namespace std;

// Define long long type for convenience, as heights and d can be large
typedef long long ll;

// Use a map to store the minimum distance (operations) found so far to reach each state.
// The key is the state represented as a tuple of three heights (h1, h2, h3).
// The value is the minimum number of operations.
// `map` is used here for simplicity and standard compliance. `unordered_map` might be faster
// but requires a custom hash function for tuples.
map<tuple<ll, ll, ll>, ll> dist;

// Function to check if a state (h1, h2, h3) satisfies the problem conditions:
// 1. All three bamboo heights must be distinct.
// 2. The middle bamboo's height (h2) must be strictly the highest or strictly the lowest among the three.
bool check_condition(ll h1, ll h2, ll h3) {
    // Check for distinctness
    if (h1 == h2 || h1 == h3 || h2 == h3) {
        return false; // Heights are not distinct
    }
    // Check if middle bamboo is strictly the maximum
    bool middle_is_max = (h2 > h1 && h2 > h3);
    // Check if middle bamboo is strictly the minimum
    bool middle_is_min = (h2 < h1 && h2 < h3);
    
    // Return true if either condition (max or min) is met
    return middle_is_max || middle_is_min;
}


int main() {
    // Use fast I/O operations
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    ll d; // The amount height decreases by magic per operation
    cin >> d;
    vector<ll> H(3); // Vector to store initial heights H1, H2, H3
    cin >> H[0] >> H[1] >> H[2];

    // Handle the special case where d = 0.
    // If d=0, the magic operation does not change heights (max(0, h-0) = h for h>=0).
    // So, we only need to check if the initial heights satisfy the condition.
    if (d == 0) {
        if (check_condition(H[0], H[1], H[2])) {
            cout << 0 << endl; // Initial state is valid, 0 operations needed.
        } else {
            cout << -1 << endl; // Initial state is invalid, and cannot be changed. Impossible.
        }
        return 0; // Exit program after handling d=0 case.
    }

    // Use a priority queue for Dijkstra's algorithm (effectively BFS since edge weights are uniform 1).
    // It stores pairs of {cost, state}. `greater<>` makes it a min-priority queue based on cost.
    priority_queue<pair<ll, tuple<ll, ll, ll>>, vector<pair<ll, tuple<ll, ll, ll>>>, greater<pair<ll, tuple<ll, ll, ll>>>> pq;

    // Create the initial state tuple from input heights.
    tuple<ll, ll, ll> initial_state = make_tuple(H[0], H[1], H[2]);
    
    // The distance to the initial state is 0 operations. Store this in the distance map.
    dist[initial_state] = 0;
    // Push the initial state and its cost (0) into the priority queue.
    pq.push({0, initial_state});

    ll min_ops = -1; // Variable to store the minimum operations found. Initialize to -1 (signifying impossible/not found yet).
    int nodes_expanded_count = 0; // Counter for the number of nodes expanded (processed) from the priority queue.
    
    // Set a limit on the number of nodes expanded to prevent exceeding time or memory limits,
    // especially if the state space is huge or finding a solution requires many steps.
    // This value is a heuristic based on typical competitive programming constraints. 2 million states is reasonable for 128MB.
    const int MAX_NODES_EXPANDED = 2000000; 

    while (!pq.empty()) {
        // Extract the state with the minimum cost from the priority queue.
        auto top = pq.top();
        pq.pop();
        
        ll current_dist = top.first; // The minimum cost found so far to reach this state.
        tuple<ll, ll, ll> current_state = top.second; // The state itself (h1, h2, h3).
        
        // Optimization: Check if we have already processed this state via a path with less or equal cost.
        // If the recorded distance in `dist` map for this state is less than `current_dist`,
        // it means we found a shorter path earlier and already processed it, so we can skip this instance.
        auto it = dist.find(current_state);
        // Note: The check `it != dist.end()` is technically redundant if we ensure states are only added to PQ after being put in `dist`.
        // But it's safer. The condition `it->second < current_dist` correctly identifies redundant paths.
        if (it != dist.end() && it->second < current_dist) {
            continue;
        }
        
        // Unpack the current state tuple into individual heights h1, h2, h3.
        ll h1, h2, h3;
        tie(h1, h2, h3) = current_state; 
        
        // Check if the current state satisfies the problem conditions.
        if (check_condition(h1, h2, h3)) {
            min_ops = current_dist; // Found the solution. Record the minimum operations.
            break; // Exit the loop as Dijkstra guarantees the first time we extract a valid state, it's via the shortest path.
        }

        // Increment the count of expanded nodes.
        nodes_expanded_count++;
        // Check if we exceeded the expansion limit.
        if (nodes_expanded_count > MAX_NODES_EXPANDED) {
             min_ops = -1; // Ensure result is -1 if limit reached without finding solution.
             break; // Stop the search.
        }


        // Explore neighboring states by applying the magic operation to each of the three bamboos.
        vector<ll> current_heights = {h1, h2, h3};
        for (int i = 0; i < 3; ++i) { // Iterate through each bamboo (index 0, 1, 2).
            ll current_h = current_heights[i];
            
            // If the current height is 0, applying magic won't change it (since d > 0).
            // Skip this to avoid redundant processing and potential infinite loops if d=0 (already handled).
            if (current_h == 0) {
                  continue; 
            }

            // Apply the magic operation: new height is max(0, current_height - d).
            ll next_h = max(0LL, current_h - d);
            
            // Create the tuple representing the next state.
            vector<ll> next_heights = current_heights;
            next_heights[i] = next_h; // Update the height of the i-th bamboo.
            tuple<ll, ll, ll> next_state = make_tuple(next_heights[0], next_heights[1], next_heights[2]);
            
            // The cost to reach the next state is one more than the cost to reach the current state.
            ll new_dist = current_dist + 1;

            // Check if the next state has not been visited before, or if the new path found is shorter
            // than any previously found path to this state.
            auto it_next = dist.find(next_state);
            if (it_next == dist.end() || new_dist < it_next->second) {
                // Update the minimum distance found to reach `next_state`.
                dist[next_state] = new_dist; 
                // Add the `next_state` and its cost `new_dist` to the priority queue for future exploration.
                pq.push({new_dist, next_state}); 
            }
        }
    }

    // Output the minimum number of operations found. If no solution was found (or limit reached), min_ops remains -1.
    cout << min_ops << endl;

    return 0;
}
0