Skip to content

Commit b760f4d

Browse files
Dodano rozwiązania zadania 'Telefony' z XXXI OI
Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
1 parent ddc1b90 commit b760f4d

File tree

5 files changed

+202
-8
lines changed

5 files changed

+202
-8
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@ git pull
8787

8888
Etap I | Etap II | Etap III | Łącznie
8989
:---: | :---: | :---: | :---:
90-
43/150 (29%) | 54/157 (34%) | 42/200 (21%) | 139/507 (27%)
90+
43/150 (29%) | 55/157 (35%) | 42/200 (21%) | 140/507 (28%)
9191

9292
## Rozwiązane zadania wg edycji
9393

9494
Edycja | Wynik | Edycja | Wynik | Edycja | Wynik | Edycja | Wynik
9595
:--- | ---: | :--- | ---: | :--- | ---: | :--- | ---:
96-
I | 3/10 (30%) | XI | 2/16 (12%) | XXI | 6/17 (35%) | XXXI | 5/17 (29%)
96+
I | 3/10 (30%) | XI | 2/16 (12%) | XXI | 6/17 (35%) | XXXI | 6/17 (35%)
9797
II | 4/14 (29%) | XII | 4/17 (24%) | XXII | 6/17 (35%) | XXXII | 7/18 (39%)
9898
III | 2/13 (15%) | XIII | 5/16 (31%) | XXIII | 3/17 (18%) | |
9999
IV | 3/16 (19%) | XIV | 3/16 (19%) | XXIV | 7/16 (44%) | |
@@ -180,7 +180,7 @@ XXVII | | czw ✅ | | |
180180
XXVIII | | ple ✅ | | pla ✅ |
181181
XXIX | | | | kon ✅ | bom ✅
182182
XXX | | | | |
183-
XXXI | | lic ✅ | ryc ✅ | cia ✅ | poj ✅
183+
XXXI | tel ✅ | lic ✅ | ryc ✅ | cia ✅ | poj ✅
184184
XXXII | sss ✅ | drz ✅ | | |
185185
</details>
186186

checklista/oi_progress.svg

Lines changed: 5 additions & 5 deletions
Loading

