You are on page 1of 9

Zadatak BOMBONI Autori: Antonio Jurić, Marin Tomić

Lako je vidjeti da je najbolje podijeliti bombone na tri jednaka dijela, a mogući


ostatak dati Petru.

potrebno znanje: dijeljenje s ostatkom


kategorija: ad-hoc

Zadatak TEKMA Autori: Antonio Jurić, Marin Tomić

Neka je rezultat u prvoj utakmici bio A:B, a u drugoj C:D. Tada je broj
pogodaka NK Maslina jednak A+D, a broj pogodaka NK Drača je B+C.

Koliko pogodaka mora zabiti NK Maslina?


Ako je A+D > B+C, onda ne moraju zabiti niti jedan pogodak.
Ako je A+D = B+C, gledamo koja je momčad zabila više pogodaka u gostima.
Ako je C > D onda NK Maslina ne mora zabiti niti jedan pogodak, inače mora
zabiti jedan.
Ako je A+D < B+C, momčad NK Maslina mora zabiti barem X=(B+C)-(A+D)
pogodaka. Međutim, to ne mora biti dovoljno, možda će im biti potreban još
jedan pogodak kako bi nadomjestili manji broj golova u gostima. Dakle, ako je
D+X < B moraju zabiti X+1 pogodak, a inače im je dovoljno X.

Slična razmatranja su potrebna i za NK Draču.

potrebno znanje: if, rastavljanje na slučajeve


kategorija: ad-hoc

Zadatak MOBITEL Autori: Antonio Jurić, Marin Tomić

Zamislimo na trenutak da skakavčev mobitel nije upao u lokvu, zadatak se


tada svodi na simuaciju pisanja jedne riječi na mobitelu s tipkama. Da bismo
spomenutu simulaciju ostvarili, dovoljno je za svako slovo, prolaskom kroz
riječ slijeva nadesno, rješenju na kraj pridodati odgovarajući broj pritisaka
tipke (prema slici iz zadatka) pritom pazeći na razdvajanje pritisaka uzastopnih
slova s iste tipke znakom ‘#’.

Kada smo pronašli rješenje dobiveno gornjim postupkom, dovoljno je svako


pojavljivanje tipke x zamijeniti tipkom y ukoliko se tipka y ponaša kao tipka x.
Ova jednostavna modifikacija rješava skakavčev problem.
Za implementacijske detalje, pogledajte službeno rješenje.

potrebno znanje: petlje, nizovi, stringovi


kategorija: implementacija, ad-hoc

Zadatak UTRKA Autor: Ivan Paljak

Naivni pristup rješavanju ovog problema bio bi sljedeći algoritam:


 
Za svakog natjecatelja s popisa 
ako se ime natjecatelja nalazi na rang listi 
označi natjecatelja 
prekriži natjecatelja s rang liste 
 
Ispiši neoznačenog natjecatelja 
 
Ovakve implementacije vremenske složenosti O(N^2*duljina_riječi)bile su
dovoljne za 50%bodova na zadatku.

Za osvajanje svih bodova valjalo je primijetiti kako će se ime natjecatelja koji


nije uspio završiti utrku pojaviti neparan broj puta u ulazu, dok će se imena
svih ostalih natjecatelja pojaviti paran broj puta.

Razmislimo li malo bolje, vidjet ćemo da analogna tvrdnja vrijedi za svako


slovo u imenu traženog natjecatelja. Primjerice, promatramo li broj
pojavljivanja početnih slova svih natjecatelja, vidjet ćemo kako se sva slova
osim početnog slova traženog natjecatelja pojavljuju paran broj puta.
Spomenuta primjedba vodi nas do sljedeće ideje:

Neka cnt[index][slovo] označava broj pojavljivanja slova slovona poziciji


index. Dovoljno je tada, nakon što smo ispunili matricu, pronaći koje se slovo
pojavljuje neparan broj puta za svaki indeks. Ta slova, počevši s indeksom 0,
čine konačno rješenje. Popunjavanje ove matrice dimenzija 27x21izvedivo je u
O(N*duljina_riječi) što je dovoljno brzo za ograničenja iz zadatka. 

U stilu glavnog lika iz šestog zadatka -- “Možemo li popraviti? Naravno da


možemo!”
Prisjetimo se nekih svojstava binarne operacije xor. Preciznije, bitna su nam
sljedeća svojstva:

1)a xor b = b xor a 
2)a xor a = 0 
3)a xor 0 = a 
 
Kombiniranjem ovih svojstava lagano je zaključiti kako je dovoljno, za svaki
indeks, ispisati xor svih slova iz ulaza koja se pojavljuju na tom indeksu.
Formalni dokaz, po običaju, ostavljamo čitateljici za vježbu.

