제출 #1317836

#제출 시각아이디문제언어결과실행 시간메모리
1317836spetr스핑크스 (IOI24_sphinx)C++20
1.50 / 100
1 ms332 KiB
#include <bits/stdc++.h> #include "sphinx.h" using namespace std; // Globální proměnné pro DSU (Disjoint Set Union) pro správu komponent vector<int> parent; int find_set(int v) { if (v == parent[v]) return v; return parent[v] = find_set(parent[v]); } void union_sets(int a, int b) { a = find_set(a); b = find_set(b); if (a != b) parent[b] = a; } std::vector<int> find_colours(int N, std::vector<int> X, std::vector<int> Y) { int n = N; vector<vector<int>> adj(n); for (size_t i = 0; i < X.size(); i++) { adj[X[i]].push_back(Y[i]); adj[Y[i]].push_back(X[i]); } // colors[i] bude držet ID barvy. Na začátku -1 (neznámá). vector<int> colors(n, -1); // Inicializace DSU parent.resize(n); iota(parent.begin(), parent.end(), 0); // Pole pro dotazy vector<int> a(n); for (int i = 0; i < n; i++) { // 1. Zjistíme, jaké barvy mají sousedé vrcholu i, kteří už jsou zpracovaní vector<int> neighbor_colors; for (int neighbor : adj[i]) { if (neighbor < i) { // Sousedé, které už jsme prošli neighbor_colors.push_back(find_set(neighbor)); } } // Odstraníme duplicity a seřadíme, abychom mohli binárně vyhledávat sort(neighbor_colors.begin(), neighbor_colors.end()); neighbor_colors.erase(unique(neighbor_colors.begin(), neighbor_colors.end()), neighbor_colors.end()); int found_color = -1; // -1 znamená "nová barva" // 2. Binární vyhledávání pouze nad barvami sousedů // Hledáme, jestli i patří do některé z existujících barevných komponent sousedů int l = 0, r = (int)neighbor_colors.size() - 1; while (l <= r) { int mid = l + (r - l) / 2; // Nastavíme dotaz: // Vrchol i bude mít barvu -1 // Sousedé s barvami v rozsahu [l, mid] budou mít taky -1 // Všichni ostatní budou mít svou unikátní barvu (nebo N, aby se nepletli) fill(a.begin(), a.end(), n); // Reset na "ignorovat" a[i] = -1; // Vybereme sadu barev, kterou testujeme vector<int> target_colors; for(int k = l; k <= mid; k++) target_colors.push_back(neighbor_colors[k]); // Označíme všechny vrcholy, které mají tuto barvu // (poznámka: pro optimalizaci bychom si mohli držet seznamy vrcholů pro každou barvu) int nodes_in_subset = 0; for(int u = 0; u < i; u++) { int root = find_set(u); bool matches = false; // Je u součástí testované množiny barev? // Protože target_colors je malá a setříděná, můžeme použít binary_search nebo prostý průchod for(int c : target_colors) if(c == root) matches = true; if(matches) { a[u] = -1; nodes_in_subset++; } else { a[u] = u; // Každý jiný vrchol má svou unikátní barvu, aby se nespojil } } // Teorie: Pokud se 'i' spojí s testovanou množinou, počet komponent bude o 1 menší, // než kdyby byl 'i' izolovaný. // Počet komponent tvořených vrcholy v podmnožině + vrchol i (všechny mají -1) // Pokud se i NEPOJÍ, bude to 1 (celá podmnožina se slije) + 1 (vrchol i) = 2 komponenty z pohledu -1 barvy? // Ne, jednodušší je porovnat s perform_experiment. // Mnohem robustnější logika pro Sphinx: // Pokud a[i] = -1 a skupina S má a[v] = -1. // Pokud se i spojí s S, celkový počet komponent v grafu klesne o 1 oproti stavu, kdy by i mělo unikátní barvu. int res = perform_experiment(a); // Kolik komponent bychom čekali? // Všichni v 'a' s hodnotou -1 by se měli slít do jedné komponenty, POKUD jsou propojení přes staré hrany. // Ale my víme, že staré hrany už barvy spojily. Takže všechny vrcholy s barvami v target_colors // už tvoří souvislý celek (nebo více) v rámci -1. // Trik: prostě se podíváme, jestli se 'i' chytilo. // Zjednodušení pro tuto úlohu: // Počet komponent = (počet vrcholů s unikátní barvou) + (počet komponent vzniklých z -1). // Vrcholy s a[u]=u přispívají každý 1. // Vrcholy s -1: Pokud se 'i' spojí s někým, bude to 1 komponenta. Pokud ne, budou to 1 (skupina) + 1 (vrchol i) = 2? // Pozor, skupina target_colors nemusí být souvislá mezi sebou navzájem, // ale my testujeme jestli se 'i' připojí k ALESPOŇ JEDNOMU z nich. // Uděláme to jednodušeji podle definice Sphinx: // Očekávaný počet = (počet vrcholů 0..i-1 mimo target_colors) + (počet disjunktních komponent v target_colors) + 1 (vrchol i). // Pokud real < očekávaný, znamená to, že se i spojilo s někým. int expected = 0; // Spočítáme očekávané komponenty ručně nebo s DSU (rychlejší): // Protože dáváme a[u]=u pro ostatní, každý je komponenta. int distinct_others = i - nodes_in_subset; // Komponenty uvnitř target_colors: // Protože target_colors jsou už ID z DSU, každá barva je jedna komponenta. // A všechny jsme přebarvili na -1. Orákulum je spojí jen pokud mezi nimi vedou hrany (to už by byly spojené) // nebo přes vrchol i. // Takže očekáváme (počet barev v target_colors) + 1 (vrchol i). // Pokud se i připojí k některé barvě, klesne to. int components_in_target = target_colors.size(); int total_expected = distinct_others + components_in_target + 1; if (res < total_expected) { // Spojilo se to! Hledaná barva je v levé polovině. found_color = target_colors.back(); // Prozatím uložíme // Musíme pokračovat v hledání, abychom našli tu první/konkrétní if (l == mid) { found_color = target_colors[0]; // Našli jsme přesně break; } r = mid; } else { // Nespojilo se, barva je v pravé polovině l = mid + 1; } } if (found_color != -1) { // i má stejnou barvu jako found_color union_sets(found_color, i); colors[i] = find_set(i); // Uložíme reprezentanta } else { // i má novou unikátní barvu // V DSU už je i samo sebou, což je ok. colors[i] = i; } } // Normalizace barev na 0..K (volitelné, Sphinx obvykle bere jakákoliv čísla) return colors; }
#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...