checklista/tasks.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,13 @@
902902
"nazwa": "poj",
903903
"punkty": 100
904904
},
905+
"xxxi_etap2_tel": {
906+
"edycja": 31,
907+
"etap": 2,
908+
"dzien": 0,
909+
"nazwa": "tel",
910+
"punkty": 100
911+
},
905912
"xxxi_etap2_dzien1_lic": {
906913
"edycja": 31,
907914
"etap": 2,

rozwiazania/xxxi/etap2/tel/tel.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Rozwiązanie do zadania 'Telefony' z II etapu XXXI OI.
2+
// Autor rozwiązania: Paweł Putra
3+
// Złożoność czasowa: O(n).
4+
// Złożoność pamięciowa: (n).
5+
// Punkty: 100
6+
7+
#include <bits/stdc++.h>
8+
#define dbg(x) #x << " = " << x << " "
9+
using namespace std;
10+
using ll = long long;
11+
constexpr int MAXN = 500'005;
12+
ll h[MAXN], w[MAXN];
13+
int vis[MAXN];
14+
vector<int> g[MAXN], sasiedzi[MAXN];
15+
16+
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
17+
ll R(ll a, ll b) {
18+
return uniform_int_distribution<ll>(a, b)(rng);
19+
}
20+
21+
void dfs(int u) {
22+
vis[u] = 1;
23+
for (auto v : g[u]) {
24+
if (!vis[v]) {
25+
cout << u << " " << v << "\n";
26+
dfs(v);
27+
}
28+
}
29+
}
30+
31+
int32_t main() {
32+
ios_base::sync_with_stdio(0);
33+
int n;
34+
cin >> n;
35+
36+
if (n == 1) {
37+
cout << "1\n"
38+
<< "1\n";
39+
return 0;
40+
}
41+
42+
// Haszem zbioru będzie suma jego wartości,
43+
// żeby mieć niskie prawdopodobieństwo kolizji zmieniam wartości liczb na losowe.
44+
for (int i = 1; i <= n; i++) w[i] = R(1, 1'000'000'000'000LL);
45+
46+
for (int i = 1; i <= n; i++) {
47+
int k;
48+
cin >> k;
49+
h[i] += w[i];
50+
while (k--) {
51+
int x;
52+
cin >> x;
53+
54+
h[i] += w[x];
55+
sasiedzi[i].push_back(x);
56+
57+
// if (x > i && (sasiedzi[i].empty() || sasiedzi[i].back() < i)) sasiedzi[i].push_back(w[i]);
58+
// sasiedzi[i].push_back(w[x]);
59+
}
60+
}
61+
62+
// Przemapowujemy hasze na numery wierzchołków z przedziału [1, m].
63+
unordered_map<ll, int> numer;
64+
for (int i = 1; i <= n; i++) {
65+
// To przypisuje od jedynki, bo sprawdzenie czy coś jest w mapie do niej insertuje.
66+
if (!numer[h[i]]) numer[h[i]] = numer.size();
67+
h[i] = numer[h[i]];
68+
}
69+
70+
// Jedyny przypadek jak reprezentacja jest niejednoznaczna to jak wszyscy mają te same sąsiedztwo wliczając siebie.
71+
// Wtedy możemy zawsze zrobić drzewo o 2 wierzchołkach dla n >= 2.
72+
if (numer.size() == 1) {
73+
cout << "2\n"
74+
<< "1";
75+
for (int i = 2; i <= n; i++) cout << " 2";
76+
cout << "\n"
77+
<< "1 2\n";
78+
79+
return 0;
80+
}
81+
82+
int m = numer.size();
83+
cout << numer.size() << "\n";
84+
for (int i = 1; i <= n; i++) {
85+
cout << h[i] << " ";
86+
87+
for (auto j : sasiedzi[i]) {
88+
if (h[i] != h[j]) g[h[i]].push_back(h[j]);
89+
}
90+
}
91+
92+
cout << "\n";
93+
// Żeby nie wypisać żadnej krawędzi więcej niż raz po prostu wypiszę je dfsem.
94+
dfs(1);
95+
96+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Rozwiązanie do zadania 'Telefony' z II etapu XXXI OI.
2+
// Autor rozwiązania: Paweł Putra
3+
// Złożoność czasowa: O(n * log^2(n)), bo każdą literkę słowa szukanego w mapie sprawdzę max log(n) razy.
4+
// Złożoność pamięciowa: (n).
5+
// Punkty: 100 (dziwi mnie, że nie mniej)
6+
7+
8+
9+
#include <bits/stdc++.h>
10+
#define dbg(x) #x << " = " << x << " "
11+
using namespace std;
12+
using ll = long long;
13+
constexpr int MAXN = 500'005;
14+
ll h[MAXN];
15+
int vis[MAXN];
16+
vector<int> g[MAXN], sasiedzi[MAXN];
17+
18+
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
19+
ll R(ll a, ll b) {
20+
return uniform_int_distribution<ll>(a, b)(rng);
21+
}
22+
23+
void dfs(int u) {
24+
vis[u] = 1;
25+
for (auto v : g[u]) {
26+
if (!vis[v]) {
27+
cout << u << " " << v << "\n";
28+
dfs(v);
29+
}
30+
}
31+
}
32+
33+
int32_t main() {
34+
ios_base::sync_with_stdio(0);
35+
int n;
36+
cin >> n;
37+
38+
if (n == 1) {
39+
cout << "1\n"
40+
<< "1\n";
41+
return 0;
42+
}
43+
44+
map<vector<int>, int> numer;
45+
for (int i = 1; i <= n; i++) {
46+
int k;
47+
cin >> k;
48+
while (k--) {
49+
int x;
50+
cin >> x;
51+
52+
if (x > i && (sasiedzi[i].empty() || sasiedzi[i].back() < i))
53+
sasiedzi[i].push_back(i);
54+
sasiedzi[i].push_back(x);
55+
}
56+
if (sasiedzi[i].empty() || sasiedzi[i].back() < i)
57+
sasiedzi[i].push_back(i);
58+
59+
if (!numer.count(sasiedzi[i]))
60+
numer[sasiedzi[i]] = numer.size() + 1;
61+
}
62+
63+
// Jedyny przypadek jak reprezentacja jest niejednoznaczna to jak wszyscy mają te same sąsiedztwo wliczając siebie.
64+
// Wtedy możemy zawsze zrobić drzewo o 2 wierzchołkach dla n >= 2.
65+
if (numer.size() == 1) {
66+
cout << "2\n"
67+
<< "1";
68+
for (int i = 2; i <= n; i++) cout << " 2";
69+
cout << "\n"
70+
<< "1 2\n";
71+
72+
return 0;
73+
}
74+
75+
for (int i = 1; i <= n; i++) h[i] = numer[sasiedzi[i]];
76+
77+
int m = numer.size();
78+
cout << numer.size() << "\n";
79+
for (int i = 1; i <= n; i++) {
80+
cout << h[i] << " ";
81+
82+
for (auto j : sasiedzi[i]) {
83+
if (h[i] != h[j]) g[h[i]].push_back(h[j]);
84+
}
85+
}
86+
87+
cout << "\n";
88+
// Żeby nie wypisać żadnej krawędzi więcej niż raz po prostu wypiszę je dfsem.
89+
dfs(1);
90+
91+
}

0 commit comments

Comments
 (0)