Implementaciju ovog rješenja, također složenosti O(N*duljina_riječi),


možete vidjeti među službenim rješenjima.  

potrebno znanje: petlje, stringovi, xor


kategorija: ad-hoc

Zadatak STUDENTSKO Autor: Marin Tomić

Promotrimo jedan primjer (8 studenata, timovi od 2 igrača):


 
3 2 1 6 7 5 8 4 
 
Označimo istim brojevima studente koji moraju biti u istom timu:

2 1 1 3 4 3 4 2 
 
Ante može uzeti bilo koji broj iz niza i premjestiti ga na drugo mjesto. Tim
operacijama, u najmanjem broju koraka, mora dobiti niz:

1 1 2 2 3 3 4 4 
 
Pronađimo najdulji podniz elemenata koji su relativno u dobrom poretku u
nizu:

2 1 1 3 4 3 4 2

To je zapravo najdulji neopadajući podniz niza. Sada možemo sve elemente


koji ne pripadaju tom podnizu premjestiti na odgovarajuća mjesta, svaki u
jednoj minuti.

Lako se pokaže da je to rješenje optimalno i to ostavljamo čitateljici za vježbu.


Traženje najduljeg rastućeg podniza je klasičan problem koji se može riješiti u
O(N2) ili O(N lg N) složenosti dinamičkim programiranjem.

Preporučamo vam da pročitate rješenje tog klasičnog problema na ovom linku,


a implementacijske detalje proučite u izvornom kodu.

potrebno znanje: najdulji rastući podniz


kategorija: pohlepni algoritmi, sortiranje
Zadatak BOB Autor: Dominik Gleich

Zadatak nas traži broj pravokutnika kojima su sva polja jednaka. Pokušajmo
prvo riješiti jednostavniju verziju zadatka; postoje samo dva tipa polja: 0 i 1 i
potrebno je prebrojiti broj pravokutnika koji nemaju nula tj. ispunjeni su samo
jedinicama.
Pokušajmo prebrojiti te pravokutnike na način da im fiksiramo donji desni kut.
Također, pokušajmo prebrojavati s lijeva na desno, spustajući se po retcima.
Dodatno, definirajmo a[x][y] kao broj jedinica do prve nule prema vrhu
matrice. (x je vertikalna komponente, y je horizontalna)

Pretpostavimo da računamo rješenje za donji desni kut (x, y).


Neka je (x, z) takav par da vrijedi a[x][z] < a[x][y], da je z < y, te da z je
maksimalan od svih mogućih z-ova, tj. zanima nas prva pozicija lijevo od naše
trenutne pozicije y tako da visina tog stupca bude manja od visine stupca na
trenutnoj poziciji.

Nadalje, potrebno je primijetiti da svaki pravokutnik kojem je desni kraj na


trenutnoj poziciji (trenutni y), a lijevi kraj na poziciji z ili ljevije od nje zapravo
je neki pravokutnik kojemu je desni kraj na poziciji z, produžen do stupca y.
Dakle, broj pravokutnika koji završavaju na y-onu, a prolaze preko z-a, ima
jednako kao i broj pravokutnika koji završavaju na z-u.

Ostaje nam još prebrojiti broj pravokutnika koji imaju lijevi kraj desnije od z-a.
Takvih pravokutnika ima (y - z)*a[x][y] iz razloga što su svi stupci do z-a viši
ili jednaki stupcu na a[x][y], što znači da je svaka visina pravokutnika, bilo
koje širine do širine y-z moguća.

Potrebno je još nekako održavati strukturu koja nam odgovara na pitanje prvi
stupac lijevo, manji od trenutnog stupca. To možemo napraviti koristeći stog ili
neku od naprednijih struktura podataka poput logaritamske ili tournament
stabla.

Koristeći stog to možemo napravit na sljedeći način (pseudokod):


sve dok je stupac na vrhu stoga veći od trenutnog stupca
makni taj stupac sa stoga
y <- stupac koji je ostao na vrhu stoga
ubaci trenutni stupac na vrh stoga
Složenost ovog algoritma na stogu je linearna.
Nakon što smo riješili ovu, jednostavniju, verziju zadatka potrebno je još
proširiti ovo rješenje za zadanu verziju zadatka.
Proširenje je vrlo jednostavno i ostaje na vježbu čitatelju.

potrebno znanje: stog


kategorija: ad-hoc

Zadatak ŠUMA Autor: Mislav Bradač

Rješimo prvo jednostavniju verziju zadatka u kojoj ne postoje dva susjedna


polja u kojima su stabla jednake visine i koja jednako brzo rastu.

