Na ovoj stranici izdvojeni su zadaci sa različitih okružnih takmičenja za osnovne škole.
Svaki zadatak ima odvojene postavke, ulaz, izlaz i primere, a uz njega su detaljno uputstvo i C++ rešenje
koje možeš prikazati kada pokušaš da ga rešiš sam. Na kraju strane nalazi se kviz.
Tri programera – A, B i C (tim redom) prijavila su se na konkurs za izbor pobedničke video igrice. Žiri svakoj igrici daje dve ocene – ocenu za dizajn (prva ocena) i ocenu za funkcionalnost (druga ocena). Napišite program KONKURS koji određuje koji je programer osvojio prvo mesto.
Pobednik se bira na sledeći način: za svaku igricu se saberu obe ocene i pobeđuje programer čija igrica ima najveći zbir. Ako više programera ima isti najveći zbir, pobeđuje onaj koji je dobio veću ocenu za dizajn. Ako i tada ostane izjednačenje, pobeđuje onaj koji je igricu prvi predstavio žiriju (redosled predstavljanja je A, B, C).
Ulaz
Na standardnom ulazu, u jednom redu, zadaju se tri para prirodnih brojeva (nijedan nije veći od 1000) razdvojenih razmacima. Prvi par su ocene prvog programera, drugi par ocene drugog, a treći par ocene trećeg programera.
Izlaz
Ispisati jedno od slova A, B ili C, u zavisnosti od toga koji je programer pobedio.
Primer 1
Ulaz
5 6 7 4 5 3
Izlaz
B
Objašnjenje
Zbirovi su 11, 11 i 8. Programeri A i B imaju isti zbir, ali B ima veću ocenu za dizajn (7 prema 5).
Primer 2
Ulaz
14 18 17 7 18 7
Izlaz
A
Objašnjenje
Zbirovi su 14 + 18 = 32, 17 + 7 = 24 i 18 + 7 = 25, pa je pobednik A. (U originalnoj zbirci uz ovaj ulaz stoji izlaz B, što je očigledna greška: prema pravilima pobeđuje A.)
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Zbirovi i ocene za dizajn
Za svakog programera čuvamo ocenu za dizajn i zbir obe ocene. Dovoljna su dva niza od po tri elementa.
2. Traženje pobednika
Pretpostavimo da vodi programer A. Zatim redom proveravamo B i C: novi programer preuzima vođstvo samo ako ima strogo veći zbir, ili isti zbir i strogo veću ocenu za dizajn.
3. Zašto ovo rešava i treći uslov
Pošto vođstvo menjamo samo kod strogo boljeg rezultata, pri potpunoj jednakosti ostaje raniji programer – a to je upravo onaj koji je prvi predstavio igricu.
4. Ispis
Indeks pobednika (0, 1 ili 2) pretvaramo u slovo izrazom (char)('A' + indeks).
C++ rešenje
#include <iostream>
using namespace std;
int main() {
int dizajn[3], zbir[3];
for (int i = 0; i < 3; i++) {
int funkcionalnost;
cin >> dizajn[i] >> funkcionalnost;
zbir[i] = dizajn[i] + funkcionalnost;
}
int pobednik = 0; // za sada vodi programer A
for (int i = 1; i < 3; i++) {
if (zbir[i] > zbir[pobednik] ||
(zbir[i] == zbir[pobednik] && dizajn[i] > dizajn[pobednik])) {
pobednik = i;
}
}
cout << (char)('A' + pobednik) << endl;
return 0;
}
Objašnjenje: Starije rešenje je tri slučaja zbirova proveravalo ručno i nije pokrivalo izjednačenja po oceni za dizajn niti po redosledu predstavljanja (za neke ulaze nije ispisivalo ništa). Ovde su sva tri kriterijuma obuhvaćena jednim poređenjem.
Kažemo da je neki broj prelep ako su mu sve cifre međusobno različite. Napišite program LEPOTA koji pronalazi koliko ima prelepih brojeva u datom segmentu [m, n].
Ulaz
U prvoj liniji standardnog ulaza data su dva cela broja m i n razdvojena razmakom.
Ograničenja: 0 ≤ m ≤ n ≤ 10 000 000.
Izlaz
Na standardnom izlazu ispisati jedan ceo broj – broj prelepih brojeva u segmentu.
Primer
Ulaz
90 91
Izlaz
2
Objašnjenje
Oba broja, 90 i 91, imaju različite cifre.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Pomoćna funkcija
Napravimo funkciju prelep(x) koja vraća true ako su sve cifre broja x različite.
2. Provera cifara
Cifre izdvajamo sa x % 10 i skraćujemo broj sa x /= 10. Pomoću niza videna[10] pamtimo koje smo cifre već srele; ako se neka cifra javi drugi put, broj nije prelep.
3. Broj 0
Za x = 0 petlja mora da se izvrši bar jednom, zato koristimo do { ... } while (x > 0). Broj 0 ima jednu cifru, pa je prelep.
4. Brojanje
Petljom for prođemo kroz sve brojeve od m do n i brojimo one za koje funkcija vrati true. Za najviše 10 miliona brojeva, sa najviše 8 cifara, to je dovoljno brzo.
C++ rešenje
#include <iostream>
using namespace std;
// Vraća true ako su sve cifre broja x međusobno različite
bool prelep(int x) {
bool videna[10] = {false};
do {
int cifra = x % 10;
if (videna[cifra]) {
return false;
}
videna[cifra] = true;
x /= 10;
} while (x > 0);
return true;
}
int main() {
int m, n;
cin >> m >> n;
int brojac = 0;
for (int i = m; i <= n; i++) {
if (prelep(i)) {
brojac++;
}
}
cout << brojac << endl;
return 0;
}
Objašnjenje: Niz videna je znatno jednostavniji od poređenja svake cifre sa svakom, jer svaku cifru proveravamo samo jednom.
Pet programera tokom jednog dana boravi u firmi. Za svakog od njih poznati su sat i minut dolaska i sat i minut odlaska. Napiši program koji određuje da li je moguće da organizuju zajednički sastanak (na kome moraju biti prisutni svi) i, ako je moguće, koliko je najduže trajanje takvog sastanka (u satima i minutima).
Ulaz
Svaki od pet redova standardnog ulaza sadrži četiri cela broja razdvojena razmacima: sat i minut dolaska, sat i minut odlaska jednog programera.
Izlaz
Na standardni izlaz ispisati trajanje sastanka tako da su broj sati i broj minuta razdvojeni jednim razmakom, ili reč ne ako sastanak nije moguće održati.
Transportna kompanija uspostavlja brodske vožnje između matične luke i nekoliko (najviše 5) drugih lučkih gradova. Na svakoj liniji cirkuliše tačno jedan brod: kreće iz matične luke, prevozi putnike do svog odredišta, a zatim druge putnike vraća nazad u matičnu luku.
Svi brodovi iz matične luke kreću istovremeno, a za svaki je poznato koliko mu je dana potrebno da otputuje i da se vrati u matičnu luku (pretpostavlja se da se svaki transport i povratak obavlja unutar jedne kalendarske godine). Napiši program koji određuje posle koliko dana će se svi brodovi ponovo susresti u matičnoj luci. Obrati pažnju na to da, iako rešenje uvek postoji, ono može biti veoma veliki broj.
Ulaz
Sa standardnog ulaza unosi se broj linija (najviše 5), a zatim, za svaku liniju, broj dana potrebnih da brod otputuje i da se vrati.
Izlaz
Na standardni izlaz ispisati traženi broj dana.
Primer
Ulaz
3
15
24
60
Izlaz
120
Objašnjenje
Brodovi su zajedno u luci posle NZS(15, 24, 60) = 120 dana.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Šta se traži
Brod sa kružnom linijom od t dana u luci je u danima t, 2t, 3t, .... Svi brodovi su zajedno u luci u prvom danu koji je deljiv svim trajanjima – to je njihov najmanji zajednički sadržalac (NZS).
2. NZS preko NZD
Za dva broja važi NZS(a, b) = a / NZD(a, b) * b. NZD računamo Euklidovim algoritmom: dok je b != 0, zamenjujemo (a, b) parom (b, a % b).
3. Više brojeva
NZS više brojeva računamo postepeno: krenemo od 1 i svaki učitani broj „ugradimo“ u dotadašnji rezultat.
4. Tip podataka
Rezultat može biti mnogo veći od najvećeg ulaznog broja (npr. za brojeve oko 360 i do pet brodova prelazi milijardu), pa koristimo long long. Deljenje radimo pre množenja da bi međurezultat bio što manji.
C++ rešenje
#include <iostream>
using namespace std;
long long nzd(long long a, long long b) {
while (b != 0) {
long long ostatak = a % b;
a = b;
b = ostatak;
}
return a;
}
int main() {
int n;
cin >> n;
long long nzs = 1;
for (int i = 0; i < n; i++) {
long long dani;
cin >> dani;
nzs = nzs / nzd(nzs, dani) * dani; // NZS(nzs, dani)
}
cout << nzs << endl;
return 0;
}
Napiši program koji izračunava i ispisuje količnik prirodnih brojeva m i n (manjih od milion) sa datim brojem decimala k (1 ≤ k ≤ 1000). Ne vršiti zaokruživanje rezultata – samo odseći decimale iza poslednje tražene. Rezultat prikazati sa decimalnim zarezom (ne decimalnom tačkom).
Ulaz
Sa standardnog ulaza redom se učitavaju k, m i n (svaki u posebnom redu).
Izlaz
Ispisati količnik m / n sa tačno k decimala, sa decimalnim zarezom.
Primer 1
Ulaz
20
1
7
Izlaz
0,14285714285714285714
Primer 2
Ulaz
7
1
2
Izlaz
0,5000000
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Zašto ne realni brojevi
Tip double pamti oko 15–16 cifara, a traži se i do 1000 decimala. Zato decimale računamo „pisanim deljenjem“ – cifru po cifru, samo sa celim brojevima.
2. Celobrojni deo
Ispišemo m / n (celobrojno deljenje), a zatim zarez. Preostaje ostatak ostatak = m % n.
3. Svaka sledeća decimala
Ostatak pomnožimo sa 10 (kao kad „spustimo nulu“). Sledeća decimala je ostatak / n, a novi ostatak ostatak % n. Ovo ponavljamo k puta.
#include <iostream>
using namespace std;
int main() {
int k, m, n;
cin >> k >> m >> n;
cout << m / n << ","; // celobrojni deo količnika
int ostatak = m % n;
for (int i = 0; i < k; i++) {
ostatak *= 10;
cout << ostatak / n; // sledeća decimala
ostatak %= n;
}
cout << endl;
return 0;
}
Objašnjenje: Odsecanje (a ne zaokruživanje) dolazi „samo od sebe“, jer ispisujemo tačno k cifara i ne gledamo šta bi bilo sledeće.
Policija koja pokušava da uhvati hakera uspela je da dođe do nekih poruka koje hakeri razmenjuju među sobom. Svaku poruku čini jedan broj. Stručnjaci za šifrovanje došli su do zaključka da broj predstavlja niz šifara za pristup nekim računarima. Svaka šifra sadrži samo cifre od 0 do 5, kraj šifre označava cifra 6 ili kraj broja, a cifre 7, 8 i 9 koriste se za maskiranje i treba ih ignorisati. Na ovaj način hakeri u jednom broju mogu da pošalju i po nekoliko šifara, pri čemu broj 0 ne može biti šifra.
Napisati program koji za uneti broj K ispisuje šifre (bez obzira na redosled) koje su u njemu skrivene i koliko se šifara u tom broju nalazi.
Ulaz
Sa standardnog ulaza učitava se broj K.
Izlaz
U prvom redu ispisati šifre (reč Sifre su:, a zatim šifre razdvojene razmacima), a u drugom redu broj poslatih šifara.
Primer
Ulaz
23675
Izlaz
Sifre su: 5 23
Poslate su 2 sifre
Objašnjenje
Cifre 2 i 3 čine jednu šifru, cifra 6 je završava, cifra 7 se ignoriše, a cifra 5 je druga šifra.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Broj kao niska
Broj K učitamo kao nisku (string) i prolazimo kroz njene znakove, jedan po jedan.
2. Pravila za svaku cifru
Cifre 0–5 dodajemo trenutnoj šifri; cifra 6 završava šifru; cifre 7, 8 i 9 preskačemo.
3. Kraj broja
Kraj broja takođe završava šifru. Najlakše je da na nisku dodamo još jednu šesticu pa da se poslednja šifra završi na isti način kao i ostale.
4. Šifra mora da ima smisla
Prazna šifra (npr. dve šestice zaredom) se ne broji. Šifra sastavljena samo od nula predstavlja broj 0, što ne može biti šifra, pa se ni ona ne broji.
5. Ispis
Šifre čuvamo u vektoru. Pošto redosled nije bitan, ispisujemo ih od poslednje ka prvoj da bi izlaz odgovarao primeru (5 23).
C++ rešenje
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
string k;
cin >> k;
vector<string> sifre;
string trenutna = "";
for (char c : k + "6") { // dodatna šestica zatvara poslednju šifru
if (c >= '0' && c <= '5') {
trenutna += c;
} else if (c == '6') {
// šifra se završava; broj 0 ne može biti šifra
bool samoNule = true;
for (char x : trenutna) {
if (x != '0') samoNule = false;
}
if (!trenutna.empty() && !samoNule) {
sifre.push_back(trenutna);
}
trenutna = "";
}
// cifre 7, 8 i 9 se ignorišu
}
cout << "Sifre su:";
for (int i = (int)sifre.size() - 1; i >= 0; i--) { // redosled nije bitan
cout << " " << sifre[i];
}
cout << endl;
cout << "Poslate su " << sifre.size() << " sifre" << endl;
return 0;
}
Objašnjenje: Pretpostavka: šifra koja počinje nulom (npr. 05) ispisuje se onako kako je zapisana. Zadatak ne precizira kako se takvi slučajevi tretiraju.
Ostala okružna takmičenja – kombinovano
Zadaci sa okružnih takmičenja iz 2009. i 2018. godine (link ka sajtu dms.rs dat je na početku strane).
Na velikom turniru P.O.S.O.T. u igranju kompjuterskih igrica postoje ekipna takmičenja u kojima dve ekipe igraju jedna protiv druge. U prvom kolu u grupi O.S. igrale su tri ekipe čije su oznake bili brojevi 1, 2 i 3. Prvu rundu odigrale su ekipe 1 i 2 i zabeleženi su njihovi poeni (za ekipu 1 kao R11, a za ekipu 2 kao R12). U drugoj rundi igrale su ekipe 1 i 3 (poeni R21 i R23), a potom ekipe 2 i 3 (poeni R32 i R33).
U odigranoj rundi pobeđuje ekipa koja ima više poena. Ukoliko u nekoj rundi ekipe imaju izjednačen broj poena, ne računa se pobeda nijednoj ekipi. Nakon odigrane sve tri runde određuje se pobednik kola: to je ekipa sa najvećim brojem pobeda. Ukoliko dve ekipe imaju jednak broj pobeda, koji je veći od broja pobeda treće ekipe, ili ukoliko su sve tri ekipe izjednačene, igraju se dodatne partije koje nose oznaku DP.
Napisati program GRUPAOS u kome se unose redom vrednosti R11, R12, R21, R23, R32 i R33, a zatim se određuje i ispisuje koja je ekipa pobednik ili se ispisuje da se igraju dodatne partije (DP).
Ulaz
U jednom redu unose se redom brojevi R11, R12, R21, R23, R32 i R33.
Izlaz
Ispisati oznaku ekipe pobednika (1, 2 ili 3) ili DP.
Primer 1
Ulaz
56 254 104 198 156 148
Izlaz
2
Objašnjenje
R11 = 56, R12 = 254, R21 = 104, R23 = 198, R32 = 156, R33 = 148. Ekipa 2 je pobedila dvaput, ekipa 3 jednom, ekipa 1 nijednom.
Primer 2
Ulaz
156 154 104 104 256 137
Izlaz
DP
Objašnjenje
Ekipa 1 je pobedila u prvoj rundi, druga runda je nerešena, a ekipa 2 je pobedila u trećoj. Ekipe 1 i 2 imaju po jednu pobedu, pa se igra DP.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Brojači pobeda
Za svaku ekipu uvodimo brojač pobeda i postavljamo ga na 0.
2. Tri runde
Za svaku rundu uporedimo poene dve ekipe: više poena znači da pobedniku povećamo brojač za 1, a pri jednakosti ne radimo ništa.
3. Pobednik
Ako neka ekipa ima strogo više pobeda od obe ostale, ona je pobednik. U svim ostalim slučajevima (dve ekipe izjednačene na vrhu ili sve tri izjednačene) ispisujemo DP.
C++ rešenje
#include <iostream>
using namespace std;
int main() {
int R11, R12, R21, R23, R32, R33;
cin >> R11 >> R12 >> R21 >> R23 >> R32 >> R33;
int p1 = 0, p2 = 0, p3 = 0; // broj pobeda svake ekipe
// runda 1: ekipe 1 i 2
if (R11 > R12) p1++;
else if (R11 < R12) p2++;
// runda 2: ekipe 1 i 3
if (R21 > R23) p1++;
else if (R21 < R23) p3++;
// runda 3: ekipe 2 i 3
if (R32 > R33) p2++;
else if (R32 < R33) p3++;
if (p1 > p2 && p1 > p3) cout << 1 << endl;
else if (p2 > p1 && p2 > p3) cout << 2 << endl;
else if (p3 > p1 && p3 > p2) cout << 3 << endl;
else cout << "DP" << endl;
return 0;
}
Objašnjenje: Starije rešenje bilo je tačno; ovde je samo sređeno i dopunjeno komentarima.
Žarko u jednoj od igara koju igra na turniru P.O.S.O.T. treba svojim likom, koji vodi u igrici, da prođe kroz sobu sa senzorima. Senzori su postavljeni na podu sobe u N paralelnih linija po širini sobe. Prva linija, koja je najbliža Žarkovom liku, ima samo jedan senzor, i to tačno na sredini sobe. Druga linija ima tri senzora, pri čemu se srednji nalazi tačno iza senzora u prvoj liniji. Treća linija ima 5 senzora, pri čemu su središnja tri tačno iza senzora u drugoj liniji, a preostala dva su jedan sa jedne, a drugi sa druge strane.
Svaka naredna linija ima po dva senzora više, tako što se u odnosu na prethodnu liniju dodaje po jedan sa leve i desne strane. Rastojanje između dva susedna senzora na svakoj liniji je jednako i iznosi R centimetara. Ovako postavljeni senzori formiraju trougao. Dimenzije sobe su dovoljno velike da stanu svi predviđeni senzori.
Žarkov lik u igrici mora da prođe pravo po sredini sobe na drugu stranu, pri čemu će aktivirati sve senzore preko kojih pređe. Ako Žarko zna da je širina njegovog lika S centimetara, potrebno mu je da izračuna koliko će senzora njegov lik aktivirati. Napisati program SENZORI koji za unete vrednosti N, R i S određuje broj aktiviranih senzora.
Slika 1: Okružno 2009: zadatak „Senzori“
Ulaz
U jednom redu unose se broj linija N, razmak između senzora R i širina lika S (R i S su realni brojevi).
Izlaz
Ispisati broj aktiviranih senzora.
Primer
Ulaz
5 1.1 5.4
Izlaz
19
Objašnjenje
Senzora po linijama ima 1, 3, 5, 7 i 9, ali lik širine 5,4 cm pokriva samo senzore na rastojanju najviše 2,7 cm od sredine, a to su ona dva sa svake strane (na 1,1 i 2,2 cm). Dakle: 1 + 3 + 5 + 5 + 5 = 19.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Koji senzori su u liniji
Neka je sredina sobe u nuli. U liniji sa rednim brojem i (počevši od 0) senzori su na rastojanjima 0, ±R, ±2R, ..., ±i·R od sredine, pa je tu 2i + 1 senzora.
2. Šta lik pokriva
Lik širine S pokriva deo poda od −S/2 do S/2. Senzor na rastojanju k·R je aktiviran ako je k·R ≤ S/2, odnosno 2·k·R ≤ S.
3. Najdalji aktivirani senzor
Nađemo najveće k za koje je 2·k·R ≤ S (petljom: povećavamo k dok uslov važi). Dalji senzori nikada nisu aktivirani, ma koliko linija bilo.
4. Zbir po linijama
U liniji i aktivirano je 2·min(i, k) + 1 senzora. Saberemo to za i od 0 do N − 1.
5. Realni brojevi
Poređenje realnih brojeva može da pogreši zbog zaokruživanja, pa uz S dodajemo mali dodatak 1e-9. Pretpostavka je da senzor koji lik samo dodiruje ivicom računamo kao aktiviran.
C++ rešenje
#include <iostream>
using namespace std;
int main() {
int n;
double r, s;
cin >> n >> r >> s;
// Koliko je senzora na svakoj strani od sredine aktivirano (najviše):
// senzor na k-tom mestu od sredine je udaljen k*r od sredine,
// pa ga lik širine s dodiruje ako je k*r <= s/2.
int k = 0;
while ((k + 1) * 2 * r <= s + 1e-9) {
k++;
}
int ukupno = 0;
for (int i = 0; i < n; i++) { // i = broj senzora levo od sredine u ovoj liniji
int sa_svake_strane = (i < k) ? i : k;
ukupno += 2 * sa_svake_strane + 1;
}
cout << ukupno << endl;
return 0;
}
Objašnjenje: Provera na primeru: R = 1.1, S = 5.4 daje k = 2 (jer je 2·2·1.1 = 4.4 ≤ 5.4, a 2·3·1.1 = 6.6 > 5.4), pa po linijama imamo 1, 3, 5, 5, 5 senzora.
Zbir unutrašnjih uglova svakog trougla je 180 stepeni. Trougao je oštrougli ako su mu sva tri ugla oštra (manja od 90 stepeni), pravougli ako mu je jedan ugao prav (jednak 90 stepeni), a tupougli ako mu je jedan ugao tup (veći od 90 stepeni). Napiši program koji učitava veličine dva ugla trougla u stepenima (celi brojevi, svaki u posebnom redu), određuje da li je taj trougao oštrougli, pravougli ili tupougli i ispisuje odgovarajući tekst (latinicom).
Ulaz
U dva reda unose se celi brojevi – veličine dva ugla trougla u stepenima.
Izlaz
Ispisati jednu od reči ostrougli, pravougli ili tupougli (kao u primerima, bez dijakritika).
Primer 1
Ulaz
30
60
Izlaz
pravougli
Objašnjenje
Treći ugao je 180 − 30 − 60 = 90.
Primer 2
Ulaz
18
18
Izlaz
tupougli
Objašnjenje
Treći ugao je 180 − 18 − 18 = 144.
Primer 3
Ulaz
75
60
Izlaz
ostrougli
Objašnjenje
Treći ugao je 45, pa su sva tri ugla oštra.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Treći ugao
Zbir uglova je 180°, pa je treći ugao 180 − a − b.
2. Redosled provera
Prvo proveravamo da li je neki ugao jednak 90° (pravougli). Zatim da li je neki veći od 90° (tupougli). Ako nijedno ne važi, trougao je oštrougli.
3. Pažnja
Proveru ne radimo samo za unete uglove – i treći ugao može biti prav ili tup (primer 1 i 2).
C++ rešenje
#include <iostream>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
int c = 180 - a - b; // treći ugao
if (a == 90 || b == 90 || c == 90) {
cout << "pravougli" << endl;
} else if (a > 90 || b > 90 || c > 90) {
cout << "tupougli" << endl;
} else {
cout << "ostrougli" << endl;
}
return 0;
}
Objašnjenje: Trougao ne može imati dva ugla koja nisu oštra, pa je redosled provera nebitan, ali je provera sva tri ugla obavezna.
Mirko je mali programer koji pokušava da isprogramira igricu iks-oks. Blizu je da završi, ali mu je potrebna mala pomoć. Smislio je da korisnik mišem određuje kvadrat u koji će se njegov simbol upisati. Polje za igru sastoji se od 9 kvadrata (raspoređenih u tri vrste i tri kolone) i svaki kvadrat je dimenzije 100 puta 100 piksela (polje je dimenzije 300 puta 300 piksela).
Poznat je položaj piksela na koji je kliknuto mišem. Potrebno je odrediti redni broj kvadrata u kojem se taj piksel nalazi. Položaj piksela određen je rednim brojevima (koordinatama) tog piksela po horizontali i po vertikali, računajući od donjeg levog ugla polja (pikseli se broje od 1 do 300). Kvadrati se broje od 1 do 9, vrstu po vrstu, počevši od donjeg levog ugla polja naviše, kako je prikazano na slici.
Slika 2: Numeracija kvadrata u zadatku Iks-oks
Ulaz
U jednom redu unose se dva cela broja (od 1 do 300): koordinata piksela po horizontali i koordinata po vertikali.
Izlaz
Ispisati redni broj kvadrata (od 1 do 9) u kome se nalazi taj piksel.
Primer 1
Ulaz
1 1
Izlaz
1
Primer 2
Ulaz
120 280
Izlaz
8
Primer 3
Ulaz
100 201
Izlaz
7
Primer 4
Ulaz
101 200
Izlaz
5
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Kolona i vrsta
Svaki kvadrat ima stranicu 100 piksela. Pikseli 1–100 su u prvoj koloni, 101–200 u drugoj, 201–300 u trećoj. Pošto se pikseli broje od 1, od koordinate oduzimamo 1: kolona = (x − 1) / 100 daje 0, 1 ili 2.
2. Zašto oduzimanje
Bez oduzimanja piksel 100 bi dao 100 / 100 = 1, tj. pogrešnu kolonu. Sa oduzimanjem je (100 − 1) / 100 = 0, što je tačno.
3. Isto za vrstu
vrsta = (y − 1) / 100, pri čemu se vrste broje odozdo naviše.
4. Redni broj kvadrata
Pre kvadrata u datoj vrsti nalazi se vrsta punih vrsta od po 3 kvadrata, pa je traženi broj vrsta * 3 + kolona + 1.
C++ rešenje
#include <iostream>
using namespace std;
int main() {
int x, y;
cin >> x >> y;
int kolona = (x - 1) / 100; // 0, 1 ili 2 (sa leva na desno)
int vrsta = (y - 1) / 100; // 0, 1 ili 2 (odozdo naviše)
cout << vrsta * 3 + kolona + 1 << endl;
return 0;
}
Objašnjenje: Starije uputstvo je pogrešno navodilo deljenje sa 30; ispravno je deljenje sa 100 (strana kvadrata), uz oduzimanje 1 od koordinate. Provera: piksel (100, 201) daje kolonu 0 i vrstu 2, dakle kvadrat 7.
Na velikom turniru P.O.S.O.T. u igranju kompjuterskih igrica Žarko je odigrao četiri partije. Nakon završenih partija zaključio je da mu je lakše da prati promenu rezultata između dve partije nego tačan broj bodova. Tako je zapamtio da je:
u drugoj partiji imao tačno 1042 poena više nego u prvoj,
u trećoj partiji imao koliko u prvoj i drugoj zajedno,
u četvrtoj partiji duplo manje nego u trećoj.
Nakon završetka znao je tačan broj poena koje je ostvario u četvrtoj partiji. Napisati program ZARKO kojim se za uneti broj poena C osvojenih u četvrtoj partiji izračunava koliko je Žarko osvojio poena u prvoj partiji.
Ulaz
Sa standardnog ulaza učitava se broj C – broj poena u četvrtoj partiji.
Izlaz
Ispisati broj poena u prvoj partiji.
Primer
Ulaz
2845
Izlaz
2324
Objašnjenje
Prva partija: 2324, druga: 3366, treća: 5690, četvrta: 2845.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Označimo nepoznatu
Neka je p broj poena u prvoj partiji.
2. Ostale partije preko p
Druga: p + 1042. Treća: p + (p + 1042) = 2p + 1042. Četvrta: (2p + 1042) / 2 = p + 521.
3. Rešenje
Dobili smo C = p + 521, odnosno p = C − 521. Program učita C i ispiše C − 521.
C++ rešenje
#include <iostream>
using namespace std;
int main() {
int c;
cin >> c;
// Neka je p broj poena u prvoj partiji:
// druga partija: p + 1042
// treća partija: p + (p + 1042) = 2p + 1042
// četvrta partija: (2p + 1042) / 2 = p + 521
// Dakle, c = p + 521, odnosno p = c - 521.
cout << c - 521 << endl;
return 0;
}
Objašnjenje: Provera: za C = 2845 je p = 2324; tada su druga, treća i četvrta partija 3366, 5690 i 2845, što odgovara uslovima zadatka.
Putujući od Agrada do Begrada, Maja prolazi pored četiri putokaza (nije obavezno tim redom kojim su prikazani na ulazu). Putokaz sa rednim brojem i opisan je sa dva broja: ai i bi – to znači da je taj putokaz udaljen ai kilometara od Agrada i bi kilometara od Begrada.
Međutim, jedan putokaz je netačan. Odrediti koji.
Ulaz
U svakom od četiri reda standardnog ulaza nalaze se dva broja ai i bi. Maja ne voli dugo da putuje, pa su svi brojevi na ulazu manji od 109.
Izlaz
Na standardni izlaz ispisati tačno jedan broj – redni broj putokaza koji je netačan.
Primer
Ulaz
2 9
8 3
9 4
5 6
Izlaz
3
Objašnjenje
Putokazi su numerisani redom 1, 2, 3 i 4. Zbirovi su 11, 11, 13 i 11, pa je netačan treći putokaz.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Ključna ideja
Na ispravnom putokazu zbir a + b jednak je ukupnoj dužini puta od Agrada do Begrada, dakle isti za sve ispravne putokaze.
2. Tri ista, jedan drugačiji
Tri zbira su jednaka, a jedan se razlikuje. Treba naći onaj koji se razlikuje.
3. Analiza slučajeva
Ako su zbirovi prvog i drugog putokaza jednaki, netačan je treći ili četvrti: treći je netačan ako se razlikuje od prvog, inače je netačan četvrti. Ako se zbirovi prvog i drugog razlikuju, netačan je jedan od njih: ako je treći jednak prvom, netačan je drugi, inače prvi.
4. Tip podataka
Zbir dva broja manja od 109 može preći granicu tipa int, zato koristimo long long.
C++ rešenje
#include <iostream>
using namespace std;
int main() {
long long a[4], b[4], zbir[4];
for (int i = 0; i < 4; i++) {
cin >> a[i] >> b[i];
zbir[i] = a[i] + b[i]; // trebalo bi da je isti za sve putokaze
}
if (zbir[0] == zbir[1]) {
// prva dva se slažu, pa je netačan treći ili četvrti
if (zbir[2] != zbir[0]) cout << 3 << endl;
else cout << 4 << endl;
} else {
// jedan od prva dva je netačan; treći odlučuje koji
if (zbir[2] == zbir[0]) cout << 2 << endl;
else cout << 1 << endl;
}
return 0;
}
Objašnjenje: Rešenje ne zahteva petlje ni sortiranje, samo četiri sabiranja i nekoliko poređenja.
Dat je prirodan broj n (n ≤ 109). Odrediti proizvod prostih cifara u tom broju.
Ulaz
Na standardnom ulazu unosi se tačno jedan prirodan broj n.
Izlaz
Na standardni izlaz treba ispisati jedan prirodan broj – proizvod prostih cifara u tom broju. Ukoliko broj nema prostih cifara, ispisati -1.
Napomena. Za prirodan broj kažemo da je prost ako ima tačno dva različita delioca u skupu prirodnih brojeva. Brojevi 0 i 1 nisu prosti.
Primer 1
Ulaz
52483579
Izlaz
1050
Objašnjenje
Proizvod prostih cifara je 5 · 2 · 3 · 5 · 7 = 1050.
Primer 2
Ulaz
186
Izlaz
-1
Objašnjenje
Cifre 1, 8 i 6 nisu proste.
Primer 3
Ulaz
1026
Izlaz
2
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Koje su cifre proste
Jednocifreni prosti brojevi su 2, 3, 5 i 7. Cifre 0, 1, 4, 6, 8 i 9 nisu proste.
2. Izdvajanje cifara
Cifre broja izdvajamo odozgo nadole petljom: n % 10 je poslednja cifra, a n /= 10 je odbacuje.
3. Proizvod i slučaj bez prostih cifara
Proizvod počinje od 1 i množi se prostim ciframa. Pošto je 1 i proizvod „praznog skupa“, posebnom logičkom promenljivom pamtimo da li smo ijednu prostu cifru sreli. Ako nismo, ispisujemo -1.
C++ rešenje
#include <iostream>
using namespace std;
int main() {
long long n;
cin >> n;
long long proizvod = 1;
bool imaProstih = false;
while (n > 0) {
int cifra = n % 10;
// prosti brojevi među ciframa: 2, 3, 5 i 7
if (cifra == 2 || cifra == 3 || cifra == 5 || cifra == 7) {
proizvod *= cifra;
imaProstih = true;
}
n /= 10;
}
if (imaProstih) cout << proizvod << endl;
else cout << -1 << endl;
return 0;
}
Objašnjenje: Najveći mogući proizvod je 79 = 40 353 607, što staje u int, ali long long ne škodi.
Data je niska koja sadrži pojedinačne reči i rečenice razdvojene razmacima, pri čemu su rečenice zagrađene uglastim zagradama. Napiši program koji određuje sve zapisane reči i rečenice.
Ulaz
Sa standardnog ulaza učitava se niska dužine najviše 10 000 karaktera sastavljena od malih slova engleske abecede, razmaka i uglastih zagrada. Niska je ispravno zapisana i sadrži reči i rečenice. Niska ne sadrži višestruke uzastopne razmake.
Izlaz
Na standardni izlaz ispisati svaku reč, odnosno rečenicu u posebnom redu.
Primer 1
Ulaz
[zdravo svima] dobar dan [kako ste] pozdrav
Izlaz
zdravo svima
dobar
dan
kako ste
pozdrav
Primer 2
Ulaz
pozdrav svima
Izlaz
pozdrav
svima
Primer 3
Ulaz
Danas je [takmicenje] [iz programiranja]
Izlaz
Danas
je
takmicenje
iz programiranja
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Učitavanje cele linije
Pošto niska sadrži razmake, učitavamo je sa getline(cin, s), a ne sa cin >> s.
2. Prolazak kroz nisku
Indeksom i idemo s leva na desno. Razmak preskačemo. Ako je na poziciji i znak [, rečenica traje do prve zatvorene zagrade ]; inače je to običan početak reči koja traje do sledećeg razmaka (ili kraja niske).
3. Isecanje delova
Deo niske isecamo sa s.substr(početak, dužina). Za rečenicu isecamo sadržaj između zagrada, bez samih zagrada.
4. Nastavak
Posle obrade nastavljamo od prve pozicije iza reči, odnosno iza zatvorene zagrade.
C++ rešenje
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
getline(cin, s);
int n = s.size();
int i = 0;
while (i < n) {
if (s[i] == ' ') { // razmake preskačemo
i++;
} else if (s[i] == '[') { // rečenica: do zatvorene zagrade
int j = i + 1;
while (s[j] != ']') j++;
cout << s.substr(i + 1, j - i - 1) << endl;
i = j + 1;
} else { // obična reč: do prvog razmaka
int j = i;
while (j < n && s[j] != ' ') j++;
cout << s.substr(i, j - i) << endl;
i = j;
}
}
return 0;
}
Objašnjenje: Zagrade se ne ugnježdavaju, pa je za svaku [ dovoljno naći prvu sledeću ].
Za par takmičara kažemo da je dobar ako je razlika u poenima dva takmičara najviše k. Odrediti broj dobrih parova na takmičenju.
Ulaz
U prvom redu standardnog ulaza nalazi se broj takmičara n (n ≤ 105). U drugom redu nalazi se n prirodnih brojeva manjih od 105 – poeni takmičara. U trećem redu nalazi se najveća dopuštena razlika poena k (1 ≤ k ≤ 105).
U 50% primera važi n ≤ 103. U ostalim test-primerima broj takmičara je veliki, pa se za 100% poena očekuje efikasno rešenje.
Izlaz
Na standardni izlaz ispisati tačno jedan ceo broj – broj dobrih parova.
Primer 1
Ulaz
6
1 12 2 9 5 8
4
Izlaz
8
Objašnjenje
Dobre parove čine takmičari sa poenima (1,2), (1,5), (12,9), (12,8), (2,5), (9,5), (9,8) i (5,8).
Primer 2
Ulaz
10
15 3 24 17 9 16 3 22 19 8
5
Izlaz
14
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Sporo rešenje
Proverom svakog para (dve petlje) dobijamo oko n²/2 poređenja, a za n = 105 to je 5 milijardi. Dovoljno za 50% poena, ali ne i za sve.
2. Sortiranje
Kada su poeni sortirani, svi takmičari koji sa datim takmičarem čine dobar par nalaze se u jednom neprekidnom bloku odmah ispred njega.
3. Dva pokazivača
Za svakog takmičara desno (redom) pomeramo levo udesno dok je poeni[desno] − poeni[levo] > k. Tada su svi takmičari od levo do desno − 1 dobri parovi sa takmičarem desno, pa dodajemo desno − levo.
4. Složenost i tip
Pokazivač levo samo napreduje, pa je posle sortiranja posao linearan: ukupno O(n log n). Broj parova može biti oko 5·109, pa brojač mora biti long long.
C++ rešenje
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n, k;
cin >> n;
vector<int> poeni(n);
for (int i = 0; i < n; i++) cin >> poeni[i];
cin >> k;
sort(poeni.begin(), poeni.end());
long long parova = 0;
int levo = 0;
for (int desno = 0; desno < n; desno++) {
// pomeramo levi kraj dok je razlika prevelika
while (poeni[desno] - poeni[levo] > k) {
levo++;
}
// takmičar "desno" čini dobar par sa svima iz [levo, desno)
parova += desno - levo;
}
cout << parova << endl;
return 0;
}
Objašnjenje: Svaki par se broji tačno jednom: kada se „desno“ nalazi na većem (kasnijem) od dva takmičara.
Ako su poznate dužine stranica nekoliko trouglova, odrediti vrednost najvećeg obima tih trouglova.
Ulaz
Sa standardnog ulaza unosi se broj n (1 ≤ n ≤ 100), a zatim u narednih n redova po tri prirodna broja koji predstavljaju dužine stranica trougla (sve trojke brojeva zadovoljavaju odgovarajuće nejednakosti trougla).
Izlaz
Na standardni izlaz ispisati najveći obim trougla.
Primer
Ulaz
3
3 4 5
10 3 11
5 7 8
Izlaz
24
Objašnjenje
Obimi su 12, 24 i 20; najveći je 24.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Obim
Obim trougla je zbir tri stranice: a + b + c.
2. Najveći obim
Pamtimo najveći obim do sada u promenljivoj najveciObim (početna vrednost 0, jer su obimi pozitivni). Posle svakog učitanog trougla ažuriramo je sa max.
3. Pažnja
Trojke ne moramo posebno proveravati: zadatak garantuje da su sve trouglovi.
C++ rešenje
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
int najveciObim = 0;
for (int i = 0; i < n; i++) {
int a, b, c;
cin >> a >> b >> c;
najveciObim = max(najveciObim, a + b + c);
}
cout << najveciObim << endl;
return 0;
}
Objašnjenje: Nije potrebno čuvati sve trouglove u nizu – dovoljno je da se za svaki izračuna obim i uporedi sa dosadašnjim najvećim.
Potrebno predznanje: Operatori, petlje, nizovi Opciono:Vektori · Mape u C++
Postavka zadatka
Ivan je zapisao rezultate 4 četvrtfinalna meča, 2 polufinalna meča i finalnog meča nokaut faze turnira (ukupno 7 mečeva). Rezultati koji su dati na ulazu nisu sortirani (na primer, poslednji red na ulazu ne znači nužno da je taj meč poslednji odigran). Odrediti pobednika i drugoplasiranog na turniru.
Ulaz
Sedam linija standardnog ulaza sadrže po 2 imena razdvojena jednim razmakom. Prvo ime u redu predstavlja pobednika, a drugo poraženog u tom meču. Sva imena se sastoje od najmanje jednog, a najviše 10 slova engleske abecede.
Izlaz
U prvom redu standardnog izlaza ispisati pobednika turnira. U drugom redu ispisati drugoplasiranog na turniru.
Primer
Ulaz
Bojan Aleksa
Vanja Goran
Emil Zivadin
Emil Vanja
Vanja Bojan
Emil Dusan
Dusan Djordje
Izlaz
Emil
Vanja
Objašnjenje
U četvrtfinalu: Emil je pobedio Živadina, Dušan Đorđa, Bojan Aleksu, Vanja Gorana. U polufinalu je Emil pobedio Dušana, a Vanja Bojana. U finalu je Emil pobedio Vanju.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Koliko ko ima pobeda
U nokaut turniru sa 8 učesnika pobednik dobija 3 meča (četvrtfinale, polufinale, finale), finalista 2 meča (četvrtfinale, polufinale) i izgubi finale, polufinalisti koji su poraženi imaju 1 pobedu, a ostali 0.
2. Brojanje
Za svako ime pamtimo broj pobeda u rečniku map<string, int>. Pri čitanju svakog meča povećamo broj pobeda samo prvom imenu (pobedniku).
3. Rezultat
Pobednik turnira je ime sa 3 pobede, a drugoplasirani ime sa 2 pobede.
4. Alternativa
Isto se može zaključiti i bez broja pobeda: pobednik turnira je jedino ime koje se nikada ne pojavljuje kao poraženo.
C++ rešenje
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> pobede; // ime -> broj osvojenih mečeva
for (int i = 0; i < 7; i++) {
string pobednik, poraz;
cin >> pobednik >> poraz;
pobede[pobednik]++;
}
string prvi, drugi;
for (auto &par : pobede) {
if (par.second == 3) prvi = par.first; // pobednik turnira: 3 pobede
if (par.second == 2) drugi = par.first; // finalista: 2 pobede, a finale je izgubio
}
cout << prvi << endl << drugi << endl;
return 0;
}
Objašnjenje: Redosled mečeva na ulazu nije bitan jer se oslanjamo samo na ukupan broj pobeda svakog takmičara.
U jednoj dečijoj igri svako dete stoji pored svog drveta, osim jednog, kojeg zovemo krojač. Krojač nema drvo kraj kojeg bi stajao, već ide od deteta do deteta i pita: „Kod koga su makazice?“. Upitano dete na to kaže ime jednog od ostale dece. Dok se krojač kreće ka pomenutom detetu, sva ostala deca pokušavaju da razmene mesta, a krojač pokušava da zauzme neko drvo, tako što stigne do drveta pre drugog deteta, ili bar istovremeno sa njim. Ako u tome uspe, njegovu ulogu preuzima dete koje je ostalo bez drveta.
U ovom zadatku pretpostavlja se da se sva deca kreću istom brzinom i da krojač odmah primećuje svaku započetu razmenu mesta i kreće ka bližem od dva privremeno slobodna drveta. Prvo dete pokušava da proceni sa koliko druge dece bi ono moglo da razmeni mesto, a da ih krojač ne ugrožava. Možete li da mu pomognete?
Slika 3: Zadatak Makazice – okružno takmičenje iz informatike, 8. razred, 2023/24.
Ulaz
U prvom redu standardnog ulaza su dva cela broja razdvojena razmakom – koordinate krojača. U drugom redu je jedan ceo broj n, broj drveća, tj. broj dece koja nisu krojač (n ≤ 50). U svakom od narednih n redova su po dva cela broja razdvojena razmakom – koordinate jednog deteta (prvo navedeno dete je ono koje procenjuje razmenu). Sve koordinate su iz intervala [0, 30000].
Izlaz
Na standardni izlaz ispisati jedan ceo broj – broj dece sa kojima prvo dete može bezbedno da razmeni mesto.
Primer 1
Ulaz
19 7
5
11 11
3 17
8 4
14 3
18 15
Izlaz
1
Objašnjenje
Prvo dete je na (11, 11). Bezbedna je samo razmena sa detetom na (8, 4): deca trče oko 7,6, a krojač je od bližeg drveta udaljen oko 8,9.
Primer 2
Ulaz
100 100
4
50 50
150 50
50 150
150 150
Izlaz
0
Objašnjenje
Krojač je u sredini, pa je za svaku razmenu bliži jednom od slobodnih drveta nego što je deci potrebno da stignu.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Šta znači „bezbedno“
Neka je prvo dete na drvetu P, a drugo dete na drvetu Q. Deca trče rastojanje |PQ|. Krojač trči do bližeg od dva slobodna drveta, na rastojanje min(|KP|, |KQ|). Pošto krojač pobeđuje i kad stigne istovremeno, razmena je bezbedna samo ako je min(|KP|, |KQ|) > |PQ|.
2. Poređenje bez korenovanja
Rastojanje dve tačke je koren iz dx² + dy². Korenovanje nije potrebno jer su sva rastojanja nenegativna – dovoljno je porediti kvadrate rastojanja, i to celim brojevima (bez grešaka pri zaokruživanju). Kvadrat rastojanja može dostići oko 1,8·109, pa koristimo long long.
3. Petlja po deci
Prvo dete je prvo u spisku. Za svako od preostalih n − 1 dece računamo tri kvadrata rastojanja i uvećavamo brojač ako je razmena bezbedna.
4. Provera na primeru
Za primer 1 razmena sa detetom na (14, 3) nije bezbedna jer je krojač drvetu na (14, 3) bliži nego što deca trče; za dete na (18, 15) rastojanja su jednaka, što znači da krojač stiže istovremeno i razmena nije bezbedna. Jedina bezbedna razmena je sa detetom na (8, 4).
C++ rešenje
#include <iostream>
using namespace std;
long long kvadrat(long long a, long long b, long long c, long long d) {
// kvadrat rastojanja između tačaka (a, b) i (c, d)
return (a - c) * (a - c) + (b - d) * (b - d);
}
int main() {
long long kx, ky;
int n;
cin >> kx >> ky >> n;
long long x[50], y[50];
for (int i = 0; i < n; i++) cin >> x[i] >> y[i];
int bezbedno = 0;
for (int j = 1; j < n; j++) { // dete 0 je prvo dete
long long izmedju = kvadrat(x[0], y[0], x[j], y[j]); // koliko deca trče
long long krojacDo0 = kvadrat(kx, ky, x[0], y[0]);
long long krojacDoJ = kvadrat(kx, ky, x[j], y[j]);
long long krojac = (krojacDo0 < krojacDoJ) ? krojacDo0 : krojacDoJ;
// krojač mora da bude strogo dalje od bližeg drveta nego što deca trče
if (krojac > izmedju) {
bezbedno++;
}
}
cout << bezbedno << endl;
return 0;
}
Objašnjenje: Pretpostavka: prvo dete iz spiska je ono koje procenjuje razmenu; to je potvrđeno oba data primera. Slika uz zadatak prikazuje primer 1.
Mika je dao Peri N (N ≤ 2·105) kanapa celobrojnih dužina (svi kanapi su kraći od 1018). Pera izbacuje tačno jedan kanap iz skupa kanapa koji mu je dat. Nakon što Pera izbaci taj kanap, on želi da preostale kanape iseče na komade istih dužina (svi komadi moraju biti jednakih dužina, bez obzira od kog kanapa su potekli). Pera želi da izbaci kanap nakon kog bi preostalih N − 1 kanapa mogao da iseče na komade što veće dužine. Koliko iznosi ta dužina?
Imajte na umu da vaše rešenje mora da bude dovoljno efikasno – da se izvršava za manje od 1 sekunde.
Ulaz
U prvom redu standardnog ulaza nalazi se prirodan broj N – broj kanapa (N ≤ 2·105). U drugom redu nalazi se tačno N prirodnih brojeva – dužine kanapa (svi kanapi su kraći od 1018).
Dodatna ograničenja. Test primeri su podeljeni u tri disjunktne grupe:
40 poena: N ≤ 103 i 1 ≤ Ai ≤ 104;
20 poena: N ≤ 4·104 i 1 ≤ Ai ≤ 104;
40 poena: N ≤ 2·105 i 1 ≤ Ai ≤ 1018.
Izlaz
Na standardni izlaz ispisati tačno jedan prirodan broj – maksimalnu dužinu na koju možemo iseći kanape tako da svi preostali komadi budu iste dužine.
Primer 1
Ulaz
3
8 39 12
Izlaz
4
Objašnjenje
Pera može da izbaci kanap dužine 39. Tada preostala dva kanapa može da iseče na komade dužine 4. Ako bi izbacio kanap dužine 8, maksimalna dužina bila bi 3, a ako bi izbacio kanap dužine 12, bila bi 1. Prema tome, maksimalna dužina je 4.
Primer 2
Ulaz
4
10 13 12 8
Izlaz
2
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Šta je tražena dužina
Komad dužine d može da se iseče iz svakog preostalog kanapa samo ako d deli dužinu tog kanapa. Najveće takvo d je najveći zajednički delilac (NZD) svih preostalih dužina.
2. Sporo rešenje
Za svaki izbačeni kanap računati NZD ostalih zahteva O(N²) računanja NZD, što je prespor za N = 2·105.
3. Prefiksi i sufiksi
Izračunamo levo[i] – NZD prvih i kanapa, i desno[i] – NZD kanapa od pozicije i do kraja. Kada izbacimo kanap i, NZD ostalih je NZD(levo[i], desno[i+1]).
4. Početne vrednosti
NZD praznog skupa uzimamo kao 0 jer je NZD(0, x) = x.
5. Rezultat i tip
Od svih izbačenih kanapa biramo onaj sa najvećim dobijenim NZD. Vrednosti dostižu 1018, pa je long long obavezan.
C++ rešenje
#include <iostream>
#include <vector>
using namespace std;
long long nzd(long long a, long long b) {
while (b != 0) {
long long ostatak = a % b;
a = b;
b = ostatak;
}
return a;
}
int main() {
int n;
cin >> n;
vector<long long> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
// levo[i] = NZD prvih i kanapa, desno[i] = NZD kanapa od pozicije i do kraja
vector<long long> levo(n + 1, 0), desno(n + 2, 0);
for (int i = 0; i < n; i++) levo[i + 1] = nzd(levo[i], a[i]);
for (int i = n - 1; i >= 0; i--) desno[i] = nzd(desno[i + 1], a[i]);
long long najbolje = 0;
for (int i = 0; i < n; i++) {
// izbacujemo kanap i: ostaju kanapi levo od njega i desno od njega
long long dobijeno = nzd(levo[i], desno[i + 1]);
if (dobijeno > najbolje) najbolje = dobijeno;
}
cout << najbolje << endl;
return 0;
}
Objašnjenje: Ukupna složenost je O(N log A), gde je A najveća dužina, jer svaki od 3N računanja NZD traje O(log A).
Potrebno predznanje: Operatori, petlje, nizovi Opciono:Vektori
Postavka zadatka
U kvizu „Želite li da postanete milioner?“ takmičari odgovaraju na pitanja koja imaju 4 ponuđena odgovora (a, b, c, d). Takmičarima su na raspolaganju tri pomoći:
Pomoć publike – 100 gledalaca glasa za jedan od 4 ponuđena odgovora i učesnik može da vidi koliko ljudi je glasalo za koji odgovor.
Pola-pola – računar nasumično odbaci dva netačna odgovora i ostavi igraču jedan tačan i jedan netačan.
Pozovi prijatelja – učesnik telefonom zove svog prijatelja koji mu kaže šta misli da je tačan odgovor.
Darko je stigao do pretposlednjeg pitanja i ostale su mu sve tri pomoći. Pošto ne zna odgovor, odlučio se za sledeću taktiku: prvo će pitati publiku i ako jedan odgovor ima više glasova od svih ostalih zajedno, izabraće njega. Ako nijedan odgovor ne ispunjava uslov, uzeće pomoć pola-pola. Kada ostanu dva ponuđena odgovora, Darko će izabrati onaj koji ima bar 20 glasova publike više u odnosu na drugi. Ako i dalje nijedan odgovor ne ispunjava uslov, Darko će pozvati prijatelja i odgovoriće onako kako mu prijatelj kaže. Odrediti Darkov konačan odgovor na pretposlednje pitanje.
Ulaz
U prvom redu standardnog ulaza nalaze se 4 cela broja odvojena razmacima koji predstavljaju broj gledalaca koji su glasali redom za odgovore a, b, c i d. Svi ovi brojevi su između 0 i 100 i zbir im je 100.
Ukoliko je potrebno (tj. ako Darko nije na osnovu prve pomoći dao odgovor), u drugom redu nalaze se dva različita slova (iz skupa a, b, c, d) odvojena razmakom koja predstavljaju ponuđene odgovore koje je računar ostavio Darku.
Ukoliko je potrebno (tj. ako Darko ni na osnovu druge pomoći nije dao odgovor), u poslednjem redu nalazi se jedno slovo – odgovor koji prijatelj predlaže. To slovo je sigurno jedno od onih koje je računar ostavio kao moguć odgovor.
Izlaz
U jedinom redu standardnog izlaza ispisati jedno slovo (a, b, c ili d) koje predstavlja konačan odgovor koji je Darko dao.
Primer 1
Ulaz
12 17 11 60
Izlaz
d
Objašnjenje
Za odgovor d glasalo je više gledalaca nego za sve ostale zajedno, pa Darko odmah odlučuje da to bude njegov odgovor i ne koristi ostale pomoći.
Primer 2
Ulaz
12 17 34 37
b c
c
Izlaz
c
Objašnjenje
Nijedan odgovor nema neophodnu većinu, pa Darko traži pomoć pola-pola. Ostaju odgovori b i c čija je razlika u broju glasova publike (17 i 34) manja od 20, pa Darko traži pomoć prijatelja i daje odgovor c.
Jedan odgovor ima više glasova od svih ostalih zajedno ako ima više od polovine glasova. Pošto je ukupno 100 glasova, uslov je glasovi[i] > 50. Ako postoji takav odgovor, ispisujemo ga i završavamo program.
2. Druga pomoć: pola-pola
Tek tada učitavamo drugi red (dva slova). Glasove za slovo čitamo iz niza: glasovi[slovo - 'a']. Ako jedan od ta dva odgovora ima bar 20 glasova više, to je odgovor.
3. Treća pomoć: prijatelj
Ako nijedan uslov nije ispunjen, učitamo treći red i ispišemo slovo koje je prijatelj predložio.
4. Redosled učitavanja
Važno je da drugi i treći red učitavamo samo kada su potrebni – ulaz ih ne sadrži kada je odgovor poznat ranije.
C++ rešenje
#include <iostream>
using namespace std;
int main() {
int glasovi[4];
for (int i = 0; i < 4; i++) cin >> glasovi[i];
// 1. pomoć: publika. Jedan odgovor mora imati više glasova od svih ostalih zajedno,
// a pošto je ukupno 100 glasova, to znači više od 50.
for (int i = 0; i < 4; i++) {
if (glasovi[i] > 50) {
cout << (char)('a' + i) << endl;
return 0;
}
}
// 2. pomoć: pola-pola
char prvi, drugi;
cin >> prvi >> drugi;
int gp = glasovi[prvi - 'a'];
int gd = glasovi[drugi - 'a'];
if (gp - gd >= 20) {
cout << prvi << endl;
return 0;
}
if (gd - gp >= 20) {
cout << drugi << endl;
return 0;
}
// 3. pomoć: prijatelj
char prijatelj;
cin >> prijatelj;
cout << prijatelj << endl;
return 0;
}
Objašnjenje: Uslovi su „strogo više od polovine“ za publiku i „bar 20 više“ (tj. razlika ≥ 20) za pola-pola.
Potrebno predznanje: Operatori, petlje, nizovi Opciono:Vektori
Postavka zadatka
Napisati program koji ispituje koliko postoji ispravnih rasporeda dve slike poznatih dimenzija na papir poznatih dimenzija, tako da su ivice slika paralelne ivicama papira, da su slike prikazane cele i da se ne preklapaju. Slike nije dopušteno rotirati, ali papir jeste (moguće je postavljati ga bilo u horizontalnoj „pejzaž“ orijentaciji, bilo u vertikalnoj „portret“ orijentaciji). Slike je dopušteno postavljati bilo jednu ispod druge, bilo jednu pored druge, na papir koji je okrenut bilo horizontalno, bilo vertikalno (postoji, dakle, najviše 4 moguća rasporeda, pri čemu neki od njih mogu biti neispravni jer su slike prevelike).
Ulaz
Sa standardnog ulaza unose se dimenzije (širina i visina) papira, dimenzije prve slike i dimenzije druge slike.
Izlaz
Na standardni izlaz ispisati broj od 0 do 4 koji predstavlja broj mogućih načina da se slike rasporede na papir.
Papir može biti u dve orijentacije (širina i visina zamene mesta), a slike u dva rasporeda (jedna pored druge ili jedna ispod druge): ukupno 4 mogućnosti.
2. Jedna pored druge
Zajednička širina je w1 + w2, a potrebna visina je veća od dve visine, max(h1, h2). Raspored je ispravan ako je w1 + w2 ≤ širina papira i max(h1, h2) ≤ visina papira.
3. Jedna ispod druge
Potrebna širina je max(w1, w2), a visina h1 + h2. Raspored je ispravan ako je max(w1, w2) ≤ širina i h1 + h2 ≤ visina.
4. Orijentacije papira
Napravimo funkciju koja za zadate dimenzije papira prebroji ispravne rasporede (0, 1 ili 2) i pozovemo je dvaput: za (širina, visina) i za (visina, širina).
C++ rešenje
#include <iostream>
#include <algorithm>
using namespace std;
// Da li se slike dimenzija (w1,h1) i (w2,h2) mogu rasporediti
// na papir širine pw i visine ph, jedna pored druge ili jedna iznad druge?
int rasporedi(int pw, int ph, int w1, int h1, int w2, int h2) {
int broj = 0;
// jedna pored druge
if (w1 + w2 <= pw && max(h1, h2) <= ph) broj++;
// jedna ispod druge
if (max(w1, w2) <= pw && h1 + h2 <= ph) broj++;
return broj;
}
int main() {
int sirina, visina, w1, h1, w2, h2;
cin >> sirina >> visina >> w1 >> h1 >> w2 >> h2;
int ukupno = 0;
ukupno += rasporedi(sirina, visina, w1, h1, w2, h2); // papir horizontalno
ukupno += rasporedi(visina, sirina, w1, h1, w2, h2); // papir vertikalno (okrenut)
cout << ukupno << endl;
return 0;
}
Objašnjenje: Slike se ne rotiraju, pa im dimenzije ostaju iste u svim rasporedima; menja se samo orijentacija papira.
Za svaku poziciju u nizu celih brojeva odrediti proizvod svih elemenata niza osim elementa na toj poziciji.
Ulaz
Sa standardnog ulaza učitava se broj n (1 ≤ n ≤ 105), a zatim elementi niza (brojevi od −10 do 10), pri čemu se garantuje da je svaki od traženih proizvoda broj između −109 i 109.
Izlaz
Na standardni izlaz ispisati tražene proizvode razdvojene razmacima.
Primer 1
Ulaz
5
1 2 3 4 5
Izlaz
120 60 40 30 24
Primer 2
Ulaz
5
1 2 0 4 5
Izlaz
0 0 40 0 0
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Sporo rešenje
Za svaku poziciju množiti sve ostale elemente je O(n²), što je sporo za n = 105.
2. Ukupan proizvod i deljenje
Izračunamo proizvod svih elemenata i podelimo ga elementom na toj poziciji. Ovo ne radi ako u nizu ima nula – deljenje nulom nije dozvoljeno.
3. Nule
Proizvod računamo samo od elemenata različitih od nule i brojimo nule. Ako nula nema, rezultat na poziciji i je proizvod / a[i]. Ako je tačno jedna nula, rezultat na njenoj poziciji je proizvod, a svuda drugde 0. Ako ima dve ili više nula, svi su rezultati 0.
4. Tip podataka
Proizvod elemenata različitih od nule može biti 10 puta veći od traženih rezultata, pa koristimo long long.
C++ rešenje
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
int nula = 0; // koliko ima nula u nizu
long long proizvod = 1; // proizvod svih elemenata različitih od nule
for (int i = 0; i < n; i++) {
if (a[i] == 0) nula++;
else proizvod *= a[i];
}
for (int i = 0; i < n; i++) {
long long rezultat;
if (nula >= 2) {
rezultat = 0; // u svakom proizvodu ostaje bar jedna nula
} else if (nula == 1) {
rezultat = (a[i] == 0) ? proizvod : 0;
} else {
rezultat = proizvod / a[i];
}
cout << rezultat << (i + 1 < n ? " " : "\n");
}
return 0;
}
Objašnjenje: Deljenje je tačno jer je proizvod deljiv svakim svojim činiocem.
Dat je niz od n celih brojeva i jedan ceo broj x. Napiši program koji određuje k brojeva iz niza najbližih broju x (ukoliko su dva broja na istoj udaljenosti od x, bira se manji od njih). Pod udaljenošću se smatra apsolutna vrednost razlike brojeva.
Ulaz
Iz prve linije standardnog ulaza unose se brojevi n (1 ≤ n ≤ 105), k (1 ≤ k ≤ n) i x (1 ≤ x ≤ 109) razdvojeni razmacima. Zatim se u narednoj liniji unosi n celih brojeva ai (1 ≤ ai ≤ 109) koji predstavljaju elemente niza, takođe razdvojeni razmacima.
Izlaz
Na standardni izlaz ispisati traženih k brojeva razdvojenih razmacima, uređenih neopadajuće.
Primer 1
Ulaz
7 4 4
7 4 2 3 1 5 6
Izlaz
2 3 4 5
Objašnjenje
Od svih unetih brojeva, 4 broja najbliža broju 4 su 2, 3, 4 i 5. Ostali brojevi imaju veću razliku u odnosu na broj 4.
Primer 2
Ulaz
5 3 2
3 1 3 1 3
Izlaz
1 1 3
Primer 3
Ulaz
5 3 20
5 3 2 4 1
Izlaz
3 4 5
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Sortiranje po udaljenosti
Niz sortiramo tako da brojevi sa manjom udaljenošću od x idu ispred. Za istu udaljenost ispred ide manji broj – to je upravo pravilo iz zadatka.
2. Funkcija poređenja
U sort prosleđujemo funkciju koja za dva broja p i q poredi |p − x| i |q − x|, a pri jednakosti p i q.
3. Prvih k
Posle ovog sortiranja traženih k brojeva su prvih k elemenata.
4. Neopadajući izlaz
Izlaz mora biti uređen neopadajuće, pa tih prvih k elemenata ponovo sortiramo (običnim poređenjem) pre ispisa.
C++ rešenje
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;
int main() {
int n, k;
long long x;
cin >> n >> k >> x;
vector<long long> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
// sortiramo po udaljenosti od x, a pri istoj udaljenosti prvo manji broj
sort(a.begin(), a.end(), [x](long long p, long long q) {
long long dp = llabs(p - x), dq = llabs(q - x);
if (dp != dq) return dp < dq;
return p < q;
});
// uzimamo prvih k i ispisujemo ih neopadajuće
sort(a.begin(), a.begin() + k);
for (int i = 0; i < k; i++) {
cout << a[i] << (i + 1 < k ? " " : "\n");
}
return 0;
}
Objašnjenje: Dva sortiranja daju složenost O(n log n), što je dovoljno za n = 105.
Potrebno predznanje: Operatori, petlje, nizovi Opciono:Vektori
Postavka zadatka
U jednoj firmi koja se bavi onlajn prodajom za dostavu kupljene robe koriste se roboti. Kupci koje će robot Mile sutra usluživati stanuju svi na istoj strani iste ulice. Mile za svaku adresu zna njenu koordinatu, tj. rastojanje od početka ulice do te zgrade. Mile je programiran tako da adrese obilazi redom kojim su mu zadate.
Napiši program koji za dati broj dostava i date koordinate zgrada (rastojanja zgrada od početka ulice) izračunava i ispisuje ukupno rastojanje koje će robot Mile preći od prve do poslednje dostave.
Ulaz
U prvom redu standardnog ulaza nalazi se prirodan broj n, ne veći od 30. U svakom od sledećih n redova nalazi se po jedan neoznačen ceo broj – rastojanje od početka ulice do sledeće zgrade (tj. koordinata zgrade) u koju treba dostaviti narudžbinu. Ovi brojevi nisu veći od 10000.
Izlaz
Na standardni izlaz ispisati samo jedan ceo broj – ukupnu dužinu puta koji pređe robot Mile.
Primer 1
Ulaz
5
2
7
7
1
3
Izlaz
13
Objašnjenje
Pozicije zgrada u redosledu dostavljanja su 2, 7, 7, 1, 3. Mile prvo ide od pozicije 2 do pozicije 7, zatim od 7 do 7 (dostava u istoj zgradi), pa od 7 do 1 i na kraju od 1 do 3. Pređena rastojanja su redom 5, 0, 6, 2, a njihov zbir je 13.
Primer 2
Ulaz
1
7
Izlaz
0
Objašnjenje
Prva i poslednja dostava su ista dostava, pa se Mile uopšte ne kreće i pređeno rastojanje je 0.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Rastojanje između dve zgrade
Pošto su sve zgrade na istoj ulici, rastojanje između dve zgrade je apsolutna vrednost razlike njihovih koordinata: abs(a − b).
2. Čitanje bez niza
Dovoljno je da pamtimo koordinatu prethodne zgrade. Prvu zgradu učitamo odvojeno, a zatim za svaku sledeću dodamo abs(trenutna − prethodna) ukupnom putu i ažuriramo prethodna.
3. Slučaj n = 1
Petlja za preostale zgrade se tada ne izvršava, pa je rezultat 0 – bez posebne provere.
C++ rešenje
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
int n;
cin >> n;
int ukupno = 0;
int prethodna;
cin >> prethodna; // prva zgrada
for (int i = 1; i < n; i++) {
int trenutna;
cin >> trenutna;
ukupno += abs(trenutna - prethodna); // put od prethodne do ove zgrade
prethodna = trenutna;
}
cout << ukupno << endl;
return 0;
}
Objašnjenje: Ranije rešenje bilo je napisano u jeziku C#; ovde je isti algoritam u C++, kao i u ostalim zadacima.
Nastavnik je Perici zadao domaći zadatak u kojem na osnovu 4 zadate dekadne cifre treba da odredi razliku najvećeg i najmanjeg četvorocifrenog broja koji se mogu formirati pomoću tih cifara. Napisati program koji će na osnovu 4 unete dekadne cifre pomoći Perici da proveri da li je tačno uradio domaći.
Ulaz
U svakom od 4 reda standardnog ulaza nalazi se po jedna dekadna cifra, od kojih bar jedna nije nula.
Izlaz
Na standardni izlaz ispisati samo jedan prirodan broj koji predstavlja razliku najvećeg i najmanjeg četvorocifrenog broja koji se pomoću datih cifara mogu formirati.
Primer 1
Ulaz
3
7
5
9
Izlaz
6174
Objašnjenje
Najveći četvorocifreni broj koji se može formirati je 9753, a najmanji 3579. Razlika je 9753 − 3579 = 6174.
Primer 2
Ulaz
2
0
5
6
Izlaz
4464
Objašnjenje
Najveći broj je 6520, a najmanji 2056. Razlika je 6520 − 2056 = 4464. U zadatku se traži četvorocifreni broj, pa broj ne sme počinjati nulom – zato najmanji broj nije 0256.
Primer 3
Ulaz
0
0
5
0
Izlaz
0
Objašnjenje
Najveći i najmanji četvorocifreni broj su isti: 5000. Razlika je 0.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Cifre u nizu
Četiri cifre učitamo u niz i sortiramo ih rastuće.
2. Najveći broj
Najveći broj dobijamo kada cifre poređamo opadajuće, tj. čitamo sortirani niz od kraja ka početku.
3. Najmanji broj
Najmanji broj dobijamo rastućim redosledom cifara, ali prva cifra ne sme biti 0. Zato pronađemo prvu cifru različitu od nule i zamenimo je sa cifrom na prvom mestu; ostale cifre ostaju u rastućem redosledu.
4. Razlika
Brojeve formiramo kao c0 · 1000 + c1 · 100 + c2 · 10 + c3 i ispišemo razliku najvećeg i najmanjeg.
5. Provera
Za cifre 0, 0, 1, 2: najveći je 2100, a najmanji 1002 (a ne 0012), pa je razlika 1098.
C++ rešenje
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int c[4];
for (int i = 0; i < 4; i++) cin >> c[i];
sort(c, c + 4); // rastuće: c[0] <= c[1] <= c[2] <= c[3]
// najveći broj: cifre od najveće ka najmanjoj
int najveci = c[3] * 1000 + c[2] * 100 + c[1] * 10 + c[0];
// najmanji broj: cifre rastuće, ali prva cifra ne sme biti 0
int j = 0;
while (c[j] == 0) j++; // prva cifra različita od nule (postoji bar jedna)
swap(c[0], c[j]);
int najmanji = c[0] * 1000 + c[1] * 100 + c[2] * 10 + c[3];
cout << najveci - najmanji << endl;
return 0;
}
Objašnjenje: Zahtev „bar jedna cifra nije nula“ garantuje da prva nenulta cifra postoji, pa petlja za njeno traženje uvek staje.
Dva igrača igraju igru iks-oks. Ova igra se igra na tabli veličine 3×3 na koju igrači naizmenično upisuju iks ili oks. Pobednik je onaj igrač koji uspe da u jedan red, jednu kolonu ili na jednu dijagonalu upiše 3 svoja znaka. Za zadatu krajnju poziciju igre odredi da li je pobedio igrač iks, igrač oks, ili je igra završena nerešeno.
Ulaz
U tri reda standardnog ulaza nalaze se po tri znaka x, o ili *. Prvi red ulaza opisuje kako je popunjen prvi red table za igranje, itd. Oznaka x označava iks, o oks, a * da je to polje na kraju partije prazno.
Izlaz
Ukoliko je pobedio iks, ispisati znak x, ukoliko je pobedio oks, ispisati o, a ukoliko je nerešeno, ispisati nereseno.
Primer 1
Ulaz
x*x
ox*
xoo
Izlaz
x
Objašnjenje
Iks ima tri znaka na sporednoj dijagonali.
Primer 2
Ulaz
xxo
oox
xox
Izlaz
nereseno
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Table kao niska od 3 znaka
Svaki red učitamo kao string od 3 znaka; tada je t[i][j] znak u vrsti i i koloni j.
2. Osam linija
Pobedničkih linija ima osam: tri vrste, tri kolone i dve dijagonale. Za igrača p proveravamo da li su sva tri polja neke linije jednaka p.
3. Za oba igrača
Isti kod pokrećemo za 'x', a zatim za 'o'. Prazno polje * nikada nije pobednički znak jer proveravamo samo x i o.
4. Nerešeno
Ako ni jedan igrač nema liniju, ispisujemo nereseno.
C++ rešenje
#include <iostream>
#include <string>
using namespace std;
int main() {
string t[3];
for (int i = 0; i < 3; i++) cin >> t[i];
// proveravamo za oba igrača
char igraci[2] = {'x', 'o'};
for (char p : igraci) {
bool pobedio = false;
for (int i = 0; i < 3; i++) {
if (t[i][0] == p && t[i][1] == p && t[i][2] == p) pobedio = true; // vrsta i
if (t[0][i] == p && t[1][i] == p && t[2][i] == p) pobedio = true; // kolona i
}
if (t[0][0] == p && t[1][1] == p && t[2][2] == p) pobedio = true; // glavna dijagonala
if (t[0][2] == p && t[1][1] == p && t[2][0] == p) pobedio = true; // sporedna dijagonala
if (pobedio) {
cout << p << endl;
return 0;
}
}
cout << "nereseno" << endl;
return 0;
}
Objašnjenje: Pretpostavka je da je ulaz ispravna završna pozicija, u kojoj ne mogu pobediti oba igrača.
Napiši program koji za unetu nisku određuje apsolutnu vrednost razlike između broja cifara i broja slova u toj niski. Kao slova se broje mala i velika slova engleske abecede.
Ulaz
Jedina linija standardnog ulaza sadrži nisku dužine najviše 20 karaktera. U niski, pored malih i velikih slova engleske abecede i cifara, mogu da se pojave i praznine i drugi ASCII karakteri (neće se pojavljivati slova drugih pisama).
Izlaz
Na standardni izlaz ispisati traženu vrednost.
Primer
Ulaz
Programiranje 1
Izlaz
12
Objašnjenje
Niska ima 13 slova i 1 cifru, razlika je 12.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Cela linija
Niska može da sadrži razmake, pa je učitavamo sa getline(cin, s). Običan cin >> s bi stao na prvom razmaku.
2. Klasifikacija znakova
Prolazimo kroz sve znakove. Znak je cifra ako je između '0' i '9', a slovo ako je između 'a' i 'z' ili između 'A' i 'Z'. Sve ostalo (razmaci, znakovi interpunkcije) ne brojimo.
3. Rezultat
Ispisujemo abs(cifre − slova) – apsolutnu vrednost, jer slova mogu biti i manje i više brojna od cifara.
C++ rešenje
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main() {
string s;
getline(cin, s); // niska može da sadrži razmake
int cifre = 0, slova = 0;
for (char c : s) {
if (c >= '0' && c <= '9') {
cifre++;
} else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
slova++;
}
}
cout << abs(cifre - slova) << endl;
return 0;
}
Objašnjenje: Ni cifre ni slova ne moramo čuvati – dovoljna su dva brojača.
Potrebno je simulirati bankovni sistem za k različitih korisnika. Svaki korisnik ima račun sa početnim stanjem 0. Potrebno je podržati dve vrste operacija:
upit x – određuje koliko postoji korisnika čiji račun sadrži tačno x dinara;
ime x – dodaje x dinara na račun osobe sa imenom ime (x može biti i negativno).
Napisati program koji podržava izvršavanje n ovakvih operacija.
Ulaz
Sa standardnog ulaza unose se brojevi n i k. Nakon toga se u n redova unosi po jedna operacija.
Izlaz
Za svaki upit (operaciju prvog tipa) ispisati odgovor, svaki u zasebnom redu.
Primer
Ulaz
6 4
marko 2
milan 5
dragana 4
upit 0
milan -1
upit 4
Izlaz
1
2
Objašnjenje
Posle prve tri operacije Marko ima 2, Milan 5 i Dragana 4 dinara, a četvrti korisnik 0 – tačno jedan račun ima 0 dinara. Kada Milan izgubi 1 dinar, i Milan i Dragana imaju po 4 dinara.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Šta treba da znamo
Pitanje „koliko računa ima tačno x dinara“ možemo odmah da odgovorimo ako stalno čuvamo broj računa po stanju. Zato nam trebaju dve mape.
2. Dve mape
map<string, long long> stanje čuva stanje svakog korisnika (podrazumevano 0), a map<long long, int> brojRacuna čuva koliko računa ima dato stanje.
3. Početak
Na početku svih k korisnika ima 0 dinara, pa je brojRacuna[0] = k. To je važno: korisnici koje još nismo videli takođe se broje u upitu upit 0.
4. Uplata
Za operaciju ime x: staro stanje je stanje[ime]. Smanjimo brojRacuna[staro], postavimo novo stanje staro + x i povećamo brojRacuna[novo].
5. Upit
Za upit x ispisujemo brojRacuna[x]. Ako stanje x ne postoji u mapi, mapa ga automatski stvara sa vrednošću 0.
C++ rešenje
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
map<string, long long> stanje; // stanje računa svakog korisnika
map<long long, int> brojRacuna; // koliko računa ima tačno dato stanje
brojRacuna[0] = k; // na početku svih k računa ima 0 dinara
for (int i = 0; i < n; i++) {
string rec;
long long x;
cin >> rec >> x;
if (rec == "upit") {
cout << brojRacuna[x] << endl;
} else {
long long staro = stanje[rec]; // ako korisnik nije viđen, stanje je 0
brojRacuna[staro]--; // račun napušta staro stanje ...
stanje[rec] = staro + x;
brojRacuna[staro + x]++; // ... i prelazi u novo
}
}
return 0;
}
Objašnjenje: Svaka operacija traje O(log n). Pretpostavka je da nijedan korisnik nema ime „upit“.
Duž jedne livade ukopane su zastavice (za svaku zastavicu poznata je celobrojna x-koordinata). Krtice su se zbog toga iznervirale i krenule u akciju i svaka od njih je iskopala rupu na nekom mestu duž te livade (za svaku rupu poznata je celobrojna x-koordinata). Oko svake rupe zemlja postaje nestabilna i sve zastavice koje su na rastojanju najviše d od neke rupe se urušavaju (uključujući i one na rastojanju d). Napiši program koji određuje koliko je zastavica preostalo nakon kopanja svih rupa.
Ulaz
U prvom redu standardnog ulaza je broj zastavica m (1 ≤ m ≤ 105), a u drugom celobrojne koordinate svih zastavica (celi brojevi između 0 i 109) razdvojene po jednim razmakom.
U trećem redu je broj rupa n (1 ≤ n ≤ 105), a u četvrtom celobrojne koordinate svih rupa (celi brojevi između 0 i 109), takođe razdvojene po jednim razmakom. Na kraju, u petom redu, nalazi se broj d (1 ≤ d ≤ 109).
Dodatna ograničenja. U primerima vrednim 49% poena dodatno važi 1 ≤ m ≤ 100 i 1 ≤ n ≤ 100; u primerima vrednim 51% poena nema dodatnih ograničenja.
Izlaz
Na standardni izlaz ispisati broj preostalih zastavica.
Primer
Ulaz
3
4 5 8
4
10 9 1 8
2
Izlaz
2
Objašnjenje
Zastavica na 8 se ruši zbog rupe na 8. Zastavice na 4 i 5 su od najbliže rupe udaljene 3 > 2, pa preostaju.
Uputstvo i rešenje
Uputstvo — ideja rešenja
1. Sporo rešenje
Za svaku zastavicu proveriti svaku rupu je O(m·n), što je 1010 poređenja – previše. Dovoljno je za prvu grupu primera (m, n ≤ 100).
2. Samo dve rupe su bitne
Ako su rupe sortirane, od svih rupa zastavici z mogu biti najbliže samo dve: prva rupa desno od nje (ili na njoj) i poslednja rupa levo od nje. Ako ni jedna od te dve nije na rastojanju ≤ d, nijedna rupa je ne ruši.
3. Binarna pretraga
Prvu rupu koja nije levo od zastavice nalazimo funkcijom lower_bound u O(log n). Rupa neposredno pre nje je najbliža leva.
4. Brojanje
Brojimo zastavice kod kojih nijedna od dve najbliže rupe nije dovoljno blizu. Složenost je O(n log n + m log n).
C++ rešenje
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int m, n;
cin >> m;
vector<long long> zastavice(m);
for (int i = 0; i < m; i++) cin >> zastavice[i];
cin >> n;
vector<long long> rupe(n);
for (int i = 0; i < n; i++) cin >> rupe[i];
long long d;
cin >> d;
sort(rupe.begin(), rupe.end());
int preostalo = 0;
for (int i = 0; i < m; i++) {
long long z = zastavice[i];
bool uruseno = false;
// prva rupa koja nije levo od zastavice
auto it = lower_bound(rupe.begin(), rupe.end(), z);
if (it != rupe.end() && *it - z <= d) uruseno = true; // najbliža desno
if (it != rupe.begin() && z - *(it - 1) <= d) uruseno = true; // najbliža levo
if (!uruseno) preostalo++;
}
cout << preostalo << endl;
return 0;
}
Objašnjenje: Alternativa bez binarne pretrage: sortirati i zastavice i rupe pa ih obilaziti sa dva pokazivača.
Kviz: proveri šta si naučio
Deset kratkih pitanja o idejama iz zadataka na ovoj strani. Izaberi odgovor – odmah ćeš videti da li je tačan i zašto.
Koristimo kolačiće da bismo vam pružili najbolje moguće iskustvo. Takođe nam omogućavaju da analiziramo ponašanje korisnika kako bismo stalno poboljšavali veb lokaciju za vas.