제출 #1251767

#제출 시각아이디문제언어결과실행 시간메모리
1251767coin_Permutation Game (APIO25_permgame)C++20
0 / 100
1 ms328 KiB
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>

// Forward declaration of the grader's function for interaction with Bob.
int Bob(std::vector<int> t);

namespace {
    // Helper structures for graph analysis and permutation tracking.
    std::vector<std::vector<int>> adj;
    std::vector<int> color;
    std::vector<bool> visited;

    // Utility function to check for bipartiteness using 2-coloring (BFS/DFS).
    // It's run on the graph which is known to be connected.
    bool is_bipartite_util(int u, int c) {
        visited[u] = true;
        color[u] = c;
        for (int v : adj[u]) {
            if (!visited[v]) {
                if (!is_bipartite_util(v, 1 - c)) {
                    return false;
                }
            } else if (color[v] == color[u]) {
                return false;
            }
        }
        return true;
    }
}

int Alice(int m, int e, std::vector<int> u, std::vector<int> v,
          int n, std::vector<int> p) {
    
    // 1. Calculate the initial score of the permutation.
    int initial_score = 0;
    for (int i = 0; i < n; ++i) {
        if (p[i] == i) {
            initial_score++;
        }
    }

    // 2. Analyze the graph's structure.
    adj.assign(m, std::vector<int>());
    for (int i = 0; i < e; ++i) {
        adj[u[i]].push_back(v[i]);
        adj[v[i]].push_back(u[i]);
    }

    visited.assign(m, false);
    color.assign(m, -1);
    // The problem statement guarantees the graph is connected.
    bool is_graph_bipartite = is_bipartite_util(0, 0);

    // If the graph is bipartite, Alice cannot guarantee forcing the swaps she needs.
    // No improvement is possible against an optimal Bob.
    if (is_graph_bipartite) {
        return initial_score;
    }

    // 3. If non-bipartite, find winnable permutation cycles.
    // A cycle C is winnable if |C| >= 2m - 1. This ensures Alice can always
    // continue breaking it down until a fixed point is made.
    long long required_cycle_size = 2LL * m - 1;
    int winnable_cycles_count = 0;
    std::vector<std::vector<int>> winnable_cycles_nodes;

    visited.assign(n, false);
    for (int i = 0; i < n; ++i) {
        if (p[i] == i || visited[i]) {
            continue;
        }
        
        std::vector<int> current_cycle;
        int current = i;
        while (!visited[current]) {
            visited[current] = true;
            current_cycle.push_back(current);
            current = p[current];
        }
        
        if (current_cycle.size() >= required_cycle_size) {
            winnable_cycles_count++;
            winnable_cycles_nodes.push_back(current_cycle);
        }
    }

    int optimal_score = initial_score + winnable_cycles_count;

    // 4. Play the game to achieve the optimal score, if it's higher than the start.
    if (optimal_score > initial_score) {
        for (const auto& cycle_to_fix : winnable_cycles_nodes) {
            int target_node = cycle_to_fix[0];
            std::vector<int> current_piece = cycle_to_fix;

            // Keep playing on this cycle until our target becomes a fixed point.
            while (p[target_node] != target_node) {
                std::vector<int> t(m);
                // Map the first m nodes of the current cycle piece to the graph vertices.
                // The size condition guarantees the piece is large enough to do this
                // until the very end.
                for (int k = 0; k < m; ++k) {
                    t[k] = current_piece[k];
                }

                int edge_j = Bob(t);
                std::swap(p[t[u[edge_j]]], p[t[v[edge_j]]]);

                // After the swap, re-evaluate the cycle piece containing our target node.
                std::vector<bool> visited_piece(n, false);
                current_piece.clear();
                int current = target_node;
                while (!visited_piece[current] && p[current] != current) {
                    visited_piece[current] = true;
                    current_piece.push_back(current);
                    current = p[current];
                }
            }
        }
    }

    return optimal_score;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...