結果
問題 |
No.281 門松と魔法(1)
|
ユーザー |
![]() |
提出日時 | 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 |
ソースコード
#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; }