Promatrajmo neka dva susjedna polja. Stabla u tim poljima mogu najviše u
jednom trenutku biti jednake visine. Trenutak u kojem stabla u neka dva
susjedna polja postanu jednake visine ćemo zvati događajem.

Događaja ima manje od 4N. Za svaki događaj možemo iskoristiti DFS (ili BFS)
za širenje iz polja u kojima su stabla postale iste visine i brojanje stabala u
komponenti pri tome pazeći da za određeni trenutak ne prođemo više od
jednom po nekom polju.

Taj algoritam ima složenost O(N2) jer ćemo kroz svako polje proći najviše 4
puta (jednom za svaki događaj u koji je uključeno to polje).

U originalnom zadatku neka povezana komponenta stabala može rasti zajedno


(ako imaju iste jednake početne visine i jednaku brzinu rasta). Ako
primijenimo gore opisani algoritam dolazimo do vremenske složenosti O(N4).
Ta složenost se postiže u primjeru u kojoj postoji velika komponenta koja
zajedno raste. Ovaj pristup je bio dovoljno brz za 30% bodova. Iduća ideja
koja bi mogla pasti čitatelju na pamet je sažeti komponentu stabala koje
zajedno rastu u jedan čvor i izgraditi graf u kojem su neka dva čvora povezana
ako su njima pripadajuće komponente susjedne u početnoj matrici. Ovaj
pristup ne mijenja složenost jer može postojati komponenta s mnogo bridova
(reda veličine N2), a tijekom DFS-a za svaki događaj ćemo iterirati po svim
njegovim bridovima. Ovaj pristup uz neke dodatne (nedeterminističke)
optimizacije je nosio 50% bodova.

Rješenje za 100% bodova se temelji na prošlom rješenju, no ne ćemo koristiti


BFS ili DFS nego ćemo koristiti union-find strukturu za obradu događaja.
Union-find struktura će pamtiti roditelja svakog čvora, a korijen svakog
povezanog skupa pamti veličinu njemu pripadajućeg skupa.
Prvo sažmemo povezana stabla koja zajedno rastu u jedan čvor, zatim
izračunamo događaje za svaka dva susjedna čvora. Događaje obrađujemo tako
da spajamo čvorove u union-find strukturi koji u tom trenutku postanu jednake
visine. Tijekom obrade događaja pamtimo sve promjene koje smo napravili u
union-find strukturi kako bismo znali vratiti strukturu kako je izgledala prije
obrade događaja. Nakon obrade događaja vratimo union-find strukturu u
početni izgled. Ovo rješenje ima složenost O(N2 lg N).

Dobro je primijetiti da ne moramo koristiti tipove podataka s pomičnom


točkom tijekom izračunavanja, sortiranja i uspoređivanja događaja. Nepažljivo
rukovanje tipovima podataka s pomičnom točkom je rezultiralo krivim
rješenjem u nekim test primjerima. U službenoj implementaciji rješenja se
može vidjeti kako baratati događajima bez tipova s pomičnom točkom.

potrebno znanje: union-find


kategorija: grafovi

Zadatak NORMA Autor: Ivan Katanić

Zadatak od nas traži da za svaka dva broja Ai B(1 <= A <= B <= N)


izračunamo cijenu podniza [A,B]ulaznog niza Xte dobivene vrijednosti
posumiramo. Zamislimo da pomičemo desnu granicu, B, s lijeva na desno i
održavamo niz rješenja za trenutni B, tako da na poziciji Atog niza, nazovimo
ga niz T, stoji cijena podniza [A,B].

Tada bi algoritam na visokoj razini izgledao ovako:

postavi niz T na 0 
rješenje = 0 
za B od 1 do N 
podnizovi se proširuju s [A,B­1] na [A,B] dodavanjem X[B] 
stoga osvježi vrijednosti u nizu T na pozicijama 1 do B 
dodaj na rješenje T[1] + T[2] + … + T[B] 

Zamislimo da svaki član T[A]niza Tinterno sadržava vrijednosti m, Mi L,


minimalan broj podniza [A,B], maksimalan broj podniza [A,B]te duljinu
podniza [A,B], tim redosljedom. Tada bi vrijednost člana T[A]za koju smo
zainteresirani bila umnožak njegovih internih vrijednosti m, Mi L.

Moramo efikasno riješiti osvježavanje vrijednosti (cijena) u nizu T. Budući da je


