Professional Documents
Culture Documents
Zadatak STELLA Autor: Nikola Dmitrović
N = int(input())
kockica = 0
for i in range(4):
zn = N % 10
if zn % 2 == 0:
kockica += zn
N //= 10
print(kockica)
potrebno znanje:
naredba odlučivanja, algoritam određivanja znamenki
kategorija:
adhoc
Zadatak PAULA Autor: Nikola Dmitrović
Rješenje zadatka se svodi na to da za svaki redak ulaza provjerimo je li zbroj
elemenata u njemu između 40 i 50.
N = int(input())
ukupno = 0
for i in range(N):
L = list(map(int, input().split()))
# a, b, c, d, e = map(int, input().split())
# sum = a + b + c + d + e
if sum(L) < 40 or sum(L) > 50:
ukupno += 1
if ukupno == 0:
print("PAULA")
else:
print(ukupno)
potrebno znanje:
naredba odlučivanja, naredba ponavljanja, lista (opcija)
kategorija:
adhoc
Zadatak BELA Autor: Branimir Filipović
Kako bi izračunali ukupan broj bodova u partiji bele, potrebno je pozbrojiti bodove
za svaku kartu u partiji. Za određivanje broja bodova koju pojedina karta nosi
potrebne su nam dvije informacije: da li je karta adut (da li joj je boja jednaka B
),
te koju vrijednost nosi karta. Nakon toga, sve što je potrebno je iščitati iz dobivene
tablice vrijednost te karte. To se jednostavno može napraviti pomoću naredbi
odlučivanja.
potrebno znanje: naredba odlučivanja, naredba ponavljanja, rad sa riječima
(stringovima)
kategorija: adhoc
Zadatak PUTOVANJE Autor: Dominik Gleich
O ovom je zadatku jedino bitno simulirati Mislavovo kretanje i konzumiranje ukoliko
on krene sa svake moguće pozicije i odluči od tamo početi konzumirati plodove.
Kada krene jesti on će pojesti plod ako mu stane u želudac, inače neće i nastavit će
dalje pokušat pojesti plodove. Dakle, potrebno je iz svake pozicije izračunat koliko
će pojesti ako krene jesti od ploda na toj poziciji. Maksimum tih brojeva je rješenje.
Ukupna složenost rješenja iznosi O(n^2).
potrebno znanje: nizovi
kategorija: adhoc
Zadatak PIANINO Autor: Marin Tomić
Neka su s a , …, a
1 N označene odsvirane note. Definiramo niz brojeva b 1, …, b
N na
sljedeći način:
b = 0
1
bi+1 = b + 1 ako je a
i > a
i , i > 1
i1
bi+1 = b 1 ako je a
i < a
i , i > 1
i1
b = b
i+1 ako je a
i = a
i i1, i > 1
Označimo s p itu parcijalnu sumu niza b. Lako je vidjeti da je ita nota koju će
i
Mirka odsvirati upravo p * K + a
i .
1
Ako Mirka točno odsvira itu notu pjesme vrijedi p * K + a
i = a
1 . Ako je p
i = 0, onda
i
točnost ite note uopće ne ovisi o K, a inače će biti točno odsvirana ako je K
jednako (a a
i ) / p
1 (uočimo da kvocijent mora biti nenegativan cijeli broj).
i
Dakle, za svaku notu za koju je p različito od 0 postoji najviše jedan dobar kandidat
i
za K. Sve kandidate možemo ubaciti u niz, sortirati ga, naći koji se najviše puta
pojavljuje te njega odabrati za optimum.
Složenost rješenja je O(N lg N) zbog sortiranja.
potrebno znanje: kombinatorika
kategorija: adhoc, matematika
Zadatak PAROVI Autor: Mislav Balunović
Označimo sa A familiju skupova koji imaju pregradu na mjestu k, a sa X označimo
k
familiju svih mogućih početnih skupova.
n
Tada su rješenje svi skupovi iz X ∖
∪Ai
i = 1
Formula uključivanja i isključivanja nam daje efikasan način za računanje veličine
skupa rješenja. Vrijedi:
n k
k
∪Ai | = ∑(− 1) ∙ | ∩ Ai[j]|
| X ∖
i = 1 j = 1
Kako bismo izračunali kardinalitet potrebnog presjeka trebamo prebrojati koliko
postoji uparivanja takvih da su pregrade postavljene na određenih k mjesta (za
ostala mjesta nam nije bitno postoje li pregrade na njima).
t
Taj broj je jednak 2 gdje je t ukupan broj parova koji ne “preskaču” niti jednu
ogradu.
N
Vremenska složenost ovog rješenja je O(2 * N).
Za detalje implementacije pogledajte službeno rješenje.
Napomena: Postoji i rješenje koje koristi dinamičko programiranje, a ostavljamo ga
čitatelju za vježbu.
potrebno znanje: formula uključivanja i iskuljučivanja, matematika
kategorija: matematika
Zadatak KRUMPIRKO Autor: Dominik Gleich
Rješenje koje donosi 30% bodova trivijalno je i implementira točno ono što zadatak
traži: od svih odabira rasporeda vreća krumpira u dućane kojih ima O(2^n),
odaberi onaj s najmanjim umnoškom prosječnih cijena kod kojeg je barem jedna
polovica veličine
L
. Složenost tog rješenja je O(2^n * n). Pokušajmo sada riješiti
zadatak za sve bodove. Označimo li ukupnu cijenu krumpira u prvom dućanu s c1 i
ukupan broj krumpira s w1 , te analogno za drugi dučan s c2
i
w2
, umnožak
prosjećnih cijena jednak je c*c/
w /
w
1 2 1 2. S obzirom da je suma cijena i suma broja
krumpira konstantna možemo ovaj izraz zapisati i kao c *(
1 c
c)/(
1 w *
1 (
ww )).
1
Ukoliko fiksiramo neki w možemo primijetiti da je ovaj izraz minimalan kad je
1 c1
također minimalan. Sada je naš zadatak za svaki w1
pronaći najmanji c1
takav da je
u prvom dućanu točno L ili
N L vreća krumpira. Najmanji takav c tražimo
1
dinamičkim programiranjem, neka je f
(
n, w, l)
najmanja cijena odabira točno l
vreća krumpira u prvih n vreća krumpira tako da u odabranim vrećama imamo
točno w krumpira. Relaciju za tu dinamiku ostavljamo na vježbu čitatelju, za ostale
detalje pogledajte službeno rješenje. Ukupna složenost rješenja iznosi O( wn^2 ).
potrebno znanje: dinamičko programiranje
kategorija: matematika
Zadatak SAN Autor: Marin Tomić
Neka je tab[y] broj pojavljivanja broja y u tablici. Možemo ga (neefikasno)
izračunati sljedećim algoritmom za sve y od 1 do N:
za x od 1 do N:
tab[x] = tab[x] + 1
tab[x + rev(x)] = tab[x + rev(x)] + tab[x]
10
Ovaj algoritam je linearan, no N je do 10 pa nije dovoljno efikasan. Ključno je
uočiti da brojeva za koje je tab[y] > 1 ima vrlo malo. Označimo s cnt[y] broj
različitih brojeva x takvih da je x + rev(x) = y. Uočimo da je cnt[y] > 0 ako i samo
ako je tab[y] > 1. Označimo sa S niz brojeva koji se sastoji od svih brojeva za koje
je cnt[y] > 0 sortiranih uzlazno. Vrijednosti tab[y] za te brojeve možemo izračunati
sljedećim algoritmom:
za sve x u S:
tab[x] = tab[x] + cnt[x]
tab[x + rev(x)] = tab[x + rev(x)] + tab[x]
U ovom algoritmu imamo |S| iteracija petlje. Ključno je uočiti da brojeva u skupu S
ima relativno malo (samo nekoliko milijuna) pa je gornji algoritam dovoljno
efikasan da bi izračunali vrijednosti tab[y] za sve y za koje je to veće od 1. Za sve
ostale y vrijedi tab[y] = 1 pa sada zapravo imamo izračunate vrijednosti tab[y] za
sve y što nam omogućava da efikasno odgovaramo na upite (koristeći parcijalne
sume niza tab). Uočimo da su indeksi u nizu tab vrlo veliki, no ne treba nam cijeli
niz pa ćemo ga zapravo držati u mapi.
Preostaje izračunati vrijednosti cnt[y] za sve brojeve. Rekurzijom ćemo naći sve
brojeve y i vrijednosti cnt[y] za sve y za koje je to veće od 0. Pogledajmo što se
dogodi kada zbrojimo neki 6znamenkasti broj s njim samim okrenutim naopako:
a1 a2 a3 a4 a5 a6
+ a6 a5 a4 a3 a2 a1
Ovdje su c0, …, c5 0 ili 1 i označavaju znamenke prijenosa, a b1 je (a1+a6) modulo
10, b2 je (a2+a5) modulo 10 i b3 je (a3+a4) modulo 10.
Vrijednosti cnt[y] bi mogli odrediti tako da fiksiramo znamenke a1, …, a6 na sve
moguće načine, no za to postoji mnogo kombinacija. Drugi pristup bi bio da
odredimo b1, b2 i b3, te c0, …, c5 na sve moguće načine (time je zbroj jedinstveno
određen) i izračunamo koliko različitih odabira a1, …, a6 daje točno te b1, b2 i b3 i
c0, …, c5. Kako to napraviti? Koristit ćemo rekurzivnu funkciju gen koja ima 4
parametara čije je značenje opisano u tablici:
pos znači da trenutno određujemo b
pos
num trenutno određeni dio sume a1...a6 + a6...a1
Pseudo kod za funkciju gen:
gen(pos, c1, c2, num):
ako je pos = 4:
(odredili smo cijelu sumu i broj načina da ju dobijemo)
ako je c1 != c2 izađi iz funkcije
(c1 i c2 moraju biti jednaki jer oba predstavljaju c3)
u mapi povećaj cnt[num] za 1 i izađi iz funkcije
za parove znamenki (x1, x2):
(x1 i x2 određuju b
pos,
određujemo znamenke pos i 6pos+1 u num)
ako je c1 = 1 a x1+x2 < 10 preskoči
ako je c1 = 0 a x1+x2 >= 10 preskoči
bb = (x1 + x2) % 10
nnum = num
postavi znamenku 6pos+1 u nnum na bb + c2
postavi znamenku pos u nnum na bb + 1 i pozovi
gen(pos+1, 1, x1+x2 >= 10, nnum)
(c1 = 1 označava da tražimo znamenku prijenosa)
postavi znamenku pos u nnum na bb i pozovi
gen(pos+1, 0, x1+x2 >= 10, nnum)
(c1 = 0 označava da zabranjujemo prijenos)
Gornji pristup može se poopćiti za proizvoljan broj znamenaka. Gornja rekurzija za
L/2
neku duljinu broja L radi otprilike 81 što je presporo da bi osvojilo sve bodove.
Potrebno je uočiti da ne moramo iterirati po svim parovima znamenaka, već je
dovoljno iterirati po svim mogućim zbrojevima i za svaki zbroj znati na koliko
L/2
načina ga možemo ostvariti. Tada radimo otprilike 19 operacija što je dovoljno
brzo za sve bodove. Detalje ostavljamo čitatelju, no mogu se naći i u izvornom
kodu.
potrebno znanje: rekurzija, mapa
kategorija:
dinamika, matematika