3 - Autobusi
Vremensko ograničenje | Memorijsko ograničenje |
---|---|
1500ms | 1024MB |
Tajna Komisija ni ovog puta nije imala vremena da takmičare povede u obilazak Beograda. Međutim, opšte je poznato da Beograd ima kvalitetan javni gradski prevoz, i da je ovaj prevoz besplatan za sve takmičare koji na sebi imaju značku na kojoj piše SIO 2015. Da bi takmičar ostvario pravo na besplatan prevoz, dovoljno je da vozaču pokaže značku. Međutim, Komisija je zabrinuta za bezbednost takmičara, pa želi da za neke parove početne i krajnje stanice zna koliko različitih autobuskih linija postoji, tako da je moguće doći od te početne do te krajnje stanice.
Svaka autobuska linija je opisana nizom stanica - moguće je ponavljanje stanica. Svaka stanica ima svoj identifikacioni broj koji je prirodan i manji ili jednak \(W\). Za neku liniju i neki par stanica \(x\),\(y\) kažemo da je moguće \(i\)-tom linijom doći od \(x\) do \(y\) ako i samo ako se u nizu stanica za tu liniju stanica \(x\) pojavljuje bar jednom pre nekog pojavljivanja stanice \(y\).
Opisi funkcija
Vašoj funkciji prosleđuje se \(n\), broj autobuskih linija; duzine, niz koji opisuje dužinu svake linije tj. broj stanica, zatim niz \(a\), koji je dobijen nadovezivanjem nizova stanica za sve autobuse; \(q\), broj upita; dva niza \(x\) i \(y\) - u \(i\)-tom upitu početna stanica je \(x[i]\), a krajnja \(y[i]\), i dat vam je niz \(resenja\) koji vaša funkcija treba da popuni: u \(resenja[i]\) upisati odgovor na \(i\)-ti upit.
Dodatno, označimo dužinu niza \(a\) sa \(m\). Svi nizovi su indeksirani od nule.
Primer
Neka je broj autobuskih linija \(n=3\), i neka su te linije opisane nizovima \([1,2,3,4]\),\([2,4]\),\([2,3,1,4]\). Onda je niz \(duzine=[4,2,4]\), i niz \(a=[1,2,3,4,2,4,2,3,1,4]\). Neka je broj upita \(q=4\) i neka su upiti \((1,3)\),\((2,4)\),\((1,4)\),\((4,1)\). Onda je \(x=[1,2,1,4]\) i \(y=[3,4,4,1]\). Vaša funkcija treba niz \(resenja\) da popuni sledećim vrednostima: \([1,3,2,0]\).
Za upit \((1,3)\), rešenje je \(1\) – jedina autobuska linija kod koje se stanica označena brojem \(1\) pojavljuje pre stanice označene brojem \(3\) je linija \([1,2,3,4]\).
Za upit \((2,4)\), rešenje je \(3\) – svakom linijom se može doći od stanice \(2\) do stanice \(4\).
Za upit \((1,4)\), rešenje je \(2\) – drugom linijom je nemoguće doći od \(1\) do \(4\) a preostalim dvema jeste.
Za upit \((4,1)\), rešenje je \(0\) – nijednom linijom se ne može doći od \(4\) do \(1\).
Ograničenja
- \(1\leq n,q\leq 100000\)
- \(W<100000\)
- \(m\leq 100000\)
- \(1\leq x[i],y[i]\leq W\)
- \(x[i] \neq y[i]\)
Podzadaci i bodovanje
- PODZADATAK 1 [9 POENA]: \(n,q,m\leq 1000\)
- PODZADATAK 2 [14 POENA]: \(n\leq 10\)
- PODZADATAK 3 [16 POENA]: \(W\leq 1000\)
- PODZADATAK 4 [26 POENA]: \(n,q,m\leq 50000\)
- PODZADATAK 5 [35 POENA]: Nema dodatnih ograničenja
Detalji implementacije
Potrebno je da pošaljete tačno jedan fajl, pod nazivom autobusi.c, autobusi.cpp ili autobusi.pas, koji implementira gore pomenutu funkciju. Osim tražene funkcije, vaš fajl može sadržati i dodatne globalne promenljive, pomoćne funkcije i dodatne biblioteke.
Zavisno od programskog jezika koji koristite, vaša funkcija/procedura mora biti sledećeg oblika:
C/C++
void resi(int n, int *duzine, int *a, int q, int *x, int *y, int *resenja);
Pascal
procedure resi(n : longint; var duzine, a : array of longint; q : longint; var x, y, resenja : array of longint);
Ukoliko radite u C/C++-u, potrebno je na početku fajla staviti #include “grader.h”
a ukoliko radite u Pascal-u, potrebno je na početku fajla staviti Unit autobusi;
(ovo je već dodato u fajlovima koji su vam obezbeđeni).
Testiranje i eksperimentisanje
Na raspolaganju su vam templejt fajlovi koje možete koristiti i menjati po potrebi. Takođe su vam obezbeđeni pomoćni programi () koji služe da lakše testirate kodove. Ovi programi učitavaju podatke sa standardnog ulaza, pozivaju vašu funkciju \(resi\) i ispisuju niz rešenja na standardni izlaz. Kodove ovih programa možete menjati po potrebi. Format ulaza za programe je sledeći:
U prvi red upisati broj autobuskih linija \(n\). U drugi red upisati \(n\) brojeva - dužine autobuskih linija. Za narednih \(n\) redova, u \(i\)-ti upisati \(duzine[i]\) brojeva, oznake stanica. U naredni red upisati \(q\) - broj upita. Za narednih \(q\) redova, u \(i\)-ti upisati dva broja \(x[i]\) i \(y[i]\), identifikacione brojeve početne i krajnje stanice.
Izgled ulaza za gore opisan primer je sledeći:
Autor | Tekst i test primeri | Analiza rеšenja | Testiranje |
---|---|---|---|
Ivan Stošić | Ivan Stošić | Aleksandar Višnjić | Dragan Urošević |
Prvi podzadatak:
Svakim upitom prolazimo jednom kroz niz \(A\). Napravićemo pomoćni bool niz \(B\) koji nam služi da pamtimo prethodno posećene stanice u tom prolasku. \(A\) se po definiciji deli na disjunktne segmente koji označavaju po jednu autobusku liniju, stoga kada prođemo kroz jedan takav segment potrebno je opet proći i markirati sve njegove stanice kao neposećene, pošto se svaki segment rešava zasebno. Kada naiđemo na \(Y_i\), potrebno je samo proveriti da li je stanica \(X_i\) već posećena. (Napomena: broj rešenja se povećava najviše jednom po segmentu/autobuskoj liniji) Vremenska složenost je \(O(Q\cdot M+N+W)\), a memorijska \(O(W)\).
Drugi podzadatak:
Pravimo dve pomoćne matrice \(L[i][j]\) i \(R[i][j]\) koje, redom, označavaju prvo i poslednje pojavljivanje stanice \(j\) u liniji \(i\). Broj \(-1\) označava da takva stanica ne postoji. Sada za svaki upit možemo jednostavno proveriti da li se \(X_i\) nalazi pre \(Y_i\) u svakoj od \(N\) autobuskih linija. Vremenska složenost je \(O(N\cdot W+N\cdot Q+M)\), a memorijska \(O(N\cdot W)\).
Treći podzadatak:
Izračunaćemo za svake dve stanice broj linija, pa ćemo odgovarati na upite u \(O(1)\). Za efikasno računanje ćemo po svakoj liniji zasebno proći po svim parovima stanica u njoj i odrediti da li je moguće da se jedna nađe pre druge. (Računamo samo jednistvene stanice u liniji)
Ovo radi u \(O(len_i^2)\) vremenu po liniji \(i\) koja ima \(len_i\leq W\) stanica. Neka je \(f(len_1,len_2,...,len_N)=\sum_{i=1}^N len_i^2\). Nije teško videti da važi \(f(...,len_i+1,...,len_j-1,...)>f(...,len_i,...,len_j,..)\) ako je \(len_i\geq len_j\) i \(i\neq j\). (Ne mora da važi \(i<j\) kao u primeru gore, bitno je samo da su različiti indeksi) Iz ovoga neposredno sledi \(f(len_1,...,len_N)\leq f(W,...,W,0,...,0)\). U drugoj funkciji se \(W\) pojavljuje ne više od \(\frac{M+W}{W}\) puta, pa važi \(f(W,...,W,0,...,0)\leq (M+W)\cdot W\) i to je naše gornje ograničenje za broj operacija.
Vremenska složenost je \(O(M\cdot W+W^2 + N+Q)\), a memorijska \(O(W^2)\).
Četvrti podzadatak:
Napravimo dva niza mapa \(L\) i \(R\) veličine \(N\). U njima za svaku autobusku liniju i stanicu u njoj pamtimo njeno prvo i poslednje pojavljivanje u okviru date linije. Takođe, pravimo niz skupova \(S\) veličine \(W\). U njemu za svaku stanicu određujemo koje sve linije prolaze kroz nju. Na upite odgovaramo na sledeći način:
Ako smo već odgovorili na upit \((X_i,Y_i)\), samo ćemo uzeti prethodno zapamćeno rešenje. (ovo je neophodno jer će računanje novih odgovora biti sporo, a bitno je garantovati da oni budu različiti) Za nov upit ćemo jednom proći kroz manji od skupova \(S[X_i]\) ili \(S[Y_i]\), i za svaku njegovu autobusku liniju odrediti da li se \(X_i\) nalazi pre \(Y_i\).
Ovo na prvi pogled izgleda kao da radi u \(O(Q\cdot N)\) vremenu sa malom konstantom. Dokazaćemo da to nije slučaj. Neka niz \(s_i\) predstavlja koliko smo puta prošli kroz skup \(S[i]\). Možemo nadalje pretpostaviti, bez umanjenja opštosti, da je dat niz skupova sortiran u nerastućem poretku po njihovim veličinama. Kako nikad ne pitamo dva ista skupa više od dvaput, i kako uvek pitamo manji od dva skupa, možemo zaključiti \(s_i \leq2( i-1)\) za svako \(1\leq i \leq W\). Ukupan broj operacija iznosi \(\sum s_i\cdot S[i].size\) , a maksimum se upravo postiže za \(s_i=2(i-1)\), \(1\leq i \leq \sqrt{Q}\). (Otprilike, mora da važi \(\sum s_i=Q\), a \(2\cdot \sum_{i=1}^{\sqrt{Q}} (i-1)\) prevazilazi \(Q\)) Kada bismo mogli da menjamo veličine skupova iz niza \(S\) prebacivanjem jednog elementa u drugi, povećao bi se ukupni broj operacija kada bi se povećao i skup sa više prolaska. (tj. većim brojem \(s_i\)) Ovim se na kraju dobija da najveći ukupan broj operacija nije veći nego u slučaju u kom važi \(S[1].size=S[2].size=...=S[Q].size= \sqrt{N}\), zbog poretka veličina. Algoritam će izvršiti najviše \(O(Q\sqrt{N})\) operacija.
Ako koristimo std::map i std::set, ukupna vremenska složenost je \(O(Q\cdot \sqrt{N}\cdot logN +N+M+W )\) , a memorijska \(O(N+M+W)\).
Glavno rešenje:
Rešenje je isto kao i u četvrtom podzadatku, samo ćemo umesto std::set i std::map koristiti std::unordered_set i std::unordered_map, čime se vremenska složenost poboljšava na \(O(Q\cdot\sqrt{N}+N+M+W)\). Zadatak se takođe može rešiti i offline nešto brže tako što ćemo postojanje linije koja prolazi kroz neku stanicu odrediti naknadno, ali implementacija toga je malo teža. Sve u svemu, ukupna vremenska složenost je \(O(Q\cdot\sqrt{N}+N+M+W)\), a memorijska \(O(N+M+W)\).
03_autobusi.cpp | |
---|---|
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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
|