vrijednost člana umnožak njegovih internih vrijednosti, pogledajmo kako se
one mijenjaju povećavanjem Bza 1 (pomicanje udesno). Vrijednosti Lsvakog
člana s indeksom manjim ili jednakim Bse povećaju za 1.
Neka je Pm pozicija najdesnijeg člana niza Xkoji je lijevo od Btakav da vrijedi
X[Pm] < X[B]. Vrijednost msvih članova niza Tna pozicijama iz intervala
[1,Pm] će ostati nepromijenjene dok će vrijednost msvih članova niza Tna
pozicijama iz intervala [Pm+1,B]postati upravo X[B].
Slična stvar vrijedi i za najveći element podniza, M:
Neka je PM pozicija najdesnijeg člana niza Xkoji je lijevo od Btakav da vrijedi
X[PM] > X[B]. Vrijednost Msvih članova niza Tna pozicijama [1,PM]će ostati
nepromijenjena dok će vrijednost Msvih članova niza Tna pozicijama [PM+1,B]
postati X[B].

Dakle, nad nizom Tpotrebno je ostvariti strukturu podataka koja će nam


omogućiti sljedeće operacije:
povecaj_L(lo, hi, d_L)- povećaj za d_Lvrijednost Lsvim članovima niza
na pozicijama iz intervala [lo,hi].
postavi_m(lo, hi, novi_m)- postavi na novi_mvrijednost m svim članovima
niza na pozicijama iz intervala [lo,hi].
postavi_M(lo, hi, novi_M)- postavi na novi_Mvrijednost Msvim članovima
niza na pozicijama iz intervala [lo,hi].
sumiraj_mML(lo, hi)- vrati sumu umnožaka vrijednost m, Mi Lsvih članova
niza iz intervala [lo, hi].

Ispostavlja se da se tražene operacije efikasno mogu ostvariti tournament


stablom. U tu svrhu svaki čvor stabla treba sadržavati sljedeće vrijednosti:

len- duljina intervala članova niza koje čvor pokriva, npr. za listove vrijedi
len=1 
sm- suma vrijednosti msvih članova intervala
sM- suma vrijednosti Msvih članova intervala
sL- suma vrijednosti Lsvih članova intervala
smM- suma vrijednosti m*Msvih članova intervala
smL- suma vrijednosti m*Lsvih članova intervala
sML- suma vrijednosti M*Lsvih članova intervala
smML- suma vrijednosti m*M*Lsvih članova intervala

Kako bi izgledalo povećavanje vrijednosti Lsvim članovima intervala koji


pripada čvoru stabla?
Potrebno je prikladno promjeniti svaku od vrijednosti koje čvor nosi, i to na
sljedeći način:
sL = sL + d_L * len 
smL = smL + sm * d_L 
sML = sML + sM * d_L 
smML = smML + smM * d_L.

Pogledajmo kako izgleda postavljanje vrijednosti msvim članovima niza koji


pripadaju čvoru stabla:
sm = novi_m * len 
smM = novi_m * sM 
smL = novi_m * sL 
smML = novi_m * sML.

Te, konačno, postavljanje vrijednosti Msvim članovima niza koji pripadaju


čvoru stabla:
sM = novi_M * len 
smM = novi_M * sm 
smL = novi_M * sL 
smML = novi_M * smL.

Budući da su sve vrijednosti u čvorovima sume, spajanje dva čvora djeteta u


svrhu izračunavanja vrijednosti čvora roditelja je jednostavno zbrajanje
odgovarajuće vrijednosti iz oba čvora.

Priroda spomenutih operacija na stukturi je takva da je potrebno koristiti


tournament stablo s propagacijom, detalji tog proširenja su općeniti i
izostavljeni iz ovog opisa, no mogu se pogledati u priloženom kodu.

Preostaje nam još efikasno pronalaziti najdesniji manji odnosno veći broj od
trenutnog X[B]. To se na jednostavan način ostvaruje korištenjem stoga,
objasnit ćemo ovdje pronalaženje najdesnije manje vrijednosti koja je lijevo od
X[B], a pronalaženje najdesnije veće se ostvaruje na sličan način.
Ako uzmemo u obzir da se Bpomiče s lijeva na desno, od 1 do N, onda zapravo
govorimo o zadnjem članu niza Xkojega smo prošli, a koji je manji od X[B].
Za svaki Bsa vrha stoga ćemo skinuti sve brojeve veće ili jednake X[B]budući
da oni više nikada ne mogu biti nečiji zadnji manji broj (X[B]je manji od njih i
nalazi se nakon njih). Nakon toga na vrhu stoga će biti upravo član niza X
kojega smo tražili, zadnji manji od X[B]. Prije povećanja Bi pomicanja u
desno, stavljamo X[B]na stog. Dani algoritam je linearne složenosti jer se
svaki član niza jednom stavlja i najviše jednom skida sa stoga.

Sve operacije na tournament stablu su složenosti O(log N), a radimo ih O(N)


pa je ukupna složenost rješenja O(N log N).

potrebno znanje: tournament stablo, propagacija, stog


kategorija: strukture podataka

You might also like