Submission #1238838

#TimeUsernameProblemLanguageResultExecution timeMemory
1238838hugo_pmSphinx's Riddle (IOI24_sphinx)C++20
50 / 100
172 ms1216 KiB
#include "sphinx.h"
#include <cassert>
#include <numeric>
#include <set>
using namespace std;

struct DSU {
  vector<int> parent;
  DSU(int n) : parent(n) { iota(parent.begin(), parent.end(), 0); }
  int find(int x) { return parent[x] == x ? x : parent[x] = find(parent[x]); }
  void merge(int a, int b) { parent[find(a)] = find(b); }
};

vector<int> find_colours(int N, vector<int> X, vector<int> Y) {
    auto only_keep = [&N] (vector<int> kept) {
        vector<int> E(N, N);
        for (int node : kept)
            E[node] = -1;
        return E;
    };

    vector<vector<int>> adj(N);
    for (int iEdge = 0; iEdge < (int)X.size(); ++iEdge) {
        int u = X[iEdge], v = Y[iEdge];
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    auto non_sphinx_comps = [&N, &adj] (vector<int> E) -> int {
        vector<bool> seen(N, false);
        auto Dfs = [&] (auto dfs, int node) -> void {
            seen[node] = true;
            for (int neighbor : adj[node])
                if (E[neighbor] == N && !seen[neighbor])
                    dfs(dfs, neighbor);
        };
        int cnt_sphinx_comp = 0;
        for (int node = 0; node < N; ++node) {
            if (E[node] == N && !seen[node]) {
                ++cnt_sphinx_comp;
                Dfs(Dfs, node);
            }
        }
        return perform_experiment(E) - cnt_sphinx_comp;
    };

    DSU uf(N);
    /// takes a subset of the neighborhood of center
    /// and returns a subsubset of those neighbors st they are pairwise not
    /// in the same DSU component
    auto simplified = [&] (const vector<int> &orig, int center) {
        set<int> dsu_roots;
        vector<int> root_to_orig(N, -1);
        for (int x : orig) {
            root_to_orig[uf.find(x)] = x;
            if (uf.find(x) != uf.find(center))
                dsu_roots.insert(uf.find(x));
        }
        vector<int> ret;
        for (int root : dsu_roots)
            ret.push_back(root_to_orig[root]);        
        // expected: non_sphinx_comps(only_keep(ret)) == (int)ret.size())
        return ret;
    };
    for (int center = 0; center < N; ++center) {
        vector<int> less_neighbors;
        for (int nei : adj[center])
            if (nei < center)
                less_neighbors.push_back(nei);
        while (true) {
            auto has_friend = [&] (vector<int> subset) { // assumes S simplified
                assert(subset == simplified(subset, center));
                subset.push_back(center);
                return non_sphinx_comps(only_keep(subset)) < (int)subset.size();
            };
            auto potentials = simplified(less_neighbors, center);
            if (!has_friend(potentials)) break;
            while ((int)potentials.size() >= 2) {
                vector<int> even, odd;
                for (int i = 0; i < (int)potentials.size(); ++i) {
                    (i % 2 ? odd : even).push_back(potentials[i]);
                }
                if (has_friend(even))
                    potentials = even;
                else
                    potentials = odd;
            }
            uf.merge(center, potentials[0]);
        }
    }
    vector<int> answer(N, 0);
    for (int node = 0; node < N; ++node) {
        answer[node] = uf.find(node);
    }
    return answer;
}
#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...