結果

問題 No.9 モンスターのレベル上げ
ユーザー qwewe
提出日時 2025-05-14 12:59:53
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 281 ms / 5,000 ms
コード長 7,947 bytes
コンパイル時間 1,068 ms
コンパイル使用メモリ 86,320 KB
実行使用メモリ 6,272 KB
最終ジャッジ日時 2025-05-14 13:02:13
合計ジャッジ時間 4,567 ms
ジャッジサーバーID
(参考情報)
judge3 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 20
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream> // For input/output operations
#include <vector>   // For using dynamic arrays (vectors)
#include <queue>    // For using priority queue
#include <numeric>  // Potentially useful for some operations, though not used here
#include <algorithm> // For std::max and std::min functions

// Use a type alias for long long to handle potentially large monster levels.
using ll = long long;

// Define a structure to hold the state of a monster.
// This structure will be used in the priority queue to manage monster selection.
struct MonsterState {
    ll level;           // Current level of the monster
    int fight_count;    // Number of times this monster has fought so far in the simulation
    int id;             // Original 0-based index of the monster, used as a final tie-breaker
    int has_fought_flag; // A helper flag: 0 if fight_count is 0, 1 otherwise. Used to prioritize monsters that haven't fought.

    // Custom comparison logic for the priority queue.
    // This defines the operator> which is used by std::priority_queue when configured with std::greater<MonsterState>.
    // It determines the order of elements, effectively making the priority queue a min-heap based on these rules.
    // The element for which this operator returns 'false' more often compared to others is considered 'smaller' and has higher priority.
    bool operator>(const MonsterState& other) const {
        // Rule 1: Prioritize minimum level.
        if (level != other.level) {
            return level > other.level; // Lower level is smaller (preferred). Return true if this level is greater.
        }
        
        // Rule 2 (Tiebreak 1): Prioritize monsters that haven't fought yet.
        // The has_fought_flag is 0 for monsters that haven't fought, 1 otherwise.
        // 0 is considered smaller (preferred) than 1.
        if (has_fought_flag != other.has_fought_flag) {
            // If this flag is 1 and other is 0, this is larger -> return true.
            // If this flag is 0 and other is 1, this is smaller -> return false.
            return has_fought_flag > other.has_fought_flag; 
        }
        
        // Rule 3 (Tiebreak 2): Prioritize minimum fight count.
        // This rule applies when levels are equal AND either:
        // a) Both monsters haven't fought (has_fought_flag=0, fight_count=0 for both).
        // b) Both monsters have fought (has_fought_flag=1 for both).
        // In case a), fight counts are equal (both 0), so this check passes.
        // In case b), we compare their actual fight counts.
        if (fight_count != other.fight_count) {
            return fight_count > other.fight_count; // Lower fight count is smaller (preferred). Return true if this count is greater.
        }
        
        // Rule 4 (Tiebreak 3): Prioritize minimum original index (ID).
        // This ensures a deterministic choice when all previous criteria result in a tie.
        return id > other.id; // Lower ID is smaller (preferred). Return true if this ID is greater.
    }
};


int main() {
    // Optimize standard C++ input/output stream operations for faster execution.
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int N; // Number of monsters in the team and also the number of enemy monsters.
    std::cin >> N;

    // Read the initial levels of the N team monsters. Store in a vector of long longs.
    std::vector<ll> A(N); 
    for (int i = 0; i < N; ++i) {
        std::cin >> A[i];
    }

    // Read the levels of the N enemy monsters. Store in a vector of ints.
    // Enemy levels are up to 10000, so int is sufficient.
    std::vector<int> B(N); 
    for (int i = 0; i < N; ++i) {
        std::cin >> B[i];
    }

    // Variable to store the minimum value found for the maximum fight count across all simulations.
    // Initialize it to N + 1, a value guaranteed to be larger than any possible maximum fight count (which is at most N).
    int min_max_fights = N + 1; 

    // Iterate through all N possible starting positions for fighting the enemy monsters.
    // start_idx represents the index of the first enemy monster to fight.
    for (int start_idx = 0; start_idx < N; ++start_idx) {
        
        // Set up a min-priority queue for the current simulation.
        // It stores MonsterState objects and uses std::greater<MonsterState> along with the overloaded operator> 
        // to maintain min-heap property according to our custom comparison logic.
        std::priority_queue<MonsterState, std::vector<MonsterState>, std::greater<MonsterState>> pq;
        
        // Create copies of the initial states for this simulation run.
        // This is important because each simulation starts from the same initial conditions.
        std::vector<ll> current_levels = A; // Copy initial levels.
        std::vector<int> fight_counts(N, 0); // Initialize fight counts to 0 for all monsters.

        // Populate the priority queue with the initial state of each team monster.
        for(int i = 0; i < N; ++i) {
             // Initial state: level is A[i], fight_count is 0, id is i, has_fought_flag is 0.
             pq.push({current_levels[i], 0, i, 0}); 
        }

        // Simulate the sequence of N battles against the enemy monsters.
        for (int k = 0; k < N; ++k) {
            // Calculate the index of the enemy monster for the k-th battle (0-indexed).
            // The sequence starts at start_idx and proceeds clockwise (wraps around using modulo N).
            int enemy_idx = (start_idx + k) % N;
            int enemy_level = B[enemy_idx];

            // Select the monster to fight: The highest priority monster is at the top of the min-priority queue.
            MonsterState chosen_monster_state = pq.top();
            pq.pop(); // Remove the selected monster from the queue temporarily.

            int monster_id = chosen_monster_state.id; // Get the index (ID) of the chosen monster.

            // Update the state of the chosen monster after the battle.
            // Level increases by floor(enemy_level / 2). Integer division automatically performs floor.
            // Cast enemy_level to ll before adding to potentially large current_level to be safe, although addition result would fit ll anyway.
            current_levels[monster_id] += (ll)enemy_level / 2; 
            fight_counts[monster_id]++; // Increment the fight count for this monster.

            // Determine the new has_fought_flag. It becomes 1 once the fight_count is greater than 0.
            int new_has_fought_flag = (fight_counts[monster_id] == 0) ? 0 : 1;

            // Insert the monster back into the priority queue with its updated state.
            // The priority queue will automatically place it in the correct position based on its new state.
            pq.push({current_levels[monster_id], 
                     fight_counts[monster_id], 
                     monster_id, 
                     new_has_fought_flag});
        }

        // After completing all N battles for the current starting position:
        // Find the maximum fight count among all team monsters during this simulation run.
        int current_max_fights = 0;
        // Iterate through the final fight counts of all monsters.
        for (int count : fight_counts) {
             current_max_fights = std::max(current_max_fights, count); // Update max if current count is higher.
        }
        
        // Update the overall minimum maximum fight count found across all starting positions tested so far.
        min_max_fights = std::min(min_max_fights, current_max_fights); // Update min if current max is lower.
    }

    // Output the final result: the minimum possible value for the maximum number of fights any single monster had.
    // The problem requires the output to be followed by a newline character.
    std::cout << min_max_fights << "\n"; 

    return 0; // Indicate successful execution.
}
0