#include <iostream>
#include <vector>
using namespace std;
/**
* Problem: Minimalne pokrycie wierzchołków ścieżkami w DAG-u z dolnym ograniczeniem przepływu (>=1).
* * Wyjaśnienie:
* Każde spotkanie musi mieć co najmniej jednego pracownika.
* - Jeśli spotkanie nie ma poprzednika, musimy dodać nowego pracownika.
* - Jeśli spotkanie ma poprzednika, 'dziedziczy' pracownika z dnia poprzedniego.
* - Jeśli wiele spotkań dziedziczy po tym samym poprzedniku, musimy dodać pracowników
* dla każdego 'nadmiarowego' połączenia (rozgałęzienia).
*/
void solve() {
int k;
if (!(cin >> k)) return;
int n_prev;
cin >> n_prev;
// Na start potrzebujemy tylu pracowników, ile jest spotkań pierwszego dnia.
long long total_workers = n_prev;
for (int i = 2; i <= k; ++i) {
int ni;
cin >> ni;
// Tablica liczników: ile razy każde spotkanie z dnia i-1 jest kontynuowane
// n_prev + 1, bo spotkania są numerowane od 1 do n.
vector<int> out_degree(n_prev + 1, 0);
int starts_new = 0;
for (int j = 0; j < ni; ++j) {
int prev_id;
cin >> prev_id;
if (prev_id == 0) {
// To spotkanie nie kontynuuje niczego -> nowy pracownik od zera
starts_new++;
} else {
// Zwiększamy licznik wyjść dla spotkania z dnia poprzedniego
out_degree[prev_id]++;
}
}
// Dodajemy nowych pracowników, którzy zaczynają od spotkań typu "0"
total_workers += starts_new;
// Kluczowa optymalizacja:
// Jeśli spotkanie p z dnia i-1 ma m kontynuacji (gdzie m > 1),
// to musimy dołożyć (m - 1) pracowników do tego konkretnego węzła.
for (int p = 1; p <= n_prev; ++p) {
if (out_degree[p] > 1) {
total_workers += (out_degree[p] - 1);
}
}
n_prev = ni;
}
cout << total_workers << endl;
}
int main() {
// Szybkie I/O jest niezbędne przy 500 000 danych wejściowych
ios_base::sync_with_stdio(false);
cin.tie(NULL);
solve();
return 0;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #include <iostream> #include <vector> using namespace std; /** * Problem: Minimalne pokrycie wierzchołków ścieżkami w DAG-u z dolnym ograniczeniem przepływu (>=1). * * Wyjaśnienie: * Każde spotkanie musi mieć co najmniej jednego pracownika. * - Jeśli spotkanie nie ma poprzednika, musimy dodać nowego pracownika. * - Jeśli spotkanie ma poprzednika, 'dziedziczy' pracownika z dnia poprzedniego. * - Jeśli wiele spotkań dziedziczy po tym samym poprzedniku, musimy dodać pracowników * dla każdego 'nadmiarowego' połączenia (rozgałęzienia). */ void solve() { int k; if (!(cin >> k)) return; int n_prev; cin >> n_prev; // Na start potrzebujemy tylu pracowników, ile jest spotkań pierwszego dnia. long long total_workers = n_prev; for (int i = 2; i <= k; ++i) { int ni; cin >> ni; // Tablica liczników: ile razy każde spotkanie z dnia i-1 jest kontynuowane // n_prev + 1, bo spotkania są numerowane od 1 do n. vector<int> out_degree(n_prev + 1, 0); int starts_new = 0; for (int j = 0; j < ni; ++j) { int prev_id; cin >> prev_id; if (prev_id == 0) { // To spotkanie nie kontynuuje niczego -> nowy pracownik od zera starts_new++; } else { // Zwiększamy licznik wyjść dla spotkania z dnia poprzedniego out_degree[prev_id]++; } } // Dodajemy nowych pracowników, którzy zaczynają od spotkań typu "0" total_workers += starts_new; // Kluczowa optymalizacja: // Jeśli spotkanie p z dnia i-1 ma m kontynuacji (gdzie m > 1), // to musimy dołożyć (m - 1) pracowników do tego konkretnego węzła. for (int p = 1; p <= n_prev; ++p) { if (out_degree[p] > 1) { total_workers += (out_degree[p] - 1); } } n_prev = ni; } cout << total_workers << endl; } int main() { // Szybkie I/O jest niezbędne przy 500 000 danych wejściowych ios_base::sync_with_stdio(false); cin.tie(NULL); solve(); return 0; } |
English