Documente Academic
Documente Profesional
Documente Cultură
Olimpiada - cls6
2022-12
PROBLEME DE INFORMATICĂ
date la olimpiade
OJI + ONI
ı̂n
2022-12-27
Dedication
( in ascending order! )
1
https://www.femalefirst.co.uk/books/carol-lynne-fighter-1034048.html
2
https://otiliaromea.bandcamp.com/track/dor-de-el
3
https://en.wikipedia.org/wiki/To_be,_or_not_to_be
4
https://www.youtube.com/watch?v=eMtcDkSh7fU
ii
Prefaţă
Stilul acestor cărţi este ... ca şi cum aş vorbi cu nepoţii mei (şi chiar cu mine ı̂nsumi!) ... ı̂ncercând
ı̂mpreună să găsim o rezolvare cât mai bună pentru o problemă dată la olimpiadă.
Ideea, de a scrie aceste culegeri de probleme date la olimpiadele de informatică, a apărut acum
câţiva ani când am ı̂ntrebat un student (care nu reuşea să rezolve nişte probleme foarte simple):
”Ce te faci dacă un elev, care ştie că eşti student şi că studiezi şi informatică, te roagă, din când ı̂n
când, să-l ajuţi să rezolve câte o problemă de informatică dată la gimnaziu la olimpiadă, sau pur
şi simplu ca temă de casă, şi tu, aproape de fiecare dată, nu ı̂l poţi ajuta? Eu cred că nu este prea
bine şi poate că ... te faci ... de râs!” Pe vremea mea (!), când eram elev de gimnaziu, un student
era ca un fel de ... zeu! Cu trecerea anilor am ı̂nţeles că nu este chiar aşa! Şi ı̂ncă ceva: nu am
reuşit să ı̂nţeleg de ce, atunci când cineva nu poate să rezolve corect o problemă de informatică
de clasa a 6-a, dată la olimpiada de informatică sau ca temă de casă, foloseşte această scuză: ”eu
nu am făcut informatică ı̂n liceu!” şi acest cineva este ”zeul” sau ”zeiţa” despre care vorbeam!.
5
Sunt convins că este important să studiem cu atenţie cât mai multe probleme rezolvate! . Cred
că sunt utile şi primele versiuni ale acestor cărţi ... ı̂n care sunt prezentate numai enunţurile şi
indicaţiile ”oficiale” de rezolvare. Acestea se găsesc ı̂n multe locuri; aici ı̂ncerc să le pun pe ”toate
la un loc”! Fiecare urcă spre vârf ... cât poate! Sunt multe poteci care duc spre vârf iar această
carte este ... una dintre ele!
Limbajul de programare se alege ı̂n funcţie de problema pe care o avem de rezolvat. Cu nişte
ani ı̂n urmă alegerea era mai simplă: dacă era o problemă de calcul se alegea Fortran iar dacă era
o problemă de prelucrarea masivă a datelor atunci se alegea Cobol. Acum alegerea este ceva mai
6 7
dificilă! :-) Vezi, de exemplu, IOI2020 şi IOI2019 , IOI2015 .
Cred că, de cele mai multe ori, este foarte greu să gândim ”simplu” şi să nu ”ne complicăm”
atunci când cautăm o rezolvare pentru o problemă dată la olimpiadă. Acesta este motivul pentru
care vom analiza cu foarte mare atenţie atât exemplele date ı̂n enunţurile problemelor cât şi
”restricţiile” care apar acolo (ele sigur ”ascund” ceva interesant din punct de vedere al algoritmului
8
de rezolvare!) .
Am ı̂nceput câteva cărţi (pentru clasele de liceu) cu mai mulţi ani ı̂n urmă, pentru perioada
2000-2007 ([29] - [33]), cu anii ı̂n ordine crescătoare!). A urmat o pauză de câţiva ani (destul de
mulţi!). Am observat că acele cursuri s-au ”ı̂mprăştiat” un pic ”pe net” ([48] - [56])! Încerc acum
să ajung acolo unde am rămas ... plecând mereu din prezent ... până când nu va mai fi posibil ...
aşa că, de această dată, anii sunt ı̂n ordine ... descrescătoare! :-)
”Codurile sursă” sunt cele ”oficiale” (publicate pe site-urile olimpiadelor) sau publicate pe alte
site-uri (dacă mi s-a părut că sunt utile şi se poate ı̂nvăţa câte ceva din ele).
Pentru liceu perioada acoperită este de ”azi” (până când va exista acest ”azi” pentru mine!)
până ı̂n anul 2000 (aveam deja perioada 2000-2007!).
Pentru gimnaziu perioada acoperită este de ”azi” până ı̂n anul 2010 (nu am prea mult timp
9
disponibil şi, oricum, calculatoarele folosite la olimpiade ı̂nainte de 2010 erau ceva mai ’slabe’ şi
iii
11
depăşeşte pragul ”exascale”! (1.102 Exaflop/s). ”Peta” a fost depăşit ı̂n 2008, ”tera” ı̂n 1997,
12
”giga” ı̂n 1972. . Pentru ce a fost mai ı̂nainte, vezi https://en.wikipedia.org/wiki/Li
st_of_fastest_computers.
13
O mică observaţie: ı̂n 2017 a fost prima ediţie a olimpiadei EJOI ı̂n Bulgaria şi ... tot
14
ı̂n Bulgaria a fost şi prima ediţie a olimpiadei IOI ı̂n 1989. Dar ... prima ediţie a olimpiadei
15
IMO (International Mathematical Olympiad) a fost ı̂n România ı̂n 1959. Tot ı̂n România s-au
ţinut ediţiile din anii 1960, 1969, 1978, 1999 şi 2018. Prima ediţie a olimpiadei BOI (Balkan
Olympiad in Informatics) a fost ı̂n România ı̂n 1993 la Constanţa. Prima ediţie a olimpiadei
CEOI (Central-European Olympiad in Informatics) a fost ı̂n România ı̂n 1994 la Cluj-Napoca.
Revenind la ... “culegerile noastre” ... mai departe, probabil, va urma completarea unor
informaţii ı̂n ”Rezolvări detaliate” ... pentru unele probleme numai (tot din cauza lipsei timpului
necesar pentru toate!). Prioritate vor avea problemele de gimnaziu (nu pentru că sunt mai ’uşoare’
ci pentru că ... elevii de liceu se descurcă şi singuri!). Acum, ı̂n martie 2022, am ı̂nceput şi
redactarea unei culegeri de probleme date la bacalaureat ı̂n ultimii câţiva ani (câţi voi putea!).
Îmi aduc aminte că exista o interesantă vorbă de duh printre programatorii din generaţia mea:
”nu se trage cu tunul ı̂ntr-o muscă” . Sensul este: nu se scrie un cod complicat dacă se
poate scrie un cod simplu şi clar! Asta ı̂ncerc eu ı̂n ”Rezolvări detaliate”.
Vom ı̂ncerca, ı̂mpreună, şi câteva probleme de ... IOI ... dar asta este o treabă ... nu prea
uşoară! Cred totuşi că este mai bine să prezint numai enunţuri ale problemelor date la IOI ı̂n
ultimii câţiva ani! (asta aşa, ca să vedem cum sunt problemele la acest nivel!). Cei care ajung
acolo sau vor să ajungă acolo (la IOI) sigur nu au nevoie de ajutorul meu! Se descurcă singuri!
”ALGORITMI utili la olimpiadele de informatică”, separat pentru gimnaziu şi liceu, sper să
fie de folos, aşa cum cred că sunt [1] - [28], [34] - [47], [57] - [83], ... şi multe alte cărţi şi site-uri!.
Ar fi interesant să descoperim noi ı̂nşine cât mai mulţi algoritmi ... ı̂n loc să-i ı̂nvăţăm pur şi
simplu!
O altă mică observaţie: ce am strâns şi am scris ı̂n aceste cărţi
se adresează celor interesaţi de aceste teme! Nu cârcotaşilor! Sunt
evidente sursele ”de pe net” (şi locurile ı̂n care au fost folosite) aşa
că nu sunt necesare ”ghilimele anti-plagiat”, referinţe şi precizări
suplimentare la fiecare pas!
Şi un ultim gând: criticile şi sfaturile sunt utile dacă au valoare!
Dacă sunt numai aşa ... cum critică lumea la un meci de fotbal ...
sau cum, pe bancă ı̂n parc, ”ı̂şi dă cu părerea” despre rezolvarea
problemelor economice ale ţării ... atunci ... !!!
16
”I’m only responsible for what I say, not for what you understand.”
Adrese interesante (rezultatele elevilor români):
https://stats.ioinformatics.org/halloffame/
https://stats.ioinformatics.org/tasks/
http://stats.ioinformatics.org/results/ROU
Adresele acestor cursuri:
https://www.scribd.com/user/550183580/Adrian-Răbâea
https://www.scribd.com/user/552245048/Adi-Rabaea
https://drive.google.com/drive/folders/1hC5PZuslCdS95sl37SW46H-qy59GRDGZ
Adrese utile (programe şcolare):
http://programe.ise.ro/Portals/1/Curriculum/Progr_Lic/TH/Informatica_teoretic_vocatio
nal_intensiv_clasa%20a%20IX-a.pdf
http://programe.ise.ro/Portals/1/Curriculum/Progr_Lic/TH/Informatica_teoretic_vocatio
nal_intensiv_clasa%20a%20X_a.pdf
http://programe.ise.ro/Portals/1/Curriculum/Progr_Lic/TH/Informatica_teoretic_vocatio
nal_intensiv_clasa%20a%20XI-a.pdf
17
”I want to thank God most of all because without God I wouldn’t be able to do any of this.”
Adrian R.
17
I.d.k.: ”I don’t know who the author is.”
v
Despre autor
18
nume: Răbâea Aurel-Adrian, 18.03.1953 - ...
vi
Cuprins
Prefaţă iii
Cuprins vii
3 OJI 2020 21
3.1 forta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.2 furnica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
4 OJI 2019 41
4.1 album . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
4.2 maxim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
4.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
vii
4.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
4.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
5 OJI 2018 63
5.1 numere - OJI 2018 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
5.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
5.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
5.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
5.2 turnuri - OJI 2018 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
5.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
5.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
5.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
6 OJI 2017 83
6.1 accesibil - OJI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
6.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
6.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
6.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
6.2 fermier - OJI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
6.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
6.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
6.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
Index 398
Bibliografie 399
2.1 formula1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Cazul 1, transformare a tuturor elmentelor din i1 ; i2 ı̂n 1 . . . . . . . . . . . . . . 13
2.3 Cazul 2, transformare a zerourilor din i1 2; i2 2 ı̂n 1 . . . . . . . . . . . . . . 14
2.4 Cazul 3, transformare a zerourilor din i1 ; i2 2 ı̂n 1 . . . . . . . . . . . . . . . . 14
2.5 Cazul 4, transformare a zerourilor din i1 2; i2 ı̂n 1 . . . . . . . . . . . . . . . . 14
5.1 Turnuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
5.2 Turnuri - exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
6.1 fermier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
xiii
22.1 betisoare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
22.2 praslea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
22.3 praslea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
22.4 tinta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
22.5 tinta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
xvi
Lista programelor
xvii
6.1.3 accesibil3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
6.1.4 accesibil4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
6.1.5 accesibil5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
6.2.1 fermier1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
6.2.2 fermier2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
6.2.3 fermier3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
6.2.4 fermier4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.2.5 fermier5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
7.1.1 cifre.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
7.2.1 litere.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
8.1.1 CPP SursaOficialaCovor.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
8.1.2 covor CarmenMinca.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
8.1.3 covor CristinaIordaiche.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
8.1.4 covor CristinaSichim.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
8.1.5 covor FloreUngureanu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
8.1.6 covor LilianaChira.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
8.1.7 covor RoxanaTamplaru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
8.2.1 CPP SursaOficialaOrdine.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
8.2.2 ordine CarmenMinca.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
8.2.3 ordine CristinaIordaiche.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
8.2.4 ordine CristinaSichim.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
8.2.5 ordine FloreUngureanu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
8.2.6 ordine GinaBalacea.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
8.2.7 ordine LilianaChira.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
8.2.8 ordine MarinelSerban.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
8.2.9 ordine RoxanaTamplaru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
9.1.1 imprimanta cristina 0.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
9.1.2 imprimanta cristina 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
9.1.3 imprimanta lili.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
9.1.4 imprimanta marinel.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
9.1.5 imprimanta mot.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
9.1.6 imprimanta ovidiu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
9.2.1 munte csifo.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
9.2.2 munte lili0.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
9.2.3 munte lili1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
9.2.4 munte marinel 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
9.2.5 munte marinel 2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
9.2.6 munte ovidiu 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
9.2.7 munte ovidiu 2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
9.2.8 munte roxana1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
9.2.9 munte roxana2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
10.1.1cladiri S9cif.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
10.1.2cladiridl.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
10.1.3cladiriMN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
10.1.4cladiristream.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
10.1.5Cristina cladiri.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
10.1.6Ovidiu cladiri cu vector.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
10.1.7Ovidiu cladiri fara vector.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
10.2.1galbeni.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
10.2.2galbeni dt.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
10.2.3galbeniBrut.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
10.2.4galbenidl.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
11.1.1 flori.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
11.1.2 flori dana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
11.2.1 sol-cifru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
12.1.1 CARTE CI.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
12.1.2 CARTE CS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
12.1.3 CARTE LU.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
12.1.4 CARTE OM.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
12.2.1 GRAD.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
12.2.2 GRAD CR.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
12.2.3 GRAD IC.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
12.2.4 GRAD OM.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
12.2.5 GRADFSLAB.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
12.2.6 GRADSLAB.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
13.1.1 6 pr1 s.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
13.2.1 6 pr2 s.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
17.1.1 maya100Adi.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
17.1.2 maya100PLV.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
17.2.1 optimeFBB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
17.2.2 optimePLV.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
17.2.3 optimeVMG.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
17.3.1 roata100FB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
17.3.2 roata100PLV.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
17.3.3 roata100RP.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
18.1.1 descmult.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
18.1.2 descmult algopedia.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
18.2.1 gazon algopedia.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
19.1.1 faleza CristinaI.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
19.1.2 faleza Flavius.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
19.1.3 falezaFB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
19.1.4 falezaMA.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
19.1.5 falezaMN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
19.1.6 RTfaleza nou.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
19.2.1 Marinel peste string.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
19.2.2 Marius peste.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
19.2.3 peste.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
19.2.4 peste Flavius.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
19.2.5 peste int.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
19.2.6 peste Miana 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
19.2.7 peste MS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
19.2.8 peste MS ok2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
19.2.9 pesteMN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
19.2.10 RTpeste100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
19.3.1 RTsoricel100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
19.3.2 soricel flavius.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
19.3.3 soricel Miana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
19.3.4 soricelFB2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
19.3.5 soricelMN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
20.1.1 cod cpp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
20.2.1 perm cpp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
20.3.1 robotel cpp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
21.1.1 echer.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
21.1.2 echerCarmenMinca.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
21.1.3 echerCristinaSichim.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
21.1.4 echerFlorentinaUngureanu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
21.1.5 echerGinaBalacea.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
21.1.6 echerRoxanaTimplaru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
21.2.1 lightbot.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
21.2.2 lightbotCarmenMinca.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
21.2.3 lightbotCristinaSichim.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
21.2.4 lightbotFlorentinaUngureanu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
21.2.5 lightbotLiliChira.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
21.2.6 lightbotRoxanaTimplaru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
21.3.1 terenCarmenMinca.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
21.3.2 terenCristinaSichim.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
21.3.3 terenGinaBalacea.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
21.3.4 terenMarinelSerban.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
21.3.5 terenRoxanaTimplaru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
22.1.1 betisoare OK.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
22.1.2 betisoare CristinaI.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
22.1.3 betisoare nistor.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
22.1.4 betisoare ovidiu 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
22.1.5 betisoare ovidiu 2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
22.1.6 betisoare ovidiu 3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
22.1.7 betisoare r.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
22.1.8 betisoare sanda.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
22.1.9 betisoare strtok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
22.1.10 sursa1 Lili.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
22.1.11 sursa2 Lili.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
22.1.12 sursa3 Lili.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
22.2.1 praslea.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
22.2.2 praslea Cristina quicksort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
22.2.3 praslea Cristina sortare simpla.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 313
22.2.4 praslea Lili.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
22.2.5 praslea marinel.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
22.2.6 praslea mot.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
22.2.7 praslea ovidiu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
22.2.8 praslea roxana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
22.2.9 praslea roxana1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
22.2.10 praslea sanda.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
22.3.1 tinta.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
22.3.2 tinta marinel 4M.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
22.3.3 tinta marinel 8M.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
22.3.4 tinta roxana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
24.1.1 cartier.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
24.2.1 medalion.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
24.3.1 numar.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
25.1.1 joc100 cm.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
25.1.2 joc100p cs.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
25.1.3 JOC100p om.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
25.2.1 t cs.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
25.3.1 XY.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
25.3.2 XY 1.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
25.3.3 XY 2.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
26.1.1 control.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
26.2.1 FIGURA.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
26.3.1 JOC EM.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
26.3.2 joc liliana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
B.4.1exponentiere rapida1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
B.4.2exponentiere rapida2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
B.4.3exponentiere rapida3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394
B.4.4exponentiere rapida MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394
B.5.1exponentiere naiva MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
B.5.2exponentiere rapida MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
B.6.1secventa cod.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
Part I
1
Capitolul 1
OJI 2022
1.1 Cmmdc
Problema 1 - Cmmdc 100 de puncte
Se dă un şir a1 , a2 , ..., an de numere naturale nenule.
Cerinţe
Date de intrare
Fişierul de intrare cmmdc.in conţine pe prima linie un număr natural T reprezentând cerinţa
cerută (1, 2, sau 3), pe a doua linie se află numărul natural nenul n, iar de pe următoarele n linii
se găsesc, câte un număr pe fiecare linie, cele n elemente ale şirului.
Date de ieşire
a 2 & ai & 263 - 1 oricare 1 & i & n (numerele sunt de tip long long)
# Punctaj Restrictii
1 16 T = 1, 3 & n & 100 000 şi ai & 50 000 000, pentru 1 & i & n
2 20 T = 1 şi 3 & n & 100 000
3 21 T = 2 şi 3 & n & 3 000
4 21 T = 2 şi 3 & n & 100 000
5 12 T = 3 şi 3 & n & 300
6 10 T = 3 şi 3 & n & 2 000
Exemple:
2
CAPITOLUL 1. OJI 2022 1.1. CMMDC 3
3
Complexitatea temporală este O n log2 max.
Pentru rezolvarea brută a celei de-a doua cerinţe, se pot obţine 10 puncte.
Soluţie optimă. Pentru a putea face calculele mai uşor, e bine să ştim faptul că
cmmdc x, 0 x, pentru orice număr natural x.
Trebuie să aflăm cmmdc-ul maxim dacă se elimină exact două elemente ale şirului.
Fie ai şi aj elementele pe care le eliminăm, unde i $ j. Ne vor trebui atunci valorile lui
cmmdc a1 , a2 , ..., ai1 , lui cmmdc ai1 , ..., aj 1 şi lui cmmdc aj 1 , ..., an .
Ştim ı̂nsă că cmmdc a1 , a2 , ..., ai1 sti1 , iar cmmdc aj 1 , ..., an drj 1 .
Mai trebuie să aflăm c cmmdc ai1 , ..., aj 1 ı̂n mod eficient.
Parcurgem şirul de la primul până la penultimul element şi pentru fiecare ai , 1 & i & n 1:
plecăm cu c 0
parcurgem cu j secvenţa ai1 , ai2 , ..., an
când j i 1, atunci c 0
când j i 2, atunci c cmmdc c, ai1
când j i 3, atunci c cmmdc c, ai2
. . .
la un pas oarecare j, c cmmdc c, aj 1
La fiecare pas j se actualizează valoarea maximă obţinută din eliminarea lui ai şi aj :
1.2 Vecine
Problema 2 - Vecine 100 de puncte
Se dă un şir de n cifre c1 , c2 , ..., cn , adică 0 & ci & 9. Dintr-un şir de cifre se poate obţine un
şir de 1 & m & n numere a1 , a2 , ..., am astfel:
Iniţial considerăm fiecare cifră un număr şi obţinem şirul de n numere ai ci
Un număr nou poate fi obţinut prin lipirea unei secvenţe de două sau mai multe numere
vecine din şirul original. Două elemente dintr-un şir se numesc vecine dacă acestea se regăsesc
ı̂n şir pe poziţii alăturate.
Operaţia de lipire de două sau mai multe numere se poate realiza de oricâte ori atât timp
cât numărul obţinut este mai mic sau egal cu 2 000 000 000, nu ı̂ncepe cu cifra 0 şi există
cel puţin două numere ı̂n şir.
De exemplu şirul [3, 5, 0, 2, 7, 3] poate deveni [35, 0, 2, 73] prin lipirea numerelor 3, 5
35 şi 7, 3 73, care ulterior poate deveni [3502, 73] prin lipirea numerelor 35, 0, 2 3502.
Dar nu putem crea şirul [35, 02, 73], deoarece am avea un număr care ı̂ncepe cu 0.
Două numere vecine sunt consecutive dacă primul este cu 1 mai mic decât al doilea.
Cerinţe
Date de intrare
Fişierul de intrare vecine.in conţine pe prima linie două numere p şi n, p reprezentând cerinţa
1 sau 2, iar pe linia următoare cele n cifre, despărţite prin câte un spaţiu.
CAPITOLUL 1. OJI 2022 1.2. VECINE 5
Date de ieşire
În fişierul de ieşire vecine.out se va afla un singur număr natural. Dacă p 1, acesta va reprezenta
răspunsul pentru cerinţa 1. Dacă p 2, acesta va reprezenta răspunsul pentru cerinţa 2.
a Pentru cerinţa 2 se garantează că numerele ce se pot obţine nu vor depăşi 2 000 000 000
a Tot pentru cerinţa 2 se garantează existenţa a cel puţin o pereche de numere vecine consecutive
a Cifra 0 poate forma singură doar numărul 0.
a Două numere vecine sunt consecutive dacă primul este cu 1 mai mic decât al doilea.
# Punctaj Restricţii
1 20 p = 1 şi 3 & n & 100 000
2 80 p = 2 şi 3 & n & 100 000
Exemple:
vecine.in vecine.out
1 18 2
321210630563069293
2 18 6305
321210630563069293
Explicaţii:
Pentru primul exemplu:
[3, 2, 1, 2, 1, 0, 6, 3, 0, 5, 6, 3, 0, 6, 9, 2, 9, 3]
Există două perechi de numere vecine consecutive formate dintr-o singură cifră: 1, 2 şi 5, 6.
Pentru cel de-al doilea exemplu putem lipi următoarele secvenţe:
[3, 2, 1, 2, 1, 0, 6, 3, 0, 5, 6, 3, 0, 6, 9, 2, 9, 3] [3, 2, 1, 2, 1, 0, 6305, 6306, 9, 2, 9, 3]
Perechea cu cele mai mari două numere vecine consecutive este 6305 şi 6306. Conform cerinţei
s-a scris ı̂n fişier doar primul număr din pereche.
2.1 Formula1
Problema 1 - Formula1 100 de puncte
La o cursă de Formula 1, fiecare echipă participantă ı̂şi construieşte propria maşină cu care
va concura. Numerotarea maşinilor ı̂n concurs este realizată de organizatori, cu ajutorul unor
steguleţe pătrate ce conţin alternativ, pe fiecare rând (pe orizontală şi verticală), pătrăţele albe şi
negre de dimensiuni identice.
În figura următoare sunt prezentate, ı̂n ordine, steguleţele primelor 4 maşini din concurs.
Observăm că fiecare steguleţ are cu două rânduri (pe orizontală şi verticală) mai mult decât
steguleţul precedent iar ı̂n toate cele patru colţuri ale oricărui steguleţ se află un pătrăţel negru.
Cerinţe
Scrieţi un program care citeşte două numere naturale K şi N şi determină:
1. Câte pătrăţele albe şi negre ı̂n total sunt pe steguleţul maşinii cu numărul K;
2. Notând cu A numărul total de pătrăţele albe de pe steguleţele primelor N maşini din concurs,
câte pătrăţele albe şi negre ı̂n total sunt pe cel mai mare steguleţ care conţine cel mult A
pătrăţele albe.
Date de intrare
Fişierul de intrare formula1.in conţine pe prima linie un număr natural C. Pentru toate
testele de intrare, numărul C poate avea doar valoarea 1 sau valoarea 2 şi reprezintă numărul
cerinţei care trebuie rezolvată.
Pe a doua linie a fişierului formula1.in se găsesc, ı̂n ordine, numerele naturale K şi N .
Date de ieşire
Dacă C 1, se va rezolva cerinţa 1. În acest caz, fşierul de ieşire formula1.out va conţine
pe prima linie un număr natural reprezentând numărul total de pătrăţele existente pe steguleţul
maşinii cu numărul K.
Dacă C 2, se va rezolva cerinţa 2. În acest caz, fişierul de ieşire formula1.out va conţine pe
prima linie un număr natural reprezentând numărul total de pătrăţele existente pe cel mai mare
steguleţ ce conţine cel mult A pătrăţele albe.
7
CAPITOLUL 2. OJI 2021 - OSEPI 2.1. FORMULA1 8
Exemple:
2 2 2 2
A 21 2 1 2 2 2 2 2 3 2 3 ... 2 N 2 N (2.1.2)
2 2 2 2
A 2 1 2 3 ... N 2 1 2 3 N (2.1.3)
Ne folosim de căutarea binară pentru a găsi ı̂n timp logaritmic cea mai mare valoare impară
x care respectă 2x 2x & A. ( scor obţinut:100 de puncte)
2
Ó
Putem calcula şi formulă directă: x int 2 A 1. Totuşi, conform enunţului, lungimea
unui steguleţ trebuie să fie impară. Din acest motiv, dacă x-ul returnat este par, atunci
trebuie să ı̂l decrementăm: x x 1. ( scor obţinut: 100 de puncte)
CAPITOLUL 2. OJI 2021 - OSEPI 2.1. FORMULA1 9
Obs: https://ebooks.infobits.ro/culegere_OJI_2021.pdf
69 a=a+2;
70 }
71 a=a-2;
72 fout<<a*a;
73 }
74
75 void cerinta2_formula()
76 {
77 long long s,a,i,x;
78 s=0;
79 a=1;
80 for(i=1;i<=n;i++)
81 {
82 x=a*a/2;
83 s=s+x;
84 a=a+2;
85 }
86 x=sqrt(2*s+1);
87 if(x%2==0) x--;
88 fout<<x*x;
89 }
90
91 int main()
92 {
93 int c;
94 fin>>c>>k>>n;
95 if(c==1)
96 cerinta_1();
97 else
98 {
99 //cerinta_2();
100 cerinta2_formula();
101 }
102 return 0;
103 }
57 Task_2();
58 return;
59 }
60
61 int main()
62 {
63 Read();
64 Solve();
65 return 0;
66 }
2.2 Seism
Problema 2 - Seism 100 de puncte
Cercetătorii de la NASA au instalat pe Marte un seismograf cu ajutorul căruia s-au ı̂nregistrat
mişcările la nivelul solului planetei.
Seismograful a trimis ı̂n fiecare din cele N secunde ce definesc perioada de timp analizată, câte
un semnal pe Pământ ce a fost codificat de cercetători cu valoarea 1, dacă seismograful a detectat
mişcare şi 0, ı̂n cazul ı̂n care nu s-a ı̂nregistrat mişcare la nivelul solului planetei.
Astfel, un seism de pe Marte a fost definit de cercetători ca fiind o perioadă continuă de timp
ı̂n care seismograful a trimis, din secundă ı̂n secundă, câte un semnal codificat cu 1 şi care ı̂ncepe
după cel puţin două semnale codificate cu 0, iar la sfârş itul ei sunt ı̂nregistrate cel puţin două
semnale codificate cu 0.
Cerinţe
Cunoscând şirul celor N valori transmise ı̂n ordine de seismograf, scrieţi un program care să
determine:
1. Care a fost durata maximă, exprimată ı̂n secunde a unui seism;
2. Câte seisme au avut loc ı̂n perioada de timp analizată;
3. Din cauza unei erori tehnice, o perioadă continuă de timp seismograful a transmis eronat.
Astfel, ı̂n şirul iniţial format din cele N semnale, trebuie să ı̂nlocuim valoarea 0 cu valoarea
1, ı̂ntr-o singură secvenţă, de lungime nevidă, de elemente nule alăturate. Analizând toate
posibilităţile de a face această modificare, determinaţi durata maximă a unui seism care se
obţine după modificarea şirului iniţial de semnale.
Date de intrare
Fişierul de intrare seism.in conţine pe prima linie, un număr natural C care poate avea valorile
1, 2 sau 3 şi reprezintă numărul cerinţei. Pe cea de-a doua linie, un număr natural N având
semnificaţia din enunţ. Pe următoarea linie, N numere naturale despărţite prin câte un spaţiu,
reprezentând codificarea semnalului transmis de seismograf, din secundă ı̂n secundă, ı̂ncepând cu
secunda 1 şi până la secunda N .
Date de ieşire
Fişierul de ieşire seism.out va conţine pe prima linie un singur număr natural, reprezentând
rezultatul determinat conform cerinţei.
La cerinţa 3 se garantează că există cel puţin o secvenţa nevidă de elemente egale cu 0 ce
pot fi schimbate ı̂n 1 pentru a avea cel puţin un seism ı̂n tot şirul.
Pentru rezolvarea corectă a primei cerinţe se obţin 40 de puncte, pentru rezolvarea corectă
a celei de a doua cerinţe se obţin 40 de puncte, iar pentru rezolvarea corectă a celei de a
treia cerinţe se obţin 20 de puncte.
Exemple:
a Cazul 2 ı̂nlocuim numai zerourile din intervalul i1 2; i2 2 ca ı̂n Figura 2.3. Această
construcţie are sens doar dacă i2 i1 ' 4. Acest seims are durata de i2 i1 3 secunde.
a Cazul 3 ı̂nlocuim zerourile din intervalul i1 ; i2 2 ca ı̂n Figura 2.4. Această construcţie
are sens doar dacă i2 i1 ' 2. Apoi ne extindem la stânga până la poziţia j1 , atâta timp cât
trecem numai prin valori de 1. Dacă v j1 1 0 şi v j1 2 0, atunci seismul j1 ; i2 2 este
valid şi trebuie să ı̂i verificăm lungimea.
a Cazul 4 foarte similar cu precedentul caz: ı̂nlocuim zerourile din intervalul i1 2; i2 . Apoi
trebuie să ne extindem la dreapta până la poziţia j2 şi verificăm dacă v j2 1 0 şi v j2 2 0;
Figura 2.5
Obs: https://ebooks.infobits.ro/culegere_OJI_2021.pdf
20 fin>>v[i];
21 if (C==1 || C==2)
22 {
23 i=1;
24 while(v[i]) //sar peste elementele nenule de la inceput
25 i++; //deoarece nu au 0 in stanga
26 while(i<=N-2)
27 {
28 while(v[i]==0&&i<=N-2) //sar peste 0
29 i++;
30 incep_seism=i;
31 while(v[i]&&i<=N-2) //secventa cu elemente nenule
32 i++;
33 sf_seism=i-1;
34 if(incep_seism-2>=1 && v[incep_seism-1]==0 && v[incep_seism-2]==0)
35 if(v[sf_seism+1]==0 && v[sf_seism+2]==0 && sf_seism+2<=N)
36 // E seism incadrat stanga dreapta de cate 2 zerouri
37 {
38 cate_seisme++;
39 durata_seism=sf_seism-incep_seism+1;
40 if(durata_seism>durata_max)
41 durata_max=durata_seism;
42 }
43 i++;
44 }
45
46 if (C==1)
47 fout<<durata_max<<’\n’;
48 else
49 if(C==2)
50 fout<<cate_seisme<<’\n’;
51 }
52 else //if(C==3)
53 {
54 int incep_secv0,sf_secv0,k1,k2,durata_seism=0,durata_max=0;
55 i=1;
56 while(v[i]) i++;//SAR peste elementele egale cu 1 de la n c e p u t
57 while(i<=N-2)
58 {
59 if(i!=1)
60 incep_secv0=i;
61 else
62 incep_secv0=3;
63 while(v[i]==0 && i<=N-2) i++;//secventa de 0
64 sf_secv0=i-1;
65 for(int j=incep_secv0; j<=sf_secv0; j++)
66 v[j]=1;//schimb fiecare secventa de 0 in 1
67 if( sf_secv0-incep_secv0>=5)
68 // tratez cazul in care fac seism in interiorul unei secvente de 0
69 {
70 //if(i==N)
71 durata_seism=(sf_secv0-incep_secv0+1)-4;
72 if (durata_seism>durata_max)
73 durata_max=durata_seism;
74 }
75 // recalculez lungimea seismului din acest moment adica ma duc
76 // stanga-dreapta
77 durata_seism=sf_secv0-incep_secv0+1;
78 k1=incep_secv0-1;
79 while(v[k1] &&k1>=3) k1--;
80 k1++;
81 k2=sf_secv0+1;
82 while(v[k2]&& k2<=N-2) k2++;
83 k2--;
84 if(k1-2>=1 && k2+2<=N)
85 if(v[k1-1]==0 && v[k1-2]==0 && v[k2+1]==0 && v[k2+2]==0)
86 //verific daca are in stanga si dreapta cate 2 de 0
87 {
88 durata_seism=k2-k1+1;
89 if( durata_seism>durata_max)
90 durata_max=durata_seism;
91 }
92 // refac secventa de 0
93 for(int j=incep_secv0; j<=sf_secv0; j++)
94 v[j]=0;
95 while(v[i] &&i<=N-2) i++;
CAPITOLUL 2. OJI 2021 - OSEPI 2.2. SEISM 16
96 }
97 fout<<durata_max<<’\n’;
98 }
99 return 0;
100 }
68 if(V[i] > 0)
69 if((-V[i - 1]) > 1 && (-V[i + 1]) > 1)
70 ans_1 = my_max(ans_1, V[i]);
71 g << ans_1 << ’\n’;
72 return;
73 }
74
75 void Task_2 ()
76 {
77 ans_2 = 0;
78 for(int i = 2; i < M; ++i)
79 if(V[i] > 0)
80 if((-V[i - 1]) > 1 && (-V[i + 1]) > 1)
81 ++ans_2;
82 g << ans_2 << ’\n’;
83 return;
84 }
85
86 void Task_3 ()
87 {
88 ans_3 = 0;
89 ///creez un seism intr-o secventa de 0 de lungime > 4
90 for(int i = 1; i <= M; ++i)
91 if(V[i] < 0 && my_abs(V[i]) > 4)
92 ans_3 = my_max(ans_3, my_abs(V[i]) - 4);
93 /// unesc 2 secvente de 1
94 for(int i = 3; i <= (M - 2); ++i)
95 if(V[i] < 0)
96 {
97 if(my_abs(V[i - 2]) > 1 && my_abs(V[i + 2]) > 1)
98 ans_3 = my_max(ans_3, V[i - 1] + my_abs(V[i]) + V[i + 1]);
99 }
100 /// extindem durata seismului spre stanga
101 for(int i = 3; i <= M; ++i)
102 if(V[i] < 0)
103 {
104 if(my_abs(V[i - 2]) > 1 && my_abs(V[i]) > 2)
105 ans_3 = my_max(ans_3, V[i - 1] + my_abs(V[i]) - 2);
106 }
107 /// extindem durata seismului spre dreapta
108 for(int i = 1; i <= (M - 2); ++i)
109 if(V[i] < 0)
110 {
111 if(my_abs(V[i + 2]) > 1 && my_abs(V[i]) > 2)
112 ans_3 = my_max(ans_3, V[i + 1] + my_abs(V[i]) - 2);
113 }
114 g << ans_3 << ’\n’;
115 return;
116 }
117
118 void Solve ()
119 {
120 Load();
121 if(P == 1)
122 Task_1();
123 else
124 if(P == 2)
125 Task_2();
126 else
127 Task_3();
128 return;
129 }
130
131 int main ()
132 {
133 Read();
134 Solve();
135 return 0;
136 }
4 #include <fstream>
5
6 using namespace std;
7
8 ifstream fin("seism.in");
9 ofstream fout("seism.out");
10
11 int c,x,nrz1,nrunu,nrz2,k,i,maxi,maxi1,n,nru, a1,a2,b1,b2,a3,a4,b3,b4;
12
13 void cerinte()
14 {
15 fin >> n ;
16 i = 0;
17 while(i < n )
18 {
19 fin >> x;
20 i++;
21 if (x == 0)
22 nrz1++;
23 else
24 break;
25 }
26 if (nrz1>4)
27 maxi1=nrz1-4;
28 while(i < n)
29 {
30 nrunu=1;
31 while(i < n)
32 {
33 fin >> x;
34 i++;
35 if (x == 1)
36 nrunu++;
37 else
38 break;
39 }
40 nru++;
41 nrz2=1;
42 while(i < n)
43 {
44 fin >> x;
45 i++;
46 if (x == 0) nrz2++;
47 else break;
48 }
49 if (nru % 2 == 1)
50 {
51 a1=nru;
52 a2=nrunu;
53 a3=nrz1;
54 a4=nrz2;
55 }
56 else
57 {
58 b1=nru;
59 b2=nrunu;
60 b3=nrz1;
61 b4=nrz2;
62 }
63 if (nrz1 >= 2 && nrz2 >= 2)
64 {
65 maxi=max(maxi,nrunu);
66 maxi1=max(maxi1,nrunu);
67 k++;
68 if(nrz1>nrz2)
69 nrunu += nrz1-2;
70 else
71 nrunu += nrz2-2;
72 maxi1 = max(maxi1,nrunu);
73 }
74 if (b1-a1 == 1 && a3>=2 && b4>=2)
75 maxi1=max(maxi1, b2+a2+b3);
76 else
77 if (a1-b1 == 1 && b3>=2 && a4>=2)
78 maxi1=max(maxi1,a2+b2+a3);
79 if (nrz2>4)
CAPITOLUL 2. OJI 2021 - OSEPI 2.2. SEISM 19
55 {
56 ans3 = max(ans3, i - pos1 - 1);
57 ans3 = max(ans3, last1 + pos1 - pos2 - last2 - 2);
58 }
59 if (pos2 > 0 && !v[pos2 - 1] && !v[pos2 - 2])
60 ans3 = max(ans3, pos1 - pos2 + last1);
61 }
62 }
63 if (c == 1) printf("%d", ans1);
64 else
65 if (c == 2) printf("%d", ans2);
66 else printf("%d", ans3);
67 return 0;
68 }
OJI 2020
3.1 forta
Problema 1 - forta 100 de puncte
Forţa unui număr natural nenul X este egală cu numărul de divizori pozitivi ai lui X. De
exemplu, numărul X 10 are forţa 4, deoarece 10 are 4 divizori, mulţimea divizorilor fiind
D10 r1, 2, 5, 10x.
Cerinţe
Scrieţi un program care, cunoscând un şir de n numere naturale nenule, rezolvă următoarele
cerinţe:
1. determină cel mai mic număr din şir care are forţa maximă;
2. determină lungimea maximă a unei secvenţe formată din numere cu aceeaşi forţă ce poate
fi obţinută prin rearanjarea convenabilă a elementelor din şir.
Date de intrare
Fişierul de intrare forta.in conţine pe prima linie c, care reprezintă cerinţa de rezolvat (1 sau
2), pe a doua linie un număr natural n, iar pe următoarea linie n numere naturale separate prin
câte un spaţiu, reprezentând elementele şirului.
Date de ieşire
Fişierul de ieşire forta.out va conţine o singură linie pe care va fi scris un număr natural
reprezentând răspunsul la cerinţa c.
Exemple:
21
CAPITOLUL 3. OJI 2020 3.1. FORTA 22
Pentru rezolvarea problemei trebuie mai ı̂ntâi să determinăm numărul de divizori pozitivi pe
care ı̂i are un număr X din şir. Acest lucru poate fi făcut ı̂n mai multe moduri:
În funcţie de modalitatea aleasă pentru numărarea divizorilor punctajul poate varia ı̂ntre 20
şi 90 de puncte.
Pentru rezolvarea cerinţelor:
1. Determinăm maximul dintre numărul divizorilor numerelor din şir şi care este cel mai mic
număr care are acest număr maxim de divizori
2. O soluţie posibilă utilizează un vector de numărare (de frecvenţă) pentru a contoriza pentru
fiecare forţă posibilă câte numere din şir au această forţă. Apoi identificăm maximul din vectorul
de frecvenţă.
20 {
21 int k = 1, p, d = 1; //folosesc formula d = (p1+1)(p2+1)...(pk+1)
22 while (P[k] * P[k] <= n) //unde p1 p2...pk sunt puterile factorilor primi
23 { //din descompunere
24 p = 0; //initializez puterea
25 while (n % P[k] == 0) //cat timp se divide cu numarul prim P[k]
26 {
27 n /= P[k]; //imparte
28 p++; //numara
29 }
30 d = d * (p + 1); //formula
31 k++; //trec la alt numar prim
32 }
33 if(n > 1) //daca a mai ramas ceva din n => este numar prim
34 d = d * 2; //deci d se inmulteste cu (1+1) = 2
35 return d; //returnez numarul de divizori
36 }
37
38 void ciur()
39 {
40 int i, j; //pentru determinarea numarului de divizori
41 C[0] = C[1] = 1; //voi folosi DOAR numere prime impare
42 for (i = 2; i < 45001; i ++) //suficient 45001 deoarece
43 if (C[i] == 0) //45000 * 45000 = 2025000000 > 2000000000
44 { //am un numar prim
45 m++; //il numar si
46 P[m] = i; //il salvez apoi elimin multipli
47 for (j = i * i; j < 45001; j += i)
48 C[j] = 1;
49 }
50 }
51
52 int main()
53 {
54 fin = fopen("forta.in", "r");
55 fout = fopen("forta.out", "w");
56 fscanf(fin, "%d", &cerinta); //citire cerinta si
57 fscanf(fin, "%d", &n); //numarul de numere
58 ciur(); //construiesc sirul numerelor prime
59 for (i = 1; i <= n; i++) //iau pe rand cele n numere
60 {
61 fscanf(fin, "%d", &X); //citesc numarul
62 divi[i].nrdiv = nrD(X); //calculez si retin numarul de divizori
63 divi[i].X = X; //retin si numarul
64 F[divi[i].nrdiv]++; //contorizez nr de aparitii a nr de divizori
65 if (F[divi[i].nrdiv] > Fmax) //determin numarul maxim de aparitii
66 Fmax = F[divi[i].nrdiv];
67 if (divi[i].nrdiv > Pmax) //determin si numarul maxim de divizori
68 {
69 Pmax = divi[i].nrdiv; //retin
70 nr_max = X; //retin si pentru cine este acesta
71 }
72 else
73 if (divi[i].nrdiv == Pmax) //in caz de egalitate
74 {
75 if (X < nr_max) //caut numarul mai mic
76 nr_max = X;
77 }
78 }
79 if (cerinta == 1)
80 fprintf(fout, "%d\n", nr_max); //afisez cerinta 1
81 else
82 fprintf(fout, "%d\n", Fmax); //afisez cerinta 2
83 return 0;
84 }
8 ofstream fout("forta.out");
9
10 int n,maxx=200004,viz[200004],prime[200004],k;
11 pair<int,int> v[100004];
12
13 void ciur()
14 {
15 for(int i=2;i<=maxx;i++)
16 if(viz[i]==0)
17 {
18 prime[++k]=i;
19 for(int j=i;j<=maxx;j+=i)
20 viz[j]=1;
21 }
22 }
23
24 int main()
25 {
26 ciur();
27 int cerinta;
28 fin>>cerinta>>n;
29 for(int i=1;i<=n;i++)
30 {
31 int x;
32 fin>>x;
33 v[i].first=x;
34 int putere=1;
35 for(int j=1;j<=k && prime[j]*prime[j]<=x;j++)
36 {
37 int d=0;
38 while(x%prime[j]==0)
39 {
40 d++;
41 x/=prime[j];
42 }
43 if(d>0)
44 putere*=d+1;
45
46 }
47 if(x>1)
48 putere*=2;
49 v[i].second=putere;
50
51 }
52 if(cerinta==1)
53 {
54
55 int putmax=0;
56 int min1=INT_MAX;
57 for(int i=1;i<=n;i++)
58 {
59 if(v[i].second>putmax)
60 {
61 putmax=v[i].second;
62 min1=v[i].first;
63 }
64 if(v[i].second==putmax && min1>v[i].first)
65 min1=v[i].first;
66
67 }
68 fout<<min1;
69
70 }
71 else
72 {
73 int sol=0,aparente[100000];
74 for(int i=1;i<=n;i++)
75 {
76 aparente[v[i].second]++;
77 if(aparente[v[i].second]>sol)
78 sol=aparente[v[i].second];
79 }
80 fout<<sol;
81 }
82 fout<<’\n’;
83 return 0;
CAPITOLUL 3. OJI 2020 3.1. FORTA 25
84 }
58 {
59 fin >> cerinta; //citire cerinta si
60 assert(cerinta == 1 || cerinta == 2);
61 fin >> n; //numarul de numere
62 assert(n >= 1 && n <= 100000);
63 ciur(); //construiesc sirul numerelor prime
64 for (i = 1; i <= n; i++) //iau pe rand cele n numere
65 {
66 fin >> X; //citesc numarul
67 assert(X >= 1 && X <= 2000000000);
68 divi[i].nrdiv = nrD(X); //calculez si retin numarul de divizori
69 divi[i].X = X; //retin si numarul
70 F[divi[i].nrdiv]++; //contorizez nr de aparitii a nr de divizori
71 if (F[divi[i].nrdiv] > Fmax) //determin numarul maxim de aparitii
72 Fmax = F[divi[i].nrdiv];
73 if (divi[i].nrdiv > Pmax) //determin si numarul maxim de divizori
74 {
75 Pmax = divi[i].nrdiv; //retin
76 nr_max = X; //retin si pentru cine este acesta
77 }
78 else
79 if (divi[i].nrdiv == Pmax) //in caz de egalitate
80 {
81 if (X < nr_max) //caut numarul mai mic
82 nr_max = X;
83 }
84 }
85 if (cerinta == 1)
86 fout << nr_max << ’\n’; //afisez cerinta 1
87 else
88 fout << Fmax << ’\n’; //afisez cerinta 2
89 return 0;
90 }
40 f>>C;
41 if(C==1)
42 {
43 int n, i, x, k, pMax=0, nrMin=0;
44 f>>n;
45 for(i=1; i<=n; i++)
46 {
47 f>>x;
48 k=nrDiv(x);
49 if(k>pMax)pMax=k, nrMin=x;
50 else if(k==pMax && x<nrMin)nrMin=x;
51 }
52 g<<nrMin<<’\n’;
53 }
54 else
55 {
56 int nrD[1500]= {}, n, i, x, mx=0, k, maxim=0;
57 f>>n;
58 for(i=1; i<=n; i++)
59 {
60 f>>x;
61 k=nrDiv(x);
62 if(k>mx)mx=k;
63 nrD[k]++;
64 }
65 for(i=1; i<=mx; i++)
66 if(nrD[i]>maxim)maxim=nrD[i];
67 g<<maxim<<’\n’;
68 }
69 return 0;
70 }
46 return nr;
47 }
48
49 void cerinta_2()
50 {
51 int x,i,a,maxi=0,k,ok,q;
52 //fin>>n;
53 for(i=1;i<=n;i++)
54 {
55 fin>>x;
56 y[i]=numara_div(x);
57 }
58 sort(y,y+n+1);
59 /* do
60 {
61 ok=0;
62 for(i=1;i<n;i++)
63 if (y[i]>y[i+1])
64 {
65 q=y[i];
66 y[i]=y[i+1];
67 y[i+1]=q;
68 ok=1;
69 }
70 } while (ok);*/
71 k=1;
72 a=y[1];
73 for(i=2;i<=n;i++)
74 if (y[i]==a)
75 k++;
76 else
77 {
78 if (maxi<k)
79 maxi=k;
80 a=y[i];
81 k=1;}
82
83 if(maxi<k)
84 maxi=k;
85 fout<<maxi;
86 }
87
88 int main()
89 {
90 int i,a,cerinta,maxi=0,nr,t;
91 ciur();
92 fin>>cerinta>>n;
93 if (cerinta==1)
94 {
95 for (i=1;i<=n;i++)
96 {
97 fin>>a;
98 t=numara_div(a);
99 if (t>maxi)
100 {
101 maxi=t;
102 nr=a;
103 }
104 else
105 if (t==maxi)
106 if (nr>a)
107 nr=a;
108 }
109 fout<<nr;
110 }
111 else
112 if (cerinta==2)
113 cerinta_2();
114 return 0;
115 }
3.2 furnica
Problema 2 - furnica 100 de puncte
Cercetătorii au descoperit că activitatea miriapodelor
este stimulată de culoarea galben şi de aceea o furnică
este supusă unui experiment.
Pe marginea mesei pe care se realizează experimen-
tul s-au lipit una lângă alta, N foi dreptunghiulare, de
culoare galbenă, numerotate ı̂n ordine, de la stânga la
dreapta, de la 1 la N .
Furnica se află pe masă, ı̂n faţa primei foi şi urmează un traseu deplasându-se doar pe laturile
libere ale foilor (care nu sunt lipite de alte foi sau de masă), pe verticală sau orizontală, (aşa cum
indică săgeţile din imaginea alăturată), ajungând din nou pe masă.
Ştiind că ı̂n urcare furnica parcurge un centimetru ı̂n 5 secunde, ı̂n coborâre parcurge un
centimetru ı̂n 2 secunde, iar dacă se deplasează pe orizontală parcurge un centimetru ı̂n 3 secunde,
ajutaţi-i pe cercetători să obţină unele date.
Cerinţe
Date de intrare
- pe următoarele N linii, câte două numere naturale ce reprezintă laturile foilor (exprimate ı̂n
centimetri), ı̂n ordinea numerotării acestora. Primul număr reprezintă dimensiunea laturii
orizontale, iar cel de-al doilea număr reprezintă dimensiunea laturii verticale a foii galbene.
- numerele aflate pe aceeaşi linie a fişierului sunt separate prin câte un spaţiu.
Date de ieşire
Fişierul de ieşire furnica.out va conţine o singură linie pe care va fi scris un număr natural
ce reprezintă rezultatul determinat pentru cerinţa C.
a 1 & N, T & 10 000; laturile foilor sunt numere naturale nenule cu cel mult 9 cifre fiecare;
a dacă furnica ajunge ı̂ntr-un punct aflat la ı̂mbinarea a două foi, se consideră că se află pe
foaia din stânga;
a pentru orice T furnica se va afla pe una din foi;
a pentru fiecare cerinţa se acordă 30 de puncte.
Exemple:
CAPITOLUL 3. OJI 2020 3.2. FURNICA 32
75 if (cerinta == 3)
76 {
77 //rezolv cerinta 3
78 timp = F[1].h * 5; //urc
79 if (timp > T) //am depasit
80 fprintf(fout, "%d\n", 1); //sunt pe prima
81 else
82 {
83 for (i = 1; i < N; i++) //parcurg pe rand cele N bucati
84 {
85 timp += F[i].l * 3; //orizontal pe i
86 if (timp >= T) //am depasit
87 {
88 fprintf(fout, "%lld\n", i); //asta e
89 break;
90 }
91 if (F[i].h < F[i+1].h) //pe verticala
92 {
93 timp += (F[i+1].h - F[i].h) * 5;//urca pe urmatorul
94 if (timp >= T) //am depasit
95 {
96 fprintf(fout, "%lld", i + 1); //asta e
97 break;
98 }
99 }
100 else
101 {
102 timp += (F[i].h - F[i+1].h) * 2;//coboara tot pe i
103 if (timp >= T) // am depasit
104 {
105 fprintf(fout, "%lld\n", i); //sunt TOT pe i
106 break;
107 }
108 }
109 }
110 if (timp < T) //inca nu am ajuns la T
111 fprintf(fout, "%lld", N); //voi termina pe N
112 }
113 }
114 return 0;
115 }
32 if (l>maxi)
33 maxi=l;
34 l=0;
35 }
36 s=s+x2*t_o;
37 y1=y2;
38 l=l+x2;
39 }
40 s=s+y2*t_c;
41 if (l>maxi)
42 maxi=l;
43 if (cerinta==1)
44 fout<<s;
45 else
46 fout<<maxi;
47 }
48
49 void foaie()
50 { int ok=0;
51 fin>>n>>t>>x1>>y1;
52 s=y1*t_u+x1*t_o;
53 if (s>=t) fout<<1;
54 else
55 {
56 for(i=2;i<=n;i++)
57 {
58 fin>>x2>>y2;
59 if (y2>y1)
60 {
61 s=s+(y2-y1)*t_u;
62 if (s>=t)
63 { ok=1;
64 fout<<i;
65 break;}
66 }
67 else
68 if (y1>y2)
69 {
70 s=s+(y1-y2)*t_c;
71 if (s>=t)
72 { ok=1;
73 fout<<i-1;
74 break;}
75
76 }
77
78 s=s+x2*t_o;
79 y1=y2;
80 if (s>=t)
81 {
82 fout<<i;
83 ok=1;break;
84 }
85 }
86 s=s+y2*t_c;
87 if (ok==0)
88 fout<<n;
89 }
90 }
91
92 int main()
93 {
94 fin>>cerinta;
95 if (cerinta==1 || cerinta==2)
96 timp();
97 else
98 foaie();
99 return 0;
100 }
4 #include <fstream>
5
6 using namespace std;
7
8 ifstream f("furnica.in");
9 ofstream g("furnica.out");
10
11 long long dist_coborare,dist_urcare,dist_oriz,lungime,maxi,TIMP;
12
13 int main()
14 {
15 int H,L,H1,L1,n,i,cerinta,t_oriz,t_urcare,t_coborare,cladire;
16 t_urcare=5;t_oriz=3;t_coborare=2;
17
18 f>>cerinta>>n;
19 if (cerinta==3)
20 f>>TIMP;
21 f>>L1>>H1;
22 H=H1;
23 dist_urcare=H1;dist_oriz=L1;dist_coborare=0;
24 lungime=H1+L1;
25 maxi=lungime;
26 i=1;
27 TIMP=TIMP-(dist_urcare*t_urcare+dist_oriz*t_oriz);
28 if (TIMP<=0)
29 cladire=1;
30 for(i=2; i<=n; i++)
31 {
32 f>>L>>H;
33 dist_oriz=dist_oriz+L;
34 if(H>=H1) // URCARE
35 {
36 lungime=lungime+H-H1+L;
37 dist_urcare=dist_urcare+H-H1;
38 if (TIMP>0)
39 {
40 TIMP=TIMP-(H-H1)*t_urcare;
41 if(TIMP<=0)
42 cladire=i;
43 }
44 }
45 else // COBORARE
46 {
47 dist_coborare=dist_coborare+H1-H;
48 lungime=L;
49 if (TIMP>0)
50 {
51 TIMP=TIMP-(H1-H)*t_coborare;
52 if(TIMP<=0)
53 cladire=i-1;
54 }
55 }
56 if (TIMP>0)
57 {
58 TIMP=TIMP-L*t_oriz;
59 if (TIMP<=0)
60 cladire=i;
61 }
62 if (lungime>maxi)
63 maxi=lungime;
64 H1=H;
65 L1=L;
66 }
67 if (TIMP>0)
68 if(TIMP-H*t_coborare<=0)
69 cladire=n;
70 else cladire=-1;
71
72 if (cerinta==1)
73 g<<(dist_oriz*t_oriz+dist_urcare*t_urcare+(dist_coborare+H)*t_coborare)
74 <<’\n’;
75 else if (cerinta==2)
76 g<<maxi<<’\n’;
77 else if (cerinta==3)
78 g<<cladire<<’\n’;
79 return 0;
CAPITOLUL 3. OJI 2020 3.2. FURNICA 37
80 }
72 if (lungime>maxi)
73 maxi=lungime;
74 H1=H;
75 L1=L;
76 }
77 if (TIMP>0)
78 if(TIMP-H*t_coborare<=0)
79 cladire=n;
80 else cladire=-1;
81
82 if (cerinta==1)
83 g<<(dist_oriz*t_oriz+dist_urcare*t_urcare+(dist_coborare+H)*t_coborare)
84 <<’\n’;
85 else if (cerinta==2)
86 g<<maxi<<’\n’;
87 else if (cerinta==3)
88 g<<cladire<<’\n’;
89 return 0;
90 }
54 l=ll; L=LL;
55 if(timp>=T)
56 {
57 unde=i;
58 break;
59 }
60 }
61 if(timp<T)unde=n;
62 g<<unde<<’\n’;
63 }
64 return 0;
65 }
61 {
62 lg += F[u].h - F[p].h; //urc diferenta
63 p++; //ea devine cea curenta
64 }
65 else //am terminat o secventa crescatoare
66 {
67 if (lg > lg_max) //daca e mai mare
68 lg_max = lg; //retin
69 p = u; //incep o noua seventa
70 lg = 0;
71 }
72 }
73 fout << lg_max << ’\n’;
74 }
75 if (cerinta == 3)
76 {
77 //rezolv cerinta 3
78 timp = F[1].h * 5; //urc
79 if (timp > T) //am depasit
80 fout << 1 << ’\n’; //sunt pe prima
81 else
82 {
83 for (i = 1; i < N; i++) //parcurg pe rand cele N bucati
84 {
85 timp += F[i].l * 3; //orizontal pe i
86 if (timp >= T) //am depasit
87 {
88 fout << i << ’\n’; //asta e
89 break;
90 }
91 if (F[i].h < F[i+1].h) //pe verticala
92 {
93 timp += (F[i+1].h - F[i].h) * 5;//urca pe urmatorul
94 if (timp >= T) //am depasit
95 {
96 fout << i + 1 << ’\n’; //asta e
97 break;
98 }
99 }
100 else
101 {
102 timp += (F[i].h - F[i+1].h) * 2;//coboara tot pe i
103 if (timp >= T) // am depasit
104 {
105 fout << i << ’\n’; //sunt TOT pe i
106 break;
107 }
108 }
109 }
110 if (timp < T) //inca nu am ajuns la T
111 fout << N << ’\n’; //voi termina pe N
112 }
113 }
114 return 0;
115 }
OJI 2019
4.1 album
Problema 1 - album 90 de puncte
Victor si Radu sunt fraţi. Mama le-a adus n stickere cu fotbalişti, fiecare sticker având impri-
mat pe spate un cod, un număr cuprins ı̂ntre 10 şi 999999. Fraţii, dorind cât mai multe stickere
pe care să le lipească ı̂n albumul propriu, au ı̂nceput să se certe. Mama le propune următorul mod
de ı̂mpărţire a stickerelor: ea aranjează cele n stickere ı̂n linie, cu faţa ı̂n jos, şi fiecare frate, pe
rând, va lua primul sticker disponibil, precum şi toate stickerele care conţin două cifre care sunt
egale cu cele mai mari două cifre, nu neapărat distincte, dintre cele scrise pe primul sticker luat la
această etapă. Stickerele sunt disponibile ı̂ncepând de la stânga spre dreapta. Fiind cel mai mic,
Victor va fi primul, apoi copiii iau stickere alternativ, până când nu mai sunt stickere. La final,
fiecare copil numără câte stickere are ı̂n total.
Cerinţe
Cunoscând numărul n de stickere aduse de mama şi numerele de pe ele ı̂n ordinea ı̂n care sunt
aşezate pe masă, să se determine:
1. Cele mai mari două cifre, nu neapărat distincte, de pe ultimul sticker aflat pe masă ı̂nainte
de ı̂nceperea concursului;
2. Fratele care câştigă concursul şi câte stickere are.
Date de intrare
Fişierul de intrare album.in conţine pe prima linie o cifră c care poate să fie doar 1 sau 2. Pe a
doua linie se găseşte n reprezentând numărul de stickere. Pe a treia linie se află n numere naturale
separate prin câte un spaţiu, reprezentând numerele de pe stickere.
Date de ieşire
Dacă valoarea lui c este 1, atunci se va rezolva numai punctul 1 din cerinţă. În acest caz, fişierul
de ieşire album.out va conţine pe prima linie, ı̂n ordine crescătoare, cifrele cerute.
Dacă valoarea lui c este 2, se va rezolva numai punctul 2 din cerinţă. În acest caz, fişierul de
ieşire album.out va conţine pe prima linie litera V dacă Victor are mai multe stickere, litera R
dacă Radu are mai multe stickere, sau literele V şi R separate prin exact un spaţiu dacă amândoi
au acelaşi număr de stickere. Pe a doua linie se va scrie numărul de stickere ale celui care are cele
mai multe sau numărul de stickere deţinut de fiecare, ı̂n cazul ı̂n care au acelaşi număr de stickere.
Exemple
41
CAPITOLUL 4. OJI 2019 4.1. ALBUM 42
Dificultate 3
prof. Violeta Grecea, Colegiul National de Informatica ’Matei Basarab’ Ramnicu Valcea
Pentru rezolvarea primei cerinte, se parcurg numerele din sir prin citire.
Se foloseste o variabila simpla x pentru citirea tuturor numerelor din sir.
Pentru ultima valoare a lui x se calculeaza cele mai mari doua cifre.
Pentru rezolvarea celei de-a doua cerinte, se foloseste un vector caracteristic pentru numerele
cu doua cifre, in care se va retine, la a cata parcurgere a sirului de numere se va alege elementul
ce contine acele doua cifre.
Parcurgerile cu numar impar apartin lui Victor, iar cele cu numar par lui Radu.
Pentru un numar x, din sir, se verifica in vectorul caracteristic daca exista doua cifre ale sale
care sa fie anterior alese.
In aceasta situatie se va calcula la a cata parcurgere a fost facut acest lucru, pentru a stabili
cui apartine stickerul.
Structurile de date utilizate: vectori.
24 maxim2=0;
25 while(x)
26 {
27 u=x%10;
28 if(u>=maxim1)
29 {
30 maxim2=maxim1;
31 maxim1=u;
32 }
33 if(u>maxim2 and u<maxim1)
34 maxim2=u;
35 x=x/10;
36 }
37 g<<maxim2<<" "<<maxim1;
38 }
39
40 if(C==2)
41 {
42 f>>n;
43 for(i=1; i<=n; i++)
44 {
45 f>>x;
46 k=0;
47 t=x;
48 while(x)
49 {
50 u=x%10;
51 v[++k]=u;
52 x=x/10;
53 }
54 sort(v+1,v+k+1);
55 reverse(v+1,v+k+1);
56
57 ok=0;
58 minim=1000000;
59 numar=0;
60 for(p=1; p<=k-1; p++)
61 {
62 for(y=p+1; y<=k; y++)
63 {
64 nr=v[p]*10+v[y];
65 if(ap[nr]!=0 and ap[nr]<minim)
66 {
67 minim=ap[nr];
68 numar=nr;
69 ok=1;
70 }
71 }
72 }
73 if(ok==1)
74 if(minim%2==1)
75 vi++;
76 else
77 ra++;
78 if(ok==0)
79 {
80 x=t;
81 maxim1=0;
82 maxim2=0;
83 while(x)
84 {
85 u=x%10;
86 if(u>=maxim1)
87 {
88 maxim2=maxim1;
89 maxim1=u;
90 }
91 if(u>maxim2 and u<maxim1)
92 maxim2=u;
93 x=x/10;
94 }
95 nr=maxim1*10+maxim2;
96 poz++;
97 ap[nr]=poz;
98 if(poz%2==1)
99 vi++;
CAPITOLUL 4. OJI 2019 4.1. ALBUM 44
100 else
101 ra++;
102 }
103 }
104
105 if(vi>ra)
106 g<<’V’<<endl<<vi;
107 if(ra>vi)
108 g<<’R’<<endl<<ra;
109 if(vi==ra)
110 g<<’V’<<" "<<’R’<<endl<<vi;
111
112 }
113
114 return 0;
115 }
57 if (max1!=max2)
58 {
59 k1=1;
60 k2=1;
61 }
62 else
63 {
64 k1=2;
65 k2=2;
66 }
67
68 for(i=0;i<=9;i++) v1[i]=0;
69
70 while (x)
71 {
72 v1[x%10]++;
73 x=x/10;
74 }
75
76 if (v1[max1]>=k1 && v1[max2]>=k2)
77 return 1;
78 else
79 return 0;
80 }
81
82 void c2()
83 {
84 int a,j,vf,ld,vk,rk,i,kk;
85 k=1;
86 vf=0;
87
88 maxime1(x[1],max1, max2);
89
90 vk=1;rk=0;
91 for(i=2;i<=n;i++)
92 {
93 if (exista(x[i],max1,max2))
94 vk++;
95 else
96 {
97 vf++;
98 y[vf]=x[i];
99 }
100 }
101
102 k=2;
103 ld=vf;
104 while (vf>=1)
105 {
106 a=y[1];
107 kk=0;
108
109 if(k%2==1) vk++;
110 else rk++;
111
112 maxime1(a,max1,max2);
113
114 for(j=2;j<=ld;j++)
115 {
116 if (exista(y[j],max1,max2))
117 if (k%2==0)
118 rk++;
119 else
120 vk++;
121 else
122 {
123 kk++;
124 y[kk]=y[j];
125 }
126 }
127
128 ld=kk;
129 vf=kk;
130 k++;
131 }
132
CAPITOLUL 4. OJI 2019 4.1. ALBUM 46
133 if(rk>vk)
134 g<<"R"<<endl<<rk;
135 else
136 if(vk>rk)
137 g<<"V"<<endl<<vk;
138 else
139 g<<"V R"<<endl<<vk;
140 }
141
142
143 int main()
144 {
145 f>>c>>n;
146 for(i=1;i<=n;i++)
147 f>>x[i];
148
149 if (c==1)
150 {
151 maxime1(x[n],max1,max2);
152 g<<max2<<" "<<max1;
153 }
154 else
155 c2();
156
157 return 0;
158 }
47 do
48 { // sort cifre ...
49 ok=0;
50 for(j=1;j<nrc;j++)
51 if(ci[j]<ci[j+1])
52 {
53 y=ci[j]; ci[j]=ci[j+1]; ci[j+1]=y;
54 ok=1;
55 }
56 } while(ok==1);
57
58 ok=0;
59 c1=1000000;
60 for(j=1;j<nrc;j++)
61 for(k=j+1;k<=nrc;k++)
62 {
63 y=ci[j]*10+ci[k];
64 if(ap[y]!=0)
65 {
66 ok=1;
67 if(ap[y]<c1) {c1=ap[y]; c2=y;}
68 }
69 }
70
71 if(ok==0)
72 {
73 al++;
74 ap[ci[1]*10+ci[2]]=al;
75 if(al%2==1) v++;
76 else r++;
77 }
78 else if(ap[c2]%2==1) v++;
79 else r++;
80 }
81
82 if(v>r) g<<’V’<<’\n’<<v;
83 else if(v==r) g<<’V’<<’ ’<<’R’<<’\n’<<v;
84 else g<<’R’<<’\n’<<r;
85 }
86 }
33 {
34 f>>n;
35 for(i=1;i<=n;i++) f>>ap[i];
36
37 do
38 {
39 et++;
40 i=1;
41 while(i<=n && ap[i]==-1) i++;
42
43 if(i<=n)
44 {
45 x=ap[i];
46 if(et%2==1) v++; else r++;
47
48 ap[i]=-1;
49 c1=-1; c2=-1;
50 while(x!=0)
51 {
52 if(x%10>=c1) {c2=c1; c1=x%10;}
53 else
54 if(x%10>c2) c2=x%10;
55 x=x/10;
56 }
57
58 for(j=i+1;j<=n;j++)
59 {
60 ok=0;
61 x=ap[j];
62 if(x!=-1)
63 {
64 ct1=0;
65 ct2=0;
66 while (x!=0&&ok==0)
67 {
68 if(x%10==c1) ct1++;
69 if(x%10==c2) ct2++;
70 if(ct1>=1 && ct2>=1 && c1!=c2 || ct1==2 && c1==c2) ok=1;
71 x=x/10;
72 }
73
74 if(ok==1)
75 if(et%2==1) {v++; ap[j]=-1;}
76 else {r++;
77
78 ap[j]=-1;}
79 }
80 }
81 }
82 } while(i<=n);
83
84 if(v>r) g<<’V’<<’\n’<<v;
85 else
86 if(v==r) g<<’V’<<’ ’<<’R’<<’\n’<<v;
87 else g<<’R’<<’\n’<<r;
88 }
89 }
92 else
93 radu ++;
94 v[j] = 0;
95 }
96 }
97 }
98 if(cine == 1)
99 cine = 2;
100 else
101 cine = 1;
102 }
103
104 if(victor == radu)
105 {
106 cout << "V R\n";
107 cout << victor << ’\n’;
108 }
109 else
110 if(victor > radu)
111 cout << "V \n" << victor << ’\n’;
112 else
113 cout << "R \n" << radu << ’\n’;
114 return 0;
115 }
49 {
50 f>>a;
51 //g<<a<<’\n’;
52
53 for(j=0;j<=9;++j) w[j]=0;
54
55 for(j=0;a[j];++j)
56 {
57 x=a[j]-’0’;
58 w[x]++;
59 }
60
61 i=0;
62 for(j=9;j>=0 ;--j)
63 {
64 if(w[j]>=1)
65 v[++i]=j;
66 }
67
68 n=i;
69
70 x=v[1];
71 if(w[x]>1)
72 Mm=x*10+x;
73 else
74 Mm=v[1]*10+v[2];
75
76 //g<<Mm<<’\n’;
77
78 ORD=1234567;
79
80 for(i=1;i<=n;++i) //verificam dublurile
81 {
82 x=v[i];
83 if(w[x]>1)
84 {
85 z=x*10+x;
86 //g<<z<<’\n’;
87 //cautam cel mai mic ordin
88 if(ord[z]>0) //daca numarul z a mai fost
89 {
90 if(ord[z]<ORD)
91 ORD=ord[z];
92 }
93 }
94 }
95
96 for(i=1;i<n;i++)
97 for(j=i+1;j<=n;j++)
98 {
99 z=v[i]*10+v[j];
100 //g<<z<<’\n’;
101 //cautam cel mai mic ordin
102 if(ord[z]>0) //daca a mai fost
103 {
104 if(ord[z]<ORD)
105 ORD=ord[z];
106 }
107 }
108
109 if(ORD==1234567) //se creaza un nou ordin
110 {
111 ++poz;
112 ord[Mm]=poz;
113 ORD=poz;
114 //g<<"alt ordin:"<<ORD<<’\n’;
115 if(poz%2) V++;
116 else R++;
117
118 }
119 else //s-a aderat la ordinul ORD
120 {
121 if(ORD%2) V++;
122 else R++;
123 }
124
CAPITOLUL 4. OJI 2019 4.2. MAXIM 52
4.2 maxim
Problema 2 - maxim 90 de
puncte
Dintr-un şir format din N cifre, numerotate de la 1 la N , Ionel ia exact M cifre aflate pe
poziţii consecutive. El lipeşte cifrele luate sau le amestecă şi apoi le lipeşte pentru a obţine cu ele
un număr cât mai mare.
Cerinţe
Date de intrare
Din fişierul maxim.in se citesc: P de pe prima linie, reprezentând cerinţa problemei (1 sau
2), N şi M de pe a doua linie, despărţite printr-un spaţiu, cu semnificaţia din enunţ, iar de pe
linia a treia, se citesc cele N cifre, despărţite prin câte un spaţiu.
Date de ieşire
Exemple
Dificultate: 4
1) Cerinta 1 (30 puncte)
Se citesc primele M cifre dintre cele N si se afiseaza in ordine descrescatoare.
Pentru M $ 10 (15 puncte) se poate construi numarul X format din primele M cifre si apoi se
numara aparitiile cifrei 9, apoi 8, ... apoi 0, afisand cifra respectiva de atatea ori de cte ori apare
in X.
Pentru M ¡= 1000, se pot memora primele M cifre, se ordoneaza descrescator sirul si se afiseaza
valorile, fara a spatii. Mai eficient, se contorizeaza intr-un vector AP cu indicii de la 0 la 9 numarul
de aparitii ale fiecarei cifre si se afiseaza fiecare i, de la 9 la 0 de AP i ori.
2) Cerinta 2 (60 puncte)
Se memoreaza primele M cifre (ca la cerina 1), retinand cu ajutorul unui alt vector valoarea
maxima obtinuta prin rearanjare (vector ordonat sau vector de aparitii).
Initial, acesta este si vectorul corespunzator secventei de valoare maxima.
Se prelucreaza, pe rand, celelalte N M cifre actualizand vectorul curent si comparand cu
vectorul corespunzator secventei de valoare maxima. Pentru a stabili pozitia de unde se aleg
cifrele, se poate demonstra ca, dintre toate secventele de valoare maxima, ultima este cea care
asigura ca numarul ramas sa fie de valoare maxima si pozitia sa fie maxima.
3 #include <algorithm>
4
5 using namespace std;
6
7 ifstream f("maxim.in");
8 ofstream g("maxim.out");
9
10 int c,n,m,v[100002],poz,i,j,k,q,start,sf,ap[10],ap1[10],vpoz[1002];
11
12 int main()
13 {
14 f>>c;
15 f>>n;
16 f>>m;
17
18 if(c==1)
19 {
20 for (i=1;i<=m;i++)
21 {
22 f>>v[i];
23 }
24 sort(v+1,v+m+1);
25 for(int i=m;i>=1;i--)
26 g<<v[i];
27 }
28
29 if(c==2)
30 {
31 start=1;
32
33 for (i=1;i<=n;i++)
34 {
35 f>>v[i];
36 if(i<=m)
37 {
38 ap[v[i]]++; // creez primul maxim
39 ap1[v[i]]++;
40 }
41
42 }
43
44 poz=1;
45 for (sf=m+1; sf<=n; sf++)
46 {
47 ap1[v[poz]]--;
48 ap1[v[sf]]++; // in ap 1 retin mereu cifrele
49 // din secventa curenta
50 poz++;
51 for(j=9;j>=0;j--)
52 if(ap[j]>ap1[j])
53 break;
54 else
55 if(ap1[j]>ap[j])
56 {
57
58 start=poz;
59 for (k=0;k<=9;k++)
60 ap[k]=ap1[k]; // in ap am mereu maximul
61 break;
62 }
63 }
64
65 g<<start;
66 }
67
68 if(c==3) // am facut asta pentru cazul in care sunt mai multe pozitii
69 {
70 start=1;
71
72 for (i=1;i<=n;i++)
73 {
74 f>>v[i];
75 if(i<=m)
76 {
77 ap[v[i]]++; // creez primul maxim
78 ap1[v[i]]++;
CAPITOLUL 4. OJI 2019 4.2. MAXIM 55
79 }
80 }
81
82 poz=1;
83 for (sf=m+1; sf<=n; sf++)
84 {
85 ap1[v[poz]]--;
86 ap1[v[sf]]++; // in ap 1 retin mereu cifrele din secventa curenta
87
88 poz++;
89 q=1; // presupun ca toate cifrele atunci cand le compar sunt egale
90 for(j=9;j>=0;j--)
91 if(ap[j]>ap1[j])
92 {
93 q=0;
94 break;
95 }
96 else
97 if(ap1[j]>ap[j])
98 {
99 q=0;
100 start=poz;
101 for (k=0;k<=9;k++)
102 ap[k]=ap1[k]; // in ap am mereu maximul
103 break;
104 }
105
106 if (q==1) //daca am mai gasit o solutie cu acelasi maxim
107 {
108 // verific daca prima cifra din secv eliminata ar fi
109 // mai mare decat prima cifra de dupa secv
110 if (v[start]>v[start+m])
111 start=poz; // si atunci aleg sa elimin alta secventa
112 }
113 }
114
115 g<<start;
116 }
117
118 return 0;
119 }
32 for (i=1;i<=n;i++)
33 {
34 f>>v[i];
35 if(i<=m)
36 {
37 ap[v[i]]++; // creez primul maxim
38 ap1[v[i]]++;
39 }
40
41 }
42
43 poz=1;
44
45 for (sf=m+1; sf<=n; sf++)
46 {
47 // in ap 1 retin mereu cifrele din secventa curenta
48 ap1[v[poz]]--;
49 ap1[v[sf]]++;
50
51 poz++;
52 q=1;
53
54 // presupun ca toate cifrele atunci cand le compar sunt egale
55 for(j=9;j>=0;j--)
56 if(ap[j]>ap1[j])
57 {
58 q=0;
59 break;
60 }
61 else
62 if(ap1[j]>ap[j])
63 {
64 q=0;
65 start=poz;
66 for (k=0;k<=9;k++)
67 ap[k]=ap1[k]; // in ap am mereu maximul
68 break;
69 }
70
71 if (q==1) //daca am mai gasit o solutie cu acelasi maxim
72 {
73 start=poz; // aleg sa elimin ultima secventa
74 }
75 }
76
77 g<<start;
78 }
79
80 return 0;
81 }
23 f>>N>>M;
24
25 for(i=1;i<=N;++i)
26 f>>v[i];
27
28
29 for(i=1;i<=M;++i)
30 {
31 x=v[i];
32 w[x]++;
33 }
34
35
36 if(p==1)
37 {
38 if(w[0]==M)
39 g<<0;
40 else
41 {
42 for(j=9;j>=0;j--)
43 for(i=1;i<=w[j];i++)
44 g<<j;
45 }
46 }
47
48
49 if(p==2)
50 {
51
52 for(j=0;j<10;j++)
53 W[j]=w[j];
54
55 for(i=M+1;i<=N;++i)
56 {
57 x=v[i];
58 w[x]++;
59 z=v[i-M];
60 w[z]--;
61
62 ok=1;
63 //comparam sirurile
64 for(j=9;j>0;j--)
65 {
66 if(W[j]!=w[j])
67 {
68 if(w[j]>W[j])
69 {
70 ok=2;
71 for(ii=0;ii<=9;++ii)
72 W[ii]=w[ii];
73 poz=i-M+1;
74 //g<<"gasit la "<<i<<’\n’;
75
76 }
77 else //(w[j]<W[j])
78 {
79 ok=0;
80 }
81
82 break;
83 }
84 }
85
86 if(ok==1)
87 {
88 poz=i-M+1;
89 }
90 }
91
92 g<<poz;
93 }
94
95 return 0;
96 }
27 for(i=1;i<=N;++i)
28 f>>v[i];
29
30 if(p==1)
31 {
32 sort(v+1,v+M+1,cond);
33
34 A=0;
35 for(i=1;i<=M;++i)
36 {
37 A=A*10+v[i];
38 }
39
40 g<<A<<’\n’;
41 }
42
43 if(p==2)
44 {
45
46 //for(j=0;j<10;j++)
47 // W[j]=w[j];
48 for(i=1;i<=M;++i)
49 b[i]=v[i];
50
51 sort(b+1,b+M+1,cond);
52
53 A=0;
54 for(i=1;i<=M;++i)
55 {
56 A=A*10+b[i];
57 }
58
59 //g<<A<<’\n’;
60 poz=1;
61 maxx=A;
62
63 for(i=2;i<=N-M+1;++i)
64 {
65 for(j=i;j<=i+M-1;j++)
66 b[j]=v[j];
67
68 j=i;
69 sort(b+j,b+j+M,cond);
70
71 A=0;
72 for(j=i;j<=i+M-1;j++)
73 {
74 A=A*10+b[j];
75 }
76 //g<<A<<’\n’;
77 if(maxx<=A)
78 {
79 maxx=A;
80 poz=i;
81 }
82 }
83
84 g<<poz;
85 }
86
87 return 0;
88 }
11 int p,n,m,i,j,poz,fc[10],fcmax[10];
12 f>>p>>n>>m;
13
14 for(i=0;i<=9;i++)fc[i]=fcmax[i]=0;
15
16 for(i=1;i<=m;i++)
17 {
18 f>>q[i];
19 fc[q[i]]++;
20 }
21
22 if(p==1)
23 {
24 for(i=9;i>=0;i--)
25 for(j=1;j<=fc[i];j++)
26 g<<i;
27 }
28 else
29 {
30 for(i=0;i<=9;i++)fcmax[i]=fc[i];
31 poz=1;
32 for(i=m+1;i<=n;i++) f>>q[i];
33 for(i=m+1;i<=n;i++)
34 {
35 fc[q[i]]++;
36 fc[q[i-m]]--;
37 if(q[i]>=q[i-m])
38 {
39 j=9;
40 while(j>=0 and fc[j]==fcmax[j])
41 j--;
42 if(j>=0)
43 {
44 if(fc[j]>fcmax[j])
45 {
46 for(j=0;j<=9;j++)fcmax[j]=fc[j];
47 poz=i-m+1;
48 }
49 }
50 else
51 poz=i-m+1;
52 }
53 }
54 g<<poz;
55 }
56 }
27 }
28
29 void vector_aparitii(int poz, int v1[])
30 {
31 int i;
32 for(i=0;i<=9;i++)
33 v1[i]=0;
34 for(i=poz;i<=m+poz-1;i++)
35 v1[x[i]]++;
36 }
37
38 int comparare_vector(int v1[], int v2[])
39 {
40 for(i=9;i>=0;i--)
41 if (v1[i]>v2[i]) return 1;
42 else
43 if (v1[i]<v2[i]) return -1;
44 return 0;
45 }
46
47 void cerinta2()
48 {
49 int v2[10],p,v1[10],j,i;
50
51 vector_aparitii(1,v1);
52
53 p=1;
54 for(i=2;i<=n-m+1;i++)
55 {
56 vector_aparitii(i,v2);
57 if (comparare_vector(v1,v2)==-1)
58 {
59 p=i;
60 for(j=0;j<=9;j++) v1[j]=v2[j];
61 }
62 else
63 if (comparare_vector(v1,v2)==0)
64 p=i;
65 }
66 g<<p;
67 }
68
69 int main()
70 {
71 f>>c>>n>>m;
72
73 for(i=1;i<=n;i++)
74 f>>x[i];
75
76 if (c==1)
77 cerinta1();
78 else
79 cerinta2();
80
81 return 0;
82 }
17 {
18 g<<i;
19 v[i]--;
20 }
21 }
22
23 void vector_aparitii(int poz, int v1[])
24 {
25 int i;
26 for(i=0;i<=9;i++)
27 v1[i]=0;
28 for(i=poz;i<=m+poz-1;i++)
29 v1[x[i]]++;
30 }
31
32 int comparare_vector(int v1[], int v2[])
33 {
34 for(i=9;i>=0;i--)
35 if (v1[i]>v2[i]) return 1;
36 else
37 if (v1[i]<v2[i]) return -1;
38 return 0;
39 }
40
41 void cerinta2()
42 {
43 int v2[10],p,v1[10],j,i,v3[10];
44 vector_aparitii(1,v1);
45
46 p=1;
47 for(i=0;i<=9;i++)
48 v3[i]=v1[i];
49
50 for(i=2;i<=n-m+1;i++)
51 {
52 for(j=0;j<=9;j++)
53 v2[j]=v3[j];
54 v2[x[i-1]]--;
55 v2[x[i+m-1]]++;
56 if (comparare_vector(v1,v2)==-1)
57 {
58 p=i;
59 for(j=0;j<=9;j++) v1[j]=v2[j];
60 }
61 else
62 if (comparare_vector(v1,v2)==0)
63 p=i;
64 for(j=0;j<=9;j++)
65 v3[j]=v2[j];
66 }
67 g<<p;
68 }
69
70 int main()
71 {
72 f>>c>>n>>m;
73 for(i=1;i<=n;i++)
74 f>>x[i];
75 if (c==1)
76 cerinta1();
77 else
78 cerinta2();
79 return 0;
80 }
OJI 2018
Cerinţe
Date de intrare
Fişierul de intrare numere.in conţine pe prima linie un număr natural C, care poate fi 1, 2
sau 3. Pe linia a doua se găseşte numărul natural n, dacă C 1, sau numărul natural x, dacă
C 2 sau numărul natural k, dacă C 3, numerele având semnificaţia din enunţ.
Date de ieşire
Dacă valoarea lui C este 1, se va rezolva numai cerinţa 1. În acest caz, ı̂n fişierul de ieşire
numere.out se va scrie al n-lea număr eliminat.
Dacă valoarea lui C este 2, se va rezolva numai cerinţa 2. În acest caz, ı̂n fişierul de ieşire
numere.out se vor scrie 3 numere, n1, n2, n3, cu semnificaţia din enunţ, ı̂n această ordine,
separate prin câte spaţiu.
Dacă valoarea lui C este 3, se va rezolva numai cerinţa 3. În acest caz, fişierul de ieşire
numere.out va conţine numărul valorilor de k cifre din noul şir.
63
CAPITOLUL 5. OJI 2018 5.1. NUMERE - OJI 2018 64
Exemple
numere.in numere.out Explicaţii
1 10 n 2 şi al doilea număr eliminat este 10.
2 (C fiind 1 se rezolvă numai cerinţa 1).
2 021 x 1205, numărul 120 nu apare ı̂n şir, deci n1 0, 12 apare de
1205 două ori, deci n2 2, iar 1 apare o singură dată, deci n3 1 (C
fiind 2 se rezolvă numai cerinţa 2).
3 153 k 2 şi ı̂n noul şir sunt 153 de numere de câte 2 cifre.
2 (C fiind 3 se rezolvă numai cerinţa 3).
Cerinta 3
Numarul elementelor de k cifre din noul sir este 2*(t-a)-b, unde:
=¿ Numarul elementelor de k cifre din noul sir este 162 10k 2 9 10 k 1©2 pentru k %1
Obs.
k 1©2 reprezinta partea intreaga a impartirii
1 ¡= k ¡= 50 =¿ numarul total de numere de k cifre nu se incadreaza in long long, insa avand o
forma regulata se poate afisa direct rezultatul, tratandu-se separat cazurile k 1, k 2 si k 3.
9 {
10 if (x%10==0) return 0;
11
12 int y, ras=0;
13
14 y=x;
15 while (y!=0)
16 {
17 ras=ras*10+y%10;
18 y=y/10;
19 }
20
21 if (x==ras) return 1;
22
23 return 2;
24 }
25
26 int main()
27 {
28 unsigned long long n;
29 int c,x,k,i;
30
31 f>>c;
32
33 if (c==1)
34 {f>>n; g<<(n-1)*10<<’\n’;}
35 else if (c==2)
36 {f>>x; g<<nrap(x/10)<<’ ’<<nrap(x/100)<<’ ’<<nrap(x/1000)<<’\n’;}
37 else // cazul c=3
38 {
39 f>>k;
40 if (k==1) g<<"9\n"; // caz special
41 else if (k==2) g<<"153\n";
42 else if (k==3) g<<"1530\n";
43 else
44 {
45 // nr este de forma 16199...9100...0
46 g<<161;
47 int nr0=(k-1)/2;
48 int nr9=k-2-1-nr0;
49 for (i=1; i<=nr9; i++)g<<9;
50 g<<1;
51 for (i=1; i<=nr0; i++)g<<0;
52 g<<’\n’;
53 }
54 }
55 return 0;
56 }
25 }
26 return 0;
27 }
28
29 ///p=3 numere mari
30 fin>>k;
31 if(k==1){fout<<9<<’\n’;return 0;}
32 if(k==2){fout<<153<<’\n’;return 0;}
33 if(k==3){fout<<1530<<’\n’;return 0;}
34 if(k==4){fout<<16110<<’\n’;return 0;}
35 x=(k-1)/2;
36 fout<<161;
37 for(i=1;i<=k-x-3;i++)fout<<9;
38 fout<<1;
39 for(i=1;i<=x;i++)fout<<0;
40
41 return 0;
42 }
55
56 f>>p;
57
58 if(p==1)
59 { f>>n;
60 g<<(n-1)*10;
61 }
62 else
63 {
64 if(p==2)
65 {
66 f>>x;
67 g<<cauta(x/10)<<’ ’<<cauta(x/100)<<’ ’<<cauta(x/1000);
68 }
69 else
70 {
71 f>>k;
72 switch (k)
73 {
74 case 1: g<<9;break;
75 case 2: g<<153;break;
76 case 3: g<<1530;break;
77 case 4: g<<16110;break;
78 default: calcul(k);
79 }
80 }
81 }
82
83 return 0;
84 }
Cerinţe
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 69
Ştiind că un turn poate fi format din cel puţin un cub, scrieţi un program care să determine:
1. numărul final T al turnurilor de pe bandă şi H, ı̂nălţimea celui mai ı̂nalt turn care se poate
forma, exprimată ı̂n centimetri;
2. cel mai mare număr de cuburi N max ce pot forma un turn, dacă cele N cuburi ar putea fi
rearanjate iniţial pe bandă, unul lângă altul.
Date de intrare
Date de ieşire
Fişierul turnuri.out va conţine pentru cerinţa 1 (C 1) pe prima linie două valori, separate
printr-un spaţiu, ce reprezintă T şi H. Pentru cerinţa 2 (C 2) fişierul va conţine pe prima linie
numărul N max.
a 1 & N & 10000 şi 1 & latura unui cub & 500000;
a nu există două cuburi cu laturi egale;
a se acordă 10 puncte din oficiu. Pentru rezolvarea corectă a primei cerinţe se acordă 30 de
puncte, pentru rezolvarea corectă a celei de-a doua cerinţe se acordă 60 de puncte.
Exemple
- in cazul in care cubul K nu poate fi aezat peste cubul K 1, se actualizeaza intr-o variabila de
tip contor numarul T al turnurilor iar inaltimea turnului curent se initializeaza cu inaltimea
cubului K.
51 citire();
52 if (C==1)
53 fout<<nr_turnuri<<’ ’<<max_turn<<’\n’;
54 else
55 {
56 sort(v1+1,v1+1+n1,cmp);
57 sort(v2+1,v2+1+n2,cmp);
58
59 v1[n1+1]=500003;
60 v2[n2+1]=500002;
61
62 i=1;j=1;k=0;
63
64 if (v1[i]>v2[j])
65 {
66 ++k;v3=v1[i++];p=1;
67 }
68 else
69 {
70 ++k;v3=v2[j++];p=-1;
71 }
72
73 while(i<=n1&&j<=n2)
74 {
75 if(p==1)
76 {
77 while(j<=n2 && v2[j]>=v3)
78 j++;
79 if (j<=n2)
80 {++k; v3=v2[j++];p=-p;}
81 }
82 else
83 {
84 while(i<=n1 && v1[i]>=v3)
85 i++;
86 if(i<=n1)
87 {++k;v3=v1[i++];p=-p;}
88 }
89 }
90
91 if(p==-1)
92 for(i;i<=n1;i++)
93 if (v1[i]<v3) {++k;v3=v1[i];break;}
94
95 if(p==1)
96 for(j;j<=n2;j++)
97 if (v2[j]<v3) {++k;v3=v2[j];break;}
98
99 fout<<k<<’\n’;
100 }
101
102 fin.close();
103 fout.close();
104 return 0;
105 }
18 fin>>C>>n;
19 fin>>l1>>cul1;
20
21 nr_turnuri=1;h_turn=l1;
22
23 if(cul1==’g’) v1[++n1]=l1;
24 else v2[++n2]=l1;
25
26 for(i=1; i<=n-1; i++)
27 {
28 fin>>l2>>cul2;
29
30 if(cul2==’g’) v1[++n1]=l2;
31 else v2[++n2]=l2;
32
33 if(l2<l1 && cul2!=cul1)
34 {h_turn=h_turn+l2;}
35 else
36 {nr_turnuri++;h_turn=l2;}
37
38 if (h_turn>max_turn) max_turn=h_turn;
39
40 l1=l2;cul1=cul2;
41 }
42 }
43
44 bool cmp( int a, int b)
45 {
46 return (a>b);
47 }
48
49 int main()
50 {
51 int i,j,k,p;
52 citire();
53 if (C==1)
54 fout<<nr_turnuri<<’ ’<<max_turn<<’\n’;
55 else
56 {
57 sort(v1+1,v1+1+n1,cmp);
58 sort(v2+1,v2+1+n2,cmp);
59
60 v1[n1+1]=500003;
61 v2[n2+1]=500002;
62
63 i=1;
64 j=1;
65 k=0;
66 if (v1[i]>v2[j])
67 {
68 v3[++k]=v1[i++];
69 p=1;
70 }
71 else
72 {
73 v3[++k]=v2[j++];
74 p=-1;
75 }
76
77 while(i<=n1&&j<=n2)
78 {
79 if(p==1)
80 {
81 while(j<=n2 && v2[j]>=v3[k])
82 j++;
83 if (j<=n2)
84 {v3[++k]=v2[j++];
85 p=-p;}
86 }
87 if(p==-1)
88 {
89 while(i<=n1 && v1[i]>=v3[k])
90 i++;
91 if(i<=n1)
92 {v3[++k]=v1[i++];
93 p=-p;}
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 73
94 }
95 }
96 if(p==-1)
97 for(i;i<=n1;i++)
98 if (v1[i]<v3[k]) {v3[++k]=v1[i];break;}
99
100 if(p==1)
101 for(j;j<=n2;j++)
102 if (v2[j]<v3[k]) {v3[++k]=v2[j];break;}
103
104 fout<<k<<’\n’;
105 }
106
107 fin.close();
108 fout.close();
109 return 0;
110 }
56 else i++;
57 }
58
59 if(culoare==1)
60 while(j<=n)if(ales>L[j]){lmax1++;break;}else j++;
61 else while(i<p)if(ales>L[i]){lmax1++;break;}else i++;
62
63 i=1;j=p+1;lmax2=1;culoare=2;ales=L[p];///plec cu primul galben
64 while(i<p&&j<=n)
65 {
66 if(culoare==1)
67 if(L[j]<ales) {lmax2++;ales=L[j++];culoare=2;}
68 else j++;
69 else
70 if(L[i]<ales) {lmax2++;ales=L[i++];culoare=1;}
71 else i++;
72 }
73
74 if(culoare==1)
75 while(j<=n)if(ales>L[j]){lmax2++;break;}else j++;
76 else while(i<p)if(ales>L[i]){lmax2++;break;}else i++;
77
78 fout<<max(lmax1,lmax2)<<’\n’;
79
80 return 0;
81 }
47 for(i=1;i<n;i++)
48 for(j=i+1;j<=n;j++)
49 if(v[i]<v[j])
50 {
51 aux=v[i];
52 v[i]=v[j];
53 v[j]=aux;
54 }
55 }
56
57 int main()
58 {
59 int i,j,k,p;
60
61 citire();
62
63 if (C==1)
64 fout<<nr_turnuri<<’ ’<<max_turn<<’\n’;
65 else
66 {
67 sortare(v1,n1);
68 sortare(v2,n2);
69
70 v1[n1+1]=500003;
71 v2[n2+1]=500002;
72 i=1;
73 j=1;
74 k=0;
75 if (v1[i]>v2[j])
76 {
77 v3[++k]=v1[i++];
78 p=1;
79 }
80 else
81 {
82 v3[++k]=v2[j++];
83 p=-1;
84 }
85
86 while(i<=n1&&j<=n2)
87 {
88 if(p==1)
89 {
90 while(j<=n2 && v2[j]>=v3[k])
91 j++;
92
93 if (j<=n2)
94 {
95 v3[++k]=v2[j++];
96 p=-p;
97 }
98 }
99
100 if(p==-1)
101 {
102 while(i<=n1 && v1[i]>=v3[k])
103 i++;
104 if(i<=n1)
105 {
106 v3[++k]=v1[i++];
107 p=-p;
108 }
109 }
110 }
111
112 if(p==-1)
113 for(i;i<=n1;i++)
114 if (v1[i]<v3[k]) {v3[++k]=v1[i];break;}
115
116 if(p==1)
117 for(j;j<=n2;j++)
118 if (v2[j]<v3[k]) {v3[++k]=v2[j];break;}
119
120 fout<<k<<’\n’;
121 }
122
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 76
123 return 0;
124 }
71 cub Cb[10001];
72
73 fin>>n;
74
75 for (i=0;i<n ;i++ )
76 {
77 fin>>L>>C;
78 Cb[i].lat=L;
79 if(C==’a’) Cb[i].cul=1; else Cb[i].cul=0;
80 }
81
82 /// sortare crescatoare struct de cuburi
83 qsort (Cb, n, sizeof(cub), compare);
84
85 /// construire turn maxim
86 cub_curent=n-1;
87 while(cub_curent>=0)
88 {
89 ///Hmax+=Cb[cub_curent].lat;
90 T++;
91 cub_curent=aleg(Cb,cub_curent); /// aleg cubul urmator
92 }
93
94 fout<<T<<endl;
95 }
96
97 int main()
98 {
99 int cerinta;
100 fin>>cerinta;
101 if(cerinta==1)
102 cerinta1();
103 else
104 cerinta2();
105 return 0;
106 }
37
38 nrturnuri++;
39 if (h>hmax) hmax=h;
40
41 fout<<nrturnuri<<" "<<hmax;
42 }
43
44 void pozitie(int p,int u,int &k)
45 {
46 int i,j,di,dj,aux;
47 char c1;
48
49 i=p;
50 j=u;di=0;dj=-1;
51
52 while(i<j)
53 {
54 if(lat[i]<lat[j])
55 {
56 aux=lat[i];
57 lat[i]=lat[j];
58 lat[j]=aux;
59 c1=c[i];
60 c[i]=c[j];
61 c[j]=c1;
62 aux=di;
63 di=-dj;
64 dj=-aux;
65 }
66
67 i=i+di;
68 j=j+dj;
69 }
70
71 k=i;
72 }
73
74 void quick(int p,int u)
75 {
76 int k;
77 if(p<u)
78 {
79 pozitie(p,u,k);
80 quick(p,k-1);
81 quick(k+1,u);
82 }
83 }
84
85 void rezolva_b()
86 {
87 int i, nrturnuri1=0,nrturnuri2=0;
88 char cul;
89
90 fin>>n;
91
92 for(i=1;i<=n;i++)
93 fin>>lat[i]>>c[i];
94
95 quick(1,n);
96 i=1;
97 while(i<=n && c[i]!=’a’) i++;
98
99 nrturnuri1=1;cul=c[i];
100 do
101 {
102 while(i<=n && c[i]==cul)
103 i++;
104 cul=c[i];
105 i++;
106 if (i<=n+1)nrturnuri1++;
107 }
108
109 while(i<=n); // !!!
110
111 i=1;
112 while(i<=n && c[i]!=’g’) i++;
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 79
113
114 nrturnuri2=1;cul=c[i];
115
116 do
117 {
118 while(i<=n && c[i]==cul) i++;
119 cul=c[i];
120 i++;
121 if (i<=n+1)nrturnuri2++;
122 } while(i<=n);
123
124 if (nrturnuri1<nrturnuri2)
125 fout<<nrturnuri2;
126 else
127 fout<<nrturnuri1;
128 }
129
130 int main()
131 { int p;
132 fin>>p;
133 if (p==1)
134 rezolva_a();
135 else
136 rezolva_b();
137 return 0;
138 }
47 }
48
49 if (h>hmax)hmax=h;
50 g<<k<<’ ’<<hmax<<’\n’;
51 }
52 else
53 {
54 // cerinta 2
55 for (i=1;i<N;i++)
56 for (j=i+1;j<=N;j++)
57 if (lat[i]<lat[j])
58 {
59 //swap(lat[i],lat[j]);
60 auxl=lat[i];
61 lat[i]=lat[j];
62 lat[j]=auxl;
63 // swap(cul[i],cul[j]);
64 auxc=cul[i];
65 cul[i]=cul[j];
66 cul[j]=auxc;
67 }
68
69 ul=lat[1];
70 uc=cul[1];
71 hmax=1;
72 for (i=2;i<=N;i++)
73 if (cul[i]!=uc)
74 {
75 hmax++;
76 uc=cul[i];
77 }
78
79 g<<hmax<<’\n’;
80 }
81
82 return 0;
83 }
36 k++;
37 }
38 hmax = max (h, hmax);
39 turnuri++; h = C[k].l;
40 k++;
41 }
42 if (ultim == 0)
43 {
44 turnuri++;
45 if (h > hmax) hmax = h;
46 }
47
48 //cerinta 2
49 for (i = 1; i < n; i++)
50 for (j = i + 1; j <= n; j++)
51 if (C[j].l > C[i].l)
52 swap(C[i], C[j]); //am ordonat descrescator dupa lungimea laturii
53 hmax2 = n; cul_ant = C[1].c;
54 i = 2;
55 while (i <= n)
56 {
57 if (C[i].c == cul_ant)
58 hmax2--;
59 else
60 cul_ant = C[i].c;
61 i++;
62 }
63 if (cerinta == 1)
64 fout << turnuri << ’ ’ << hmax << ’\n’;
65 else
66 fout << hmax2 << ’\n’;
67 return 0;
68 }
40 ++nr;
41 top = i;
42 h = L[i] % Ct;
43 }
44
45 if (h > H) H = h;
46 }
47 g << nr << " " << H << ’\n’;
48 }
49 else
50 {
51 sort(L+1, L+n+1);
52
53 /// caut diferenta de culoare
54 for(i=1; i<n; ++i)
55 if (L[i] / Ct != L[i+1] / Ct) break;
56
57 k = i;
58 /// alg. asemanator interclasarii
59 i = k; j = n;
60 nr = 1;
61 /// cu cine incepem
62 if (L[i] % Ct > L[j] % Ct)
63 {
64 top = i; i--;
65 ok = 1;
66 }
67 else
68 {
69 top = j; --j;
70 ok = 0;
71 }
72
73 while (i > 0 && j > k)
74 {
75 if (ok)
76 {
77 while (j > k && L[j] % Ct > L[top] % Ct) --j;
78 if (j > k)
79 {
80 ok = 0;
81 ++nr;
82 top = j;
83 }
84 }
85 else
86 {
87 while (i > 0 && L[i] % Ct > L[top] % Ct) --i;
88 if ( i > 0)
89 {
90 ok = 1;
91 ++nr;
92 top = i;
93 }
94 }
95 }
96
97 g << nr << ’\n’;
98 }
99
100 return 0;
101 }
OJI 2017
Cerinţe
Scrieţi un program care să citească numerele k, n şi un şir de n numere naturale şi să afişeze:
a) cele mai mari 3 numere accesibile, nu neapărat distincte, din şirul de n numere;
b) câte dintre numerele din şirul dat care nu sunt accesibile, devin accesibile prin eliminarea
exact a unei cifre;
c) cel mai mic şi cel mai mare număr accesibil format din k cifre;
d) numărul numerelor accesibile pare de k cifre şi numărul numerelor accesibile impare de
k cifre.
Date de intrare
Fişierul de intrare accesibil.in conţine pe prima linie un număr natural p. Pentru toate testele
de intrare, numărul p este un număr din mulţimea r1, 2, 3, 4x. Pe linia a doua a fişierului de intrare
se găsesc k şi n, iar pe a treia linie a fişierului de află n numere naturale separate prin câte un
spaţiu.
Date de ieşire
Dacă valoarea lui p este 1, se va rezolva numai punctul a) din cerinţe. În acest caz, ı̂n fişierul
de ieşire accesibil.out se vor scrie, ı̂n ordine crescătoare, separate prin câte un spaţiu, cele mai
mari trei numere accesibile dintre cele n numere aflate pe a treia linie a fişierului. Se garantează
că pentru p 1 sunt cel puţin trei numere accesibile ı̂n şirul de n numere.
Dacă valoarea lui p este 2, se va rezolva numai punctul b) din cerinţe. În acest caz, ı̂n fişierul
de ieşire se va scrie numărul numerelor din şirul dat care nu sunt accesibile, dar care ar deveni
accesibile dacă li s-ar elimina o cifră.
Dacă valoarea lui p este 3, se va rezolva numai punctul c) din cerinţe. În acest caz, ı̂n fişierul de
ieşire se vor scrie două valori, separate printr-un spaţiu, reprezentând cel mai mic număr accesibil
de k cifre şi cel mai mare număr accesibil de k cifre. Dacă cele două numere ce ar trebui afişate
coincid se va afişa valoarea lor comună o singură dată.
Dacă valoarea lui p este 4, se va rezolva numai punctul d) din cerinţe. În acest caz, ı̂n fişierul
de ieşire se vor scrie două valori reprezentând numărul numerelor accesibile pare de k cifre şi
numărul numerelor accesibile impare de k cifre, ı̂n această ordine, separate prin spaţiu.
83
CAPITOLUL 6. OJI 2017 6.1. ACCESIBIL - OJI 2017 84
a Pentru a rezolva cerinţele a) şi b) nu folosim valoarea lui k, iar pentru cerinţele c) şi d) nu
folosim şirul de n numere;
a Se acordă: 40 de puncte pentru cerinţa a); 30 de puncte pentru cerinţa b); 10 puncte pentru
cerinţa c); 10 puncte pentru cerinţa d);
a Se acordă 10 puncte din oficiu.
Exemple
accesibil.in accesibil.out Explicaţii
1 234 5678 5678 Numerele accesibile sunt 12, 5678,
38 234 şi 5678. Cele mai mari 3 valori,
6 12 235 5678 90 987 234 5678 crescător: 234 5678 5678 (p fiind 1 se
rezolvă doar cerinţa a).
2 5 Dacă eliminăm o cifră din 1238, 689,
39 4560, 7023, 1238 se obţin numere acce-
4 34 123 1238 301 689 4560 7023 1238 sibile (p fiind 2 se rezolvă doar cerinţa
b).
3 1234 6789 Cel mai mic număr accesibil de 4 cifre
43 este 1234 şi cel mai mare este 6789 (p
12 345 67 fiind 3 se rezolvă doar cerinţa c).
4 01 Există un singur număr accesibil de
93 9 cifre impar, respectiv 123456789 şi
12 345 67 niciun număr par de 9 cifre (p fiind 4
se rezolvă doar cerinţa d).
Autor: prof. Ana-Maria Arişanu, Colegiul National ”Mircea cel Batran” Rm. Valcea
a) Se citesc cele n numere, cand se intalneste un numar accesibil se actualizeaza, dupa caz,
valorile variabilelor max1, max2 si max3, initializate cu 0.
O solutie mai putin eficienta ar fi sa se memoreze toate numerele accesibile intr-un vector,
sa se sorteze acesta si sa se afiseze cele mai mari trei valori din vector.
b) Pentru numerele din sir ce au macar 3 cifre si nu sunt accesibile se determina toate numerele
ce se pot obtine prin eliminarea unei cifre. Daca un astfel de numar obtinut este accesibil
se incrementeaza variabila de numarare.
c) Doar pentru cazul k 9 cele doua numere coincid, valoarea fiind 123456789. Pentru k $9
se afiseaza 12...k si 10 k 11 k ...9
d) In total sunt 10 k numere accesibile formate din k cifre. Dintre acestea 10 k ©2 sunt
pare si 11 k ©2 sunt impare.
10 {
11 int u,c;
12 if (n<10) return 0;
13 u=n%10;
14 n=n/10;
15 while (n!=0)
16 {
17 c=n%10;
18 if (c+1!=u) return 0;
19 u=c;
20 n=n/10;
21 }
22 return 1;
23 }
24
25 int devine_accesibil(int n)
26 {
27 if(accesibil(n)|| n<100) return 0;
28 long long p=1;
29 int y;
30 while (p<=n)
31 {
32 y=n/(p*10)*p+n%p;
33 if (accesibil(y))
34 {
35 //cout<<y<<’ ’;
36 return 1;}
37 p=p*10;
38 }
39
40 return 0;
41 }
42
43 int main()
44 {
45 int p,n,k,x,nr=0,m1=0,m2=0,m3=0;
46
47 f>>p>>k>>n;
48
49 if (p==1)
50 {
51 for (int i=1;i<=n; i++)
52 {
53 f>>x;
54 if (accesibil(x))
55 {
56 if (x>=m1) { m3=m2;m2=m1;m1=x;}
57 else
58 if (x>=m2) { m3=m2;m2=x;}
59 else
60 if (x>=m3) { m3=x;}
61 }
62 }
63 if (m3==0) g<<-1<<’\n’;
64 else
65 g<<m3<<’ ’<<m2<<’ ’<<m1<<’\n’;
66 }
67 else
68 if (p==2)
69 {
70 for (int i=1;i<=n; i++)
71 {
72 f>>x;
73 // g<<’\n’<<i<<’ ’<<x<<’ ’;
74 if (devine_accesibil(x))
75 {
76 // g<<x;
77 nr++;
78 }
79 }
80 g<<nr<<’\n’;
81 }
82 else
83 if (p==3)
84 {
85 for (int i=1;i<=k;i++) g<<i;
CAPITOLUL 6. OJI 2017 6.1. ACCESIBIL - OJI 2017 86
86 if (k!=9)
87 {
88 g<<’ ’;
89 for (int i=1;i<=k;i++) g<<9-k+i;
90 }
91 g<<’\n’;
92 }
93 else
94 {
95 g<<(10-k)/2<<’ ’<<(10-k+1)/2<<’\n’;
96 }
97
98 return 0;
99 }
19 while (x > 9)
20 {
21 c = x % 10;
22 x /= 10;
23 if (c - x % 10 != 1)
24 return 0;
25 }
26 return 1;
27 }
28
29 int main()
30 {
31 int i, V3 = 0, V2 = 0, V1 = 0, c, contor = 0;
32
33 fin >> cerinta;
34 fin >> k >> n;
35 for (i = 1; i <= n; i++) fin >> V[i];
36
37 //cerinta 1
38 if (cerinta == 1)
39 {
40 for (i = 1; i <= n; i++)
41 {
42 if (accesibil(V[i]))
43 {
44 if (V[i] > V1)
45 V3 = V2, V2 = V1, V1 = V[i];
46 else
47 if (V[i] > V2)
48 V3 = V2, V2 = V[i];
49 else
50 if (V[i] > V3)
51 V3 = V[i];
52 }
53 }
54
55 if (V3 == 0)
56 fout << -1 << ’\n’;
57 else
58 fout << V3 << ’ ’ << V2 << ’ ’ << V1 << ’\n’;
59
60 return 0;
61 }
62
63 //cerinta 2
64 if (cerinta == 2)
65 {
66
67 for (i = 1; i <= n; i++)
68 {
69 p10 = 1;
70 x = V[i];
71 nrcifre = 0;
72 while (x)
73 nrcifre++, x /= 10;
74
75 x = V[i];
76 if (nrcifre > 2 && !accesibil(x))
77 while (nrcifre)
78 {
79 p10 *= 10;
80 p10_fata = p10;
81 p10_spate = p10 / 10;
82 c = x / p10_spate % 10; //cifra eliminata
83 fata = x / p10_fata;
84 spate = x % p10_spate;
85 x = fata * p10_spate + spate;
86
87 if (x > 10 && accesibil(x))
88 {
89 contor++;
90 //fout << V[i] << ’ ’;
91 break;
92 }
93
94 x = (fata * 10 + c) * p10_spate + spate;
CAPITOLUL 6. OJI 2017 6.1. ACCESIBIL - OJI 2017 89
95 nrcifre--;
96 }
97 }
98 fout << contor << ’\n’;
99 return 0;
100 }
101
102 //cerinta 3
103 if (cerinta == 3)
104 {
105 x = 0;
106 for (i = 1; i <= k; i++) x = x * 10 + i;
107 xx = 0;
108 for (i = 10 - k; i <= 9; i++) xx = xx * 10 + i;
109
110 if (x == xx)
111 fout << x << ’\n’;
112 else
113 fout << x << ’ ’ << xx << ’\n’;
114
115 return 0;
116 }
117
118 if (cerinta == 4)
119 {
120 fout << Pare[k] << ’ ’ << Impare[k] << ’\n’;
121 return 0;
122 }
123 }
44 {
45
46 int x,p=1,nr=0,k=0,i;
47 while(x)
48 {
49 x=x/10;
50 k++;
51 }
52
53 for(i=1;i<=k;i++)
54 {
55 nr=n;
56 nr=nr/p/10*p+nr%p;
57 p=p*10;
58 if(verif(nr) and nr>9) return 1;
59 }
60 return 0;
61 }
62
63 int elimin(long long n)
64 {
65 int k=0,x;
66 if(n%10!=n/10%10+1)
67 {
68 n=n/10;
69 k++;
70 }
71
72 x=n%10;
73 n=n/10;
74 while(n)
75 {
76 if(x==1 and n%10==0 )
77 {
78 k=0;
79 break;
80 }
81 if(n%10!=x-1)
82 k++;
83 else
84 x=n%10;
85 n=n/10;
86 }
87
88 if(k==1)
89 return 1;
90 else
91 return 0;
92 }
93
94 int mare(int n)
95 {
96 int i,nr=0;
97 for(i=9-n+1; i<=9; i++)
98 nr=nr*10+i;
99 return nr;
100 }
101
102 int mic(int n)
103 {
104 int nr=0,i;
105 for(i=1; i<=n; i++)
106 nr=nr*10+i;
107 return nr;
108 }
109 int numarpare(int n)
110 {
111 if(n==9)
112 return 0;
113 if(n==8 or n==7)
114 return 1;
115 if(n==6 or n==5)
116 return 2;
117 if(n==4 or n==3)
118 return 3;
119 if(n==2 or n==1)
CAPITOLUL 6. OJI 2017 6.1. ACCESIBIL - OJI 2017 91
120 return 4;
121
122 return -1;
123 }
124
125 int numarimpare(int n)
126 {
127 if(n==9 or n==8)
128 return 1;
129 if(n==7 or n==6)
130 return 2;
131 if(n==5 or n==4)
132 return 3;
133 if(n==3 or n==2)
134 return 4;
135 if(n==1)
136 return 5;
137
138 return -1;
139 }
140
141 long long n,v[100001],a[100001],i,p,k,t;
142
143 int main()
144 {
145 f>>p;
146 f>>k>>n;
147 for(i=1; i<=n; i++)
148 f>>v[i];
149
150 if(p==1)
151 {
152 for(i=1; i<=n; i++)
153 if(verif(v[i]) and v[i]>9)
154 a[++t]=v[i];
155 if(t>2)
156 {
157 sort(a+1,a+t+1);
158 g<<a[t-2]<<" "<<a[t-1]<<" "<<a[t];
159 }
160 else
161 g<<-1;
162 }
163
164 if(p==2)
165 {
166 int aaa=0;
167 for(i=1; i<=n; i++)
168 if(verif(v[i])==0)
169 {
170 if(verific_accesibil(v[i]))
171 aaa++;
172 }
173
174 g<<aaa;
175 }
176
177 if(p==3)
178 {
179 if(k==9)
180 g<<mic(k);
181 else
182 g<<mic(k)<<" "<<mare(k);
183 }
184
185 if(p==4)
186 {
187 g<<numarpare(k)<<" "<<numarimpare(k);
188 }
189
190 return 0;
191 }
1 #include <fstream>
2 #include<iostream>
3
4 using namespace std;
5
6 ifstream f("accesibil.in");
7 ofstream g("accesibil.out");
8
9 int n,k,x[1000001],min1,max1,max2,max3,n1,n2;
10
11 int accesibil(int x)
12 {
13 int c,ok=1;
14 if (x<10) return 0;
15 c=x%10;
16 x=x/10;
17
18 while(x&& ok==1)
19 {
20 if(c!=x%10+1) ok=0;
21 else
22 {
23 c=x%10;
24 x=x/10;
25 }
26 }
27 return ok;
28 }
29
30 void maxime(int n, int x[], int &max1, int &max2, int &max3)
31 {
32 int i;
33 max1=max2=max3=0;
34 for(i=1;i<=n;i++)
35 {
36 if (accesibil(x[i]))
37 if(max1<x[i])
38 {
39 max3=max2;
40 max2=max1;
41 max1=x[i];
42 }
43 else
44 if (max2<x[i])
45 {
46 max3=max2;
47 max2=x[i];
48
49 }
50 else
51 if (max3<x[i])
52 max3=x[i];
53 }
54 }
55
56 int nrcifre(int x)
57 {
58 int k=0;
59 while(x)
60 {
61 k++;
62 x=x/10;
63 }
64 return k;
65 }
66
67 int devine(int x)
68 {
69 int k,p1=10,p2=1,nr,i;
70
71 k=nrcifre(x);
72
73 for(i=1;i<=k;i++)
74 {
75 nr=(x/p1)*p2+x%p2;
76 p1=p1*10;
CAPITOLUL 6. OJI 2017 6.1. ACCESIBIL - OJI 2017 93
77 p2=p2*10;
78 if (accesibil(nr)) return 1;
79 }
80
81 return 0;
82 }
83
84
85 int nr_neacc(int n, int x[])
86 {
87 int i,nr=0;
88
89 for(i=1;i<=n;i++)
90 if(x[i]>99)
91 if (!accesibil(x[i]))
92 if (devine(x[i])==1)
93 nr++;
94
95 return nr;
96 }
97
98 void min_max(int k)
99 {
100 int i;
101
102 for(i=1;i<=k;i++)
103 g<<1+i-1;
104
105 g<<" ";
106
107 if (9-k+1!=1)
108 for(i=9-k+1;i<=9;i++)
109 g<<i;
110 }
111
112 void nr_pare_imp(int k, int &n1, int &n2)
113 {
114 switch (k)
115 {
116 case 9: n1=0;break;
117 case 8:
118 case 7: n1=1;break;
119 case 6:
120 case 5: n1=2;break;
121 case 4:
122 case 3: n1=3;break;
123 case 2:
124 case 1: n1=4;
125 }
126 switch (k)
127 {
128 case 9:
129 case 8: n2=1;break;
130 case 7:
131 case 6: n2=2;break;
132 case 5:
133 case 4: n2=3;break;
134 case 3:
135 case 2: n2=4;break;
136 case 1: n2=5;
137 }
138 }
139
140
141 int main()
142 {
143 int p,i;
144 f>>p>>k>>n;
145
146 for(i=1;i<=n;i++)
147 {
148 f>>x[i];
149 //cout<<"x["<<i<<"]="<<x[i]<<endl;
150 }
151
152 if (p==1)
CAPITOLUL 6. OJI 2017 6.2. FERMIER - OJI 2017 94
153 {
154 maxime(n,x,max3,max2,max1);
155
156 if(max1==0||max2==0||max3==0)
157 g<<-1;
158 else
159 g<<max1<<" "<<max2<<" "<<max3<<endl;
160 }
161 else
162 if (p==2)
163 {
164 g<<nr_neacc(n,x)<<endl;
165 }
166 else
167 if (p==3)
168 {
169 min_max(k);
170 }
171 else
172 {
173 nr_pare_imp(k,n1,n2);
174 g<<n1<<" "<<n2;
175 }
176
177 return 0;
178 }
La o plantaţie i se poate ajunge de la depozit trecând prin plantaţiile 1, 2, ..., i 1 sau prin
plantaţiile n, n 1, ..., i 1, alegerea făcându-se ı̂n funcţie de traseul cel mai scurt. Se cunosc
aceste distanţe, precum şi cantitatea de ı̂ngrăşăminte necesară pentru fiecare plantaţie.
La fiecare ı̂ncărcare, Dorel ia din depozit exact cantitatea c. Dorel vrea să-şi organizeze bine
munca la fermă şi să consume cât mai puţină benzină prin alegerea celor mai scurte trasee de par-
curs. Plantaţiile trebuie să fie aprovizionate obligatoriu ı̂n ordinea următoare: mai intâi plantaţia
1, apoi plantaţia 2, plantaţia 3, ..., plantaţia n. În plus, şi-a propus să ı̂ncarce o nouă cantitate
de ı̂ngrăşământ doar după ce a folosit toată cantitatea ı̂ncărcată anterior.
CAPITOLUL 6. OJI 2017 6.2. FERMIER - OJI 2017 95
Cerinţe
Ajutaţi-l pe Dorel să calculeze distanţa parcursă pentru a transporta ı̂ngrăşăminte la toate
cele n plantaţii, conform cerinţelor.
Date de intrare
Fişierul de intrare fermier.in conţine pe prima linie numerele naturale n şi c, separate printr-
un spaţiu. A doua linie conţine numerele naturale d0 , d1 , d2 , ..., dn1 , dn separate două câte două
prin câte un spaţiu, unde d0 este distanţa dintre prima plantaţie şi depozit, di (1 & i & n 1) este
distanţa intre plantaţia i şi plantaţia i 1, iar dn este distanţa dintre plantaţia n şi depozit. Pe
linia a treia se găsesc numerele naturale q1 , q2 , ..., qn1 , qn separate două câte două prin câte un
spaţiu, qi reprezentând cantitatea de ı̂ngrăşăminte necesară pentru plantaţia i (1 & i & n).
Date de ieşire
Fişierul de ieşire fermier.out va conţine pe prima linie un număr natural conform cerinţei.
Exemple
Se folosesc doi vectori de deplasare, unul pentru deplasarea de la depozit la plantatie in sensul
acelor de ceasornic si unul pentru deplasarea in sens invers.
Se pastreaza intr-un vector directia care trebuie aleasa pentru deplasarea pe drumul cel mai
scurt la o plantatie.
Se incepe apoi simularea deplasarii masinii si se calculeaza drumul parcurs.
Se aprovizioneaza mai intai plantatia 1, se calculeaza distanta parcursa pentru a realiza aceasta
cerinta. Se pastreaza intr-o variabila cantitatea de ingrasaminte ramasa dupa aprovizionarea
integrala a plantatiei 1.
Se alege apoi drumul cel mai scurt pentru a ajunge la plantatia 2, direct (deplasandu-se in
sensul acelor de ceasornic) sau invers, trecand prin depozit.
Se aprovizioneaza in continuare complet plantatia 2 si se continua in acelasi mod cu celelalte
plantatii, masina intorcandu-se in final la depozit. Se procedeaza ca la plantatia 1.
15 {
16 st[i]=d[0];
17 dr[i]=0;
18 for (j=n;j>=1;j--)
19 dr[i]+= d[j];
20 }
21 else
22 if (i==n)
23 {
24 dr[i]=d[n];
25 st[i]=d[0];
26 for(j=1;j<=n-1;j++)
27 st[i]+=d[j];
28 }
29 else
30 {
31 st[i]=st[i-1]+d[i-1];
32 dr[i]=dr[i-1]-d[i-1];
33 }
34
35 if (st[i]<dr[i])
36 sens[i]=1;
37 else
38 sens[i]=-1;
39 }
40
41 int km()
42 {
43 long long nr,nr1,rest;
44 int i,j,depoz;
45
46 nr=0;
47 depoz=0;
48 i=1;
49 rest=maxx;
50
51 while (i<=n)
52 {
53 if (depoz==0)
54 {
55 rest=maxx;
56 if (p[i]!=0)
57 if (sens[i]==1)
58 {
59 nr1=p[i]/maxx;
60 nr+=nr1*2*st[i];
61 rest=maxx*nr1;
62 if (p[i]%maxx!=0)
63 {
64 nr+=st[i]; depoz=1;rest+=maxx;
65 }
66
67 if (rest<p[i])
68 {
69 rest=0;
70 p[i]-=rest;
71 }
72 else
73 {
74 rest=rest-p[i];
75 p[i]=0;
76 }
77 }
78 else
79 {
80 nr1=p[i]/maxx;
81 nr+=nr1*2*dr[i];
82 rest=maxx*nr1;
83 if (p[i]%maxx!=0)
84 {
85 nr+=dr[i]; depoz=1; rest+=maxx;
86 }
87
88 if (rest<=p[i])
89 {
90 p[i]-=rest;
CAPITOLUL 6. OJI 2017 6.2. FERMIER - OJI 2017 98
91 rest=0;
92 }
93 else
94 {
95 rest=rest-p[i];
96 p[i]=0;
97 }
98 }
99 else i++;
100 }
101 else
102 if (rest==0 || i==n)
103 //ma intorc in depozit
104 if (sens[i]==1)
105 {
106 nr+=st[i];
107 depoz=0;
108 if (p[i]==0) i++;
109 }
110 else
111 {
112 nr+=dr[i];
113 depoz=0;
114 if (p[i]==0) i++;
115 }
116 else
117 {
118 //merg la urmatorul
119 if (d[i]<st[i]+dr[i+1])
120 nr+=d[i];
121 else
122 nr+=st[i]+dr[i+1];
123
124 if (rest<p[i+1])
125 {
126 p[i+1]-=rest;
127 rest=0;
128 depoz=1;
129 }
130 else
131 {
132 rest-=p[i+1];
133 p[i+1]=0;
134 }
135
136 i++;
137 }
138 }
139
140 return nr;
141 }
142
143 int main()
144 {
145 int i;
146
147 f>>n>>maxx;
148
149 for(i=0;i<=n;i++)
150 f>>d[i];
151
152 for(i=1;i<=n;i++)
153 f>>p[i];
154
155 for (i=1;i<=n;i++)
156 deplasari_st_dr(i);
157
158 g<<km();
159
160 return 0;
161 }
2
3 using namespace std;
4
5 int a[10010], d[10010], q[10010];
6 int n, c, sumd, sol, rest, stop;
7
8 int main ()
9 {
10 ifstream fin ("fermier.in");
11 ofstream fout("fermier.out");
12
13 fin>>n>>c;
14 for (int i=1;i<=n+1;i++)
15 {
16 fin>>d[i];
17 sumd += d[i];
18 }
19
20 for (int i=1;i<=n;i++)
21 fin>>q[i];
22
23 for (int i=1;i<=n;i++)
24 {
25 a[i] = a[i-1] + d[i];
26 // b[i] = sumd - a[i];
27 }
28
29 // a[i] = distanta de la depozit la i mergand normal
30 // sumd - a[i] = distanta de la depozit la i mergand invers;
31
32 for (int i=1; i<=n; i++)
33 {
34 int transporturi = q[i] / c;
35
36 if (q[i] % c != 0)
37 transporturi++;
38
39 sol += (2*transporturi - 1) * min(a[i], sumd-a[i]);
40
41 if (q[i] % c != 0)
42 rest = c - q[i] % c;
43 else
44 rest = 0;
45
46 if (rest == 0)
47 {
48 sol += min(a[i], sumd-a[i]);
49 continue;
50 }
51
52 if (i == n)
53 {
54 sol += min(a[i], sumd-a[i]);
55 break;
56 }
57
58 while (i+1 != n+1 && q[i+1] <= rest)
59 {
60 rest -= q[i+1];
61 sol += min( d[i+1], sumd-d[i+1] );
62 i++;
63 if (i == n)
64 {
65 stop = 1;
66 sol += min(a[n], sumd-a[n]);
67 break;
68 }
69 }
70
71 if (stop)
72 break;
73
74 if (rest != 0 && i+1 != n+1)
75 {
76 q[i+1] -= rest;
77 sol += min(d[i+1], sumd-d[i+1]) + min(a[i+1], sumd-a[i+1]);
CAPITOLUL 6. OJI 2017 6.2. FERMIER - OJI 2017 100
78 }
79
80 if (rest == 0)
81 sol += min(a[i], sumd-a[i]);
82 }
83
84 fout<<sol;
85
86 return 0;
87 }
63 q[y]=0;
64 y++;
65 }
66 else
67 {
68 q[y]=q[y]-ca;
69 ca=0;
70 }
71 }
72 else
73 {
74 ca=c;
75 drumtotal=drumtotal+dmin(x,0);
76 x=0;
77 }
78 }
79
80 if(x!=0)
81 drumtotal=drumtotal+dmin(x,0);
82 }
83
84 int main()
85 {
86 ofstream fout("fermier.out");
87 read();
88 solve();
89 fout<<drumtotal;
90 return 0;
91 }
44 }
45
46 if(q[i]==b)
47 {
48 q[i]=0;
49 b=c;
50 total+=dmin_depozit; //ma duc la depozit si reumplu masina
51 i++; //o sa ma duc la parcela urmatoare
52 }
53 else
54 if(q[i]<b)
55 {
56 b-=q[i];
57 q[i]=0;
58 if(b==0)
59 {
60 total+=dmin_depozit;//ma duc la depozit
61 b=c; //reumplu
62 i++; //ma duc pe urmatoarea parcela
63 }
64 else
65 {
66 i++;
67 if(i>n)
68 total+=dmin_depozit;//ma duc inapoi la depozit
69 }
70
71 }
72 }
73 g<<total;
74 return 0;
75 }
41 q[i]=0;
42 cant=cant+v;
43 i++;
44 }
45 else
46 {
47 m=m-q[i];
48 q[i]=0;
49 if (i==n)
50 {
51 v1=d[n];
52 v2=t-v1;
53 v=min(v1,v2);
54 cant+=v;
55 i++;
56 }
57 else
58 for (j=i+1; j<=n; j++)
59 {
60 //cout<<"Plantatia "<<j<<" are in camion "<<m<<’\n’;
61 v1=d[j-1];
62 v2=t-v1;
63 v=min(v1,v2);
64 cant+=v;
65 if (m<q[j])
66 {
67 q[j]=q[j]-m; m=0;
68 // de la plantatia j se intoarce la depozit
69 v1=0;
70 for (l=j; l<=n; l++) v1=v1+d[l];
71 v2=t-v1;
72 v=min(v1,v2);
73 cant+=v;
74 i=j;
75 break;
76 }
77 else
78 if (m==q[j])
79 {
80 q[j]=0;
81 // de la plantatia j se intoarce la depozit
82 v1=0;
83 for (l=j; l<=n; l++) v1=v1+d[l];
84 v2=t-v1;
85 v=min(v1,v2);
86 cant+=v;
87 i=j+1;
88 break;
89 }
90 else
91 {
92 m=m-q[j];
93 q[j]=0;
94 if (j==n)
95 {
96 v1=d[n];
97 v2=t-v1;
98 v=min(v1,v2);
99 cant+=v;
100 i=n+1;
101 }
102 }
103
104 }
105 }
106
107 }
108
109 g<<cant<<’\n’;
110 return 0;
111 }
OJI 2016
Cerinţe
Scrieţi un program care să citească numărul N de cutiuţe şi numerele formate de elevii fiecărei
perechi şi care să determine:
1) Numărul de cutiuţe din care Andrei poate lua jetoane respectând condiţia pusă de doamna
ı̂nvăţătoare;
2) Care este cel mai mare număr nenul pe care ı̂l poate forma Andrei respectând aceeaşi
condiţie.
Date de intrare
Fişierul cifre.in conţine pe prima linie numărul natural P reprezentând cerinţa din problemă
care trebuie rezolvată. Pe a doua linie numărul natural N , iar pe următoarele N linii câte două
numere naturale separate printr-un spaţiu reprezentând numerele formate de elevii fiecărei perechi.
Date de ieşire
Dacă valoarea lui P este 1, fişierul de ieşire cifre.out va conţine pe prima linie un număr
natural reprezentând rezolvarea primei cerinţe, adică numărul de cutiuţe din care Andrei poate
lua jetoane.
Dacă valoarea lui P este 2, fişierul de ieşire cifre.out va conţine pe prima linie un număr
natural reprezentând rezolvarea celei de a doua cerinţe, adică numărul maxim pe care ı̂l poate
forma Andrei.
104
CAPITOLUL 7. OJI 2016 7.1. CIFRE - OJI 2016 105
a 0 $ N & 10000
a 1 & numărul de jetoane al fiecarui elev & 9
a 0 & cifra scrisă pe orice jeton & 9
a Se garantează că există cel puţin o cutiuţă din care Andrei ı̂şi poate forma număr nenul
a Pentru rezolvarea corectă a fiecărei cerinţe se obţin câte 50 de puncte
Exemple
cifre.in cifre.out Explicaţii
1 1 Cu jetoanele extrase din prima cutiuţă Andrei nu poate
3 forma un număr diferit de 0. Din a doua cutiuţă Andrei nu
1010 2000 poate lua jetoane astfel ı̂ncât cei doi elevi să ı̂şi mai poată
12 34 forma numerele 12 şi 34. Andrei poate extrage jetoane
1515 552 doar din a treia cutiuţă(două jetoane cu cifra 5).
2 5311 Numărul maxim pe care Andrei ı̂l poate forma este 5311
5 şi se obţine din cutiuţa a treia.
16815 38861
12 385
5137131 6551813
15033 11583
4704 240
Se determina cifrele comune pentru cele 2 numere ce formeaza o pereche, utilizand doi vectori
de aparitii.
Pentru fiecare cifra comuna se determina minimul dintre a si b, unde a este numarul de aparitii
a cifrei in primul numar iar b este numarul de aparitii a cifrei in cel de-al doilea numar.
Daca exista cifre comune se formeaza valoarea maxima luand toate cifrele comune in ordinea
descrescatoare a valorii lor.
Daca valoarea obtinuta este strict pozitiva, se numara ca solutie, actualizandu-se daca este
cazul si valoarea maxima pe care o poate forma Andrei.
Cerinţe
Cunoscând literele numelui, scrieţi un program care determină şi afişează ı̂n fişierul de ieşire:
1. Numărul de caractere * pe care trebuie să le utilizeze pentru a completa ultimul rând;
2. Prima literă de pe fiecare rând din figura iniţială;
3. Şirul literelor de pe fiecare rând, după rotirea foii de hârtie.
Date de intrare
Fişierul de intrare litere.in conţine pe prima linie un număr natural P reprezentând cerinţa
din problemă care trebuie rezolvată, pe a doua linie un număr natural N , reprezentând numărul
de litere din nume. Pe a treia linie din fişier se află numele copilului format din N litere, majuscule
din alfabetul englez. Literele sunt separate ı̂ntre ele prin câte un spaţiu.
Date de ieşire
Dacă valoarea lui P este 1, fişierul de ieşire litere.out va conţine un număr natural,
reprezentând numărul de caractere * din figură.
CAPITOLUL 7. OJI 2016 7.2. LITERE - OJI 2016 107
Dacă valoarea lui P este 2, fişierul de ieşire litere.out va conţine, pe o singură linie, un şir de
litere, separate ı̂ntre ele prin câte un spaţiu, format din prima literă de pe fiecare rând al figurii,
ı̂nainte de rotirea sa, ı̂ncepând cu primul rând până la ultimul.
Dacă valoarea lui P este 3, fişierul de ieşire litere.out va conţine literele obţinute după rotirea
figurii iniţiale, afişarea făcându-se ı̂n ordine de sus ı̂n jos, iar ı̂n cadrul unui rând, ı̂n ordine de la
stânga la dreapta. Fiecare rând de litere va fi afişat ı̂n fişier pe câte o linie, iar literele situate pe
acelaşi rând vor fi separate ı̂ntre ele prin câte un spaţiu.
Exemple
1 5
2 3 4 7 6 2
5 6 7 8 9 9 8 4 3 1
Dupa rotire, varful noii figuri poate fi calculat direct, x 1 x 1 1, unde x reprezinta
nr. de niveluri;
Construim un vector ord cu noile numere de ordine ale triughiurilor.
Pentru fiecare nivel i 2, x calculam numerele de ordine ale celor 2 i 1 triunghiuri.
Se vor afisa caracterele v ordj diferite de caracterul *.
CAPITOLUL 7. OJI 2016 7.2. LITERE - OJI 2016 108
OJI 2015
Romburile sunt unite, consecutiv, ca ı̂n exemplul din imaginea alăturată. Săgeţile indică sensul
ı̂n care bunica ţese covorul.
Ca să nu uite modelul, Mara scrie pe caiet, ı̂ncepând cu 1, numere consecutive care să indice
modul ı̂n care ţese bunica covorul.
În exemplul următor este reprezentat modul ı̂n care se ţese un model format din patru romburi.
Cerinţe
Cunoscându-se numerele n şi k să se determine:
1. numărul maxim de romburi complete care pot forma modelul unui covor, descris cu ajutorul
unui şir format din maximum n numere naturale consecutive (primul număr din şir fiind 1);
109
CAPITOLUL 8. OJI 2015 8.1. COVOR - OJI 2015 110
Date de intrare
Fişierul de intrare covor.in conţine pe prima linie, separate prin spaţiu, două numere naturale:
n (reprezentând numărul maxim de numere consecutive utilizate la descrierea unui model) şi k
(reprezentând un număr din şirul celor n numere consecutive). Linia a doua conţine una dintre
valorile 1 sau 2 reprezentând cerinţa 1, dacă se cere determinarea numărului maxim de romburi
complete care pot forma modelul unui covor descris cu ajutorul unui şir format din maximum
n numere, respectiv cerinţa 2, dacă se cere determinarea celui mai mic indice al unui romb ce
conţine numărul k.
Date de ieşire
Fişierul de ieşire covor.out conţine pe prima linie o valoarea naturală reprezentând numărul
maxim de romburi complete care pot forma modelul unui covor, descris cu ajutorul unui şir format
din maximum n numere, dacă cerinţa a fost 1, respectiv un număr natural reprezentând cel mai
mic indice al unui romb ce conţine numărul k, dacă cerinţa a fost 2.
Exemple
covor.in covor.out Explicaţii
40 32 4 Cel mai mare număr de romburi ce pot forma un model descris
1 cu maximum 40 de numere este 4.
40 32 3 Numărul 32 se află pe cel de-al treilea romb.
2
37 7 2 Numărul 7 se află pe cel de-al doilea şi pe cel de-al treilea romb.
2 Cel mai mic indice al unui romb ce conţine numărul 7 este 2.
14 12 0 Numărul 12 nu se află pe niciunul dintre cele două romburi ce
2 pot forma un model descris cu maximum 14 de numere.
Se observa ca primul romb este format din 4 patratele, al doilea este format din 8 patratele,
... rombul cu indicele i este format din 4i patratele.
Atunci cand formeza un covor, romburile se suprapun =¿ un model format din r romburi va fi
descris printr-un sir format din 4x1+4x2+....+4xr-(r-1) = 4r(r+1)/2-(r-1)=2r(r+1)-(r-1) numere.
Pentru determinarea numarului maxim de romburi complete care pot forma modelul unui
covor, descris cu ajutorul unui sir format din maximum n numere, se calculeaza cel mai mare
numar r cu proprietatea 2r(r+1)-(r-1)¡=n.
Pentru determinarea celui mai mic indice al unui romb ce contine numarul k, se calculeaza
numarul de numere necesare pentru completarea romburilor la o trecere dus, respectiv intors, de
la rombul 1 la rombul r, respectiv de la rombul r la rombul 1, si se calculeaza pozitia lui k in
raport cu aceasta valoare.
Se observa ca atunci cand k este o valoare ce se afla pe doua romburi, primul romb pe care se
gaseste este cel care se completeaza la prima trecere (dus).
CAPITOLUL 8. OJI 2015 8.1. COVOR - OJI 2015 111
27 return 0;
28 }
29
30 int a, b, romb = 2;
31 a = 1; b = 3;
32 r = 1;
33 while(romb <= i)
34 {
35 r += 2;
36 a = b + 1;
37 b = a + r;
38 //cout << r << ’ ’ << a << ’ ’ << b << endl;
39 if (a <= k && k <= b)
40 {
41 g << romb;
42 return 0;
43 }
44 romb++;
45 }
46
47 romb--;
48
49 r = r + 1;
50 while(romb > 0)
51 {
52 r -= 2;
53 a = b + 1;
54 b = a + r;
55 //cout << r << ’ ’ << a << ’ ’ << b << endl;
56 if (a <= k && k <= b)
57 {
58 g << romb;
59 return 0;
60 }
61 romb--;
62 }
63
64 g << 0;
65 return 0;
66 }
33 else
34 {
35 for (j=1; j<i; j++)
36 if (k<=1+j*(j+1)) {g<<j; break;}
37 if ((k>i*(i+1)+1))
38 for (j=i; j>0; j--)
39 {
40 if (k<=x+2*j-1) {g<<j; break;}
41 else x+=2*j-1;
42 }
43 }
44 }
45 }
46 }
47
48 g<<’\n’;
49 return 0;
50 }
9
10 int main()
11 {
12 f>>n>>k>>v;
13 i=1;
14 while(2*i*(i+1)-i+1<=n)i++;
15
16 i--;
17 if(v==1) {g<<i<<’\n’;return 0;}
18
19 l=2*i*(i+1)-i+1;
20 if(k>l) g<<"0\n";
21 else
22 {
23 if(k<=(i+1)*(i+2)-2*i-1)
24 {
25 i=1;
26 while((i+1)*(i+2)-2*i-1<k)i++;
27 g<<i<<’\n’;
28 }
29 else
30 {
31 l=i;int p=0;
32 while(i>=1)
33 {
34 p+=2*i-1;
35 if((l+1)*(l+2)-2*l-1+p>=k)
36 {
37 g<<i<<’\n’;return 0;
38 }
39 i--;
40 }
41 }
42 }
43 return 0;
44 }
37
38 d=0;y=2*x*(x+1)-x+1;
39 if(k>y) {g<<’0’;return 0;}
40 else
41 if(k<=(x+1)*(x+2)-2*x-1)
42 {
43 for(i=1;;i++)
44 if((i+1)*(i+2)-2*i-1>=k)
45 {
46 g<<i;return 0;
47 }
48 }
49 else
50 {
51 for(i=x;i>=1;i--)
52 {
53 d+=2*(i+1)-3;
54 if((x+1)*(x+2)-2*x-1+d>=k)
55 {
56 g<<i;break;
57 }
58 }
59 }
60 }
61
62 return 0;
63 }
Cerinţe
Cunoscându-se numărul de bile şi configuraţia finală a bilelor ı̂n şir să se determine:
1. numărul ultimei bile luate de pe masă;
2. ordinea ı̂n care bilele au fost luate de pe masă.
Date de intrare
Fişierul de intrare ordine.in conţine pe prima linie numărul n de bile. Pe linia a doua a
fişierului de intrare se găsesc n numere naturale, cu valori ı̂ntre 1 şi n, separate prin câte un
spaţiu, care reprezintă şirul de bile obţinut de Gigel ı̂n cutie. Linia a treia conţine una dintre
valorile 1 sau 2 reprezentând cerinţa 1, dacă se cere determinarea ultimei bile luate de Gigel de pe
masă, respectiv cerinţa 2, dacă se cere determinarea ordinii ı̂n care Gigel a luat bilele de pe masă.
Date de ieşire
Exemple
ordine.in ordine.out
7 5
1725346
1
7 1374265
1725346
2
Prin sistemul de formare a sirului descris in enunt, bilele luate de pe masa prima, a treia, a
cincea, etc. sunt primele in sir, urmate de bilele luate a doua, a patra, a sasea, etc. Astfel:
- bila a 3-a se pune dupa prima bila, deoarece se pune la mijloc, intre primele 2 bile luate
- bila a 5-a se pune dupa primele dou bile, deoarece se pune la mijloc, intre primele 4
- bila a 7-a se pune dupa primele trei bile, deoarece se pune la mijloc, intre primele 6
- ...
iar
- bila a 2-a se pune pe pozitia 2 (dup prima bila la inceput), apoi la fiecare bila cu numar de
ordine impar se deplaseaza cu cate o pozitie spre dreapta, ceea ce inseamna ca in final va ajunge
pe poziia n/2+1 (prima pozitie dupa mijloc)
- bila a 4-a se pune dup bila a doua, apoi ...
14 int n, i, j, tip;
15
16 int main()
17 {
18 //citire date de intrare
19 fin >> n;
20
21 j = 1;
22 for (i = 1; i <= n; ++i)
23 {
24 fin >> b[j];
25 j += 2;
26 if (j > n) j = 2;
27 }
28
29 fin >> tip;
30
31 if (tip == 2) //rezolv cerinta 2
32 //afisez rezultatul
33 for (i = 1; i <= n; ++i) fout << b[i] << ’ ’;
34 else //rezolv cerinta 1
35 fout << b[n]; //e ultima bila
36 fout << ’\n’;
37 return 0;
38 }
7 ofstream fout("ordine.out");
8
9 int main()
10 {
11 vector <int> endstring;
12 vector <int> startstring;
13
14 int n;
15 int option;
16
17 fin >> n;
18
19 for (int i=0; i<n; ++i)
20 {
21 int x;
22 fin >> x;
23 endstring.push_back(x);
24 }
25
26 fin >> option;
27 fin.close();
28
29 if (1==option)
30 {
31 if(n%2==1) fout << endstring[n/2];
32 else fout << endstring[n-1];
33 }
34 else
35 {
36 int aux=n;
37 while(aux)
38 {
39 if (aux%2==1)
40 {
41 startstring.insert(startstring.begin(), endstring[aux/2]);
42 endstring.erase(endstring.begin()+aux/2);
43 aux--;
44 }
45 else
46 {
47 startstring.insert(startstring.begin(), endstring[aux-1]);
48 endstring.erase(endstring.begin()+aux-1);
49 aux--;
50 }
51 }
52 for (int j=0; j<n; ++j)
53 {
54 fout << startstring[j] <<’ ’;
55 }
56 }
57
58 fout<<’\n’;
59 return 0;
60 }
19 }
20
21 f>>k;
22
23 if(k==1)
24 if(n%2==0) g<<v[n-1]<<’\n’;
25 else g<<v[n/2]<<’\n’;
26 else
27 {
28 i=0;m=(n-1)/2;j=m+1;
29 while(j<n) g<<v[i++]<<’ ’<<v[j++]<<’ ’;
30 if(n%2) g<<v[m]<<’ ’;
31 g<<’\n’;
32 }
33
34 f.close();
35 g.close();
36 return 0;
37 }
20 {
21 for(i=1; i<=n; i++,k=k+2)
22 {
23 if(k>n)
24 {
25 b1=o[k-2];
26 k=2;
27 }
28 f>>o[k];
29 }
30 }
31
32 b2=o[n];
33
34 f>>c;
35
36 if(n%2) N=b1;
37 else N=b2;
38
39 if(c==2)
40 for(i=1; i<=n; i++) g<<o[i]<<’ ’;
41 else
42 g<<N;
43
44 f.close();
45 g.close();
46 return 0;
47 }
4 #include <fstream>
5
6 using namespace std;
7
8 #define DIM 1000001
9
10 ifstream fin("ordine.in");
11 ofstream fout("ordine.out");
12
13 int a[DIM], b[DIM];
14 int n, i, j, tip;
15
16 int main()
17 {
18 //citire date de intrare
19 fin >> n;
20 for (i = 1; i <= n; ++i) fin >> a[i];
21 fin >> tip;
22 if (tip == 2) //rezolv cerinta 2
23 {
24 //refac sirul de mutari in b
25 i = 1; j = 1;
26 while (i <= n)
27 {
28 b[i] = a[j];
29 i += 2; j++;
30 }
31
32 i = 2;
33 while (i <= n)
34 {
35 b[i] = a[j];
36 i += 2; j++;
37 }
38
39 //afisez rezultatul
40 for (i = 1; i <= n; ++i) fout << b[i] << ’ ’;
41 }
42 else //rezolv cerinta 1
43 if (n % 2 == 1) //numar impar de bile
44 fout << a[n / 2 + 1];//e bila de la mijloc
45 else //numar par de bile
46 fout << a[n]; //e ultima bila
47 fout << ’\n’;
48 return 0;
49 }
27 k+=2;
28 }
29
30 k=2;
31 for(i=(n+1)/2+1;i<=n;i++)
32 {
33 y[k]=x[i];
34 k+=2;
35 }
36
37 for(i=1;i<=m;i++)
38 g<<y[i]<<" ";
39 }
40
41 return 0;
42 }
OJI 2014
De exemplu, cifra 2 va fi tipărită prin 11 puncte ca rezultat al acţionării a 11 ace din grilă:
din primul rând de ace al grilei se vor acţiona toate cele 3 ace, din următorul rând doar acul din
dreapta, apoi de pe următorul rând toate cele 3 ace, apoi acul din stânga de pe penultimul rând
iar din ultimul rând toate cele 3 ace.
Cerinţe
a) ştiind că imprimanta Cif-Oji6 a tipărit numărul N , determinaţi care este cea mai mare cifră
a numărul N pentru care s-a acţionat un număr minim de ace ale grilei.
b) ştiind că imprimanta mai are tuş pe bandă doar pentru imprimarea a K puncte, determinaţi
cel mai mare număr natural ce poate fi tipărit prin exact K puncte.
Date de intrare
Fişierul de intrare imprimanta.in conţine pe prima linie două numere naturale N şi K sepa-
rate printr-un spaţiu, unde N reprezintă numărul tipărit de imprimantă iar K numărul de puncte
pentru care imprimanta mai are tuş.
Date de ieşire
124
CAPITOLUL 9. OJI 2014 9.1. IMPRIMANTA - OJI 2014 125
Exemple
imprimanta.in imprimanta.out Explicaţii
2852 16 5 Pentru tipărirea cifrei 2 s-au acţionat 11 ace, pentru cifra 8
74 s-au acţionat 13 ace iar pentru cifra 5 tot 11 ace. Numărul
minim de ace pentru tipărirea unei cifre este 11.
5 este cea mai mare cifră a numărului 2852 ce a fost tipărită
cu 11 ace.
Cel mai mare număr natural ce poate fi tipărit prin 16
puncte este 74
7 puncte (pentru cifra 7) + 9 puncte (pentru cifra 4) = 16
puncte.
88 25 8 Pentru tipărirea cifrei 8 s-au acţionat 13 ace.
11111 Cel mai mare număr natural ce poate fi tipărit prin 25 de
puncte este 11111
5* (5 puncte pentru cifra 1) = 25 puncte.
46 g<<cifra_maxima<<’\n’;
47 nr_maxim_de_cifre=K/5;
48 puncte_ramase=K%5;
49
50 switch(puncte_ramase)
51 {
52 case 0: for(i=1;i<=nr_maxim_de_cifre;i++)
53 g<<’1’;
54 break;
55 case 1: g<<’7’;
56 if(nr_maxim_de_cifre==3)
57 g<<’4’;
58 else
59 g<<"77";
60 for(i=1;i<=nr_maxim_de_cifre-4;i++)
61 g<<’1’;
62 break;
63 case 2: g<<’7’;
64 for(i=1;i<=nr_maxim_de_cifre-1;i++)
65 g<<’1’;
66 break;
67 case 3: g<<’8’;
68 for(i=1;i<=nr_maxim_de_cifre-2;i++)
69 g<<’1’;
70 break;
71 case 4: g<<’4’;
72 for(i=1;i<=nr_maxim_de_cifre-1;i++)
73 g<<’1’;
74 break;
75 }
76
77 g<<’\n’;
78 return 0;
79 }
11
12 fi>>n>>k; pm=15; cm=0;
13
14 while (n>0)
15 { r=n%10; n/=10;
16 if (p[r]<pm || (p[r]==pm && r>cm))
17 {cm=r; pm=p[r];}
18 }
19
20 fo<<cm<<"\n";
21 r=k%5; cm=k/5;
22
23 if (k==16) { fo<<74; cm=0;}
24 else
25 switch (r)
26 { case 0: break;
27 case 1: fo<<777; cm-=4; break;
28 case 2: fo<<7; cm--; break;
29 case 3: fo<<8; cm-=2; break;
30 case 4: fo<<77; cm-=2; break;
31 }
32
33 for (i=0;i<cm;i++) fo<<1;
34 fo<<"\n";
35 return 0;
36 }
47 {
48 g<<74;
49 afis_1(cat);
50 }
51 if ( rest == 2 ) {g<<711; afis_1(cat);}
52 if ( rest == 3 ) {g<<81; afis_1(cat);}
53 if ( rest == 4 ) {g<<411; afis_1(cat);}
54 }
55
56 return 0;
57 }
Cerinţe
Date de intrare
Fişierul de intrare munte.in conţine pe prima linie numărul n, iar pe următoarea linie numerele
naturale x1 , x2 , ..., xn separate două câte două prin câte un spaţiu.
Date de ieşire
Fişierul de ieşire munte.out va conţine pe prima linie un număr natural conform cerinţei a),
pe a doua linie un număr natural conform cerinţei b), pe a treia linie un număr natural conform
cerinţei c).
Exemple
9
10 ifstream fin("munte.in");
11 ofstream fout("munte.out");
12
13 void citire()
14 {
15 int i;
16 fin >> n;
17 for (i = 0; i < n; i++)
18 fin >> v[i];
19 fin.close();
20 }
21
22 inline void secventemunte()
23 {
24 int i, varful, cresc, descr, pvarf;
25 ok = false;
26 i = 0;
27 while (i < n - 1)
28 {
29 cresc = descr = 0;
30 while (v[i] < v[i + 1] and i < n - 1)
31 {
32 i++; cresc++;
33 }
34 varful = v[i]; pvarf = i;
35 while (v[i] > v[i + 1] and i < n - 1)
36 {
37 i++; descr++;
38 }
39 if (cresc + descr >= 2 and cresc > 0 and descr > 0)
40 {
41 varf[k++] = varful; v[pvarf] = -1;
42 ok = true;
43 }
44 }
45 }
46
47 inline void eliminvarfuri()
48 {
49 int i, k;
50 i = 0;
51 while (i < n)
52 {
53 if (v[i] == -1)
54 {
55 for (k = i; k < n - 1; k++)
56 v[k] = v[k + 1];
57 n--;
58 }
59 else
60 i++;
61 }
62 }
63
64 int main()
65 {
66 citire();
67 ok = false;
68 secventemunte();
69 eliminvarfuri();
70 fout << k << ’\n’;
71 while (ok)
72 {
73 secventemunte();
74 eliminvarfuri();
75 }
76 fout << k << ’\n’;
77 fout << n << ’\n’;
78 fout.close();
79 return 0;
80 }
1 #include<cstdio>
2 #include<bitset>
3
4 using namespace std;
5
6 int N,sola,solb;
7 int V[105];
8
9 bitset<105> B;
10
11 int main()
12 {
13 int i,j,k,p,ok;
14
15 freopen("munte.in","r",stdin);
16 freopen("munte.out","w",stdout);
17
18 scanf("%d",&N);
19
20 for(i=1; i<=N; i++)
21 scanf("%d",&V[i]);
22
23 ok=1;
24
25 for(;;)
26 {
27 B=0;
28 p=0;
29 for(i=1; V[i]>=V[i+1]; i++);
30 for(i++; i<=N;)
31 {
32 for(; i<=N; i++)
33 if(V[i-1]>V[i]) break;
34 if(i>N) break;
35 k=i-1;
36 for(; i<=N; i++)
37 if(V[i-1]<V[i]) break;
38 solb++;
39 p++;
40 B[k]=1;
41 }
42
43 if(ok)
44 {
45 sola=p;
46 ok=0;
47 }
48
49 if(!p) break;
50 for(i=j=1; i<=N; i++)
51 if(!B[i]) V[j++]=V[i];
52 N-=p;
53 }
54
55 printf("%d\n%d\n%d\n",sola,solb,N);
56
57 return 0;
58 }
15 int i,j,k,p,ok;
16
17 freopen("munte.in","r",stdin);
18 freopen("munte.out","w",stdout);
19
20 scanf("%d",&N);
21
22 for(i=1; i<=N; i++)
23 scanf("%d",&V[i]);
24
25 ok=1;
26
27 for(;;)
28 {
29 B=0;
30 p=0;
31 for(i=1; V[i]>=V[i+1]; i++);
32 for(i++; i<=N;)
33 {
34 for(; i<=N; i++)
35 if(V[i-1]>V[i]) break;
36 if(i>N) break;
37 k=i-1;
38 for(; i<=N; i++)
39 if(V[i-1]<V[i]) break;
40 b++;
41 p++;
42 B[k]=1;
43 }
44
45 if(ok)
46 {
47 a=p;
48 ok=0;
49 }
50
51 if(!p) break;
52 for(i=j=1; i<=N; i++)
53 if(!B[i]) V[j++]=V[i];
54 N-=p;
55 }
56
57 printf("%d\n%d\n%d\n",a,b,N);
58
59 return 0;
60 }
27
28 while (i <= n)
29 {
30 while (i<n && x[i]<x[i+1]) i++; //urc spre varf
31 if (i<n) //daca mai am elemente
32 {
33 munti++; cati++;
34 x[i] = MAX; //asta e un varf - il voi elimina
35 gasit_munte = true;
36 }
37 while (i<n && x[i]>x[i+1]) i++; //cobor muntele
38 if (i<n && x[i]>x[i-1])
39 i--;
40 else
41 if (i == n)
42 break;
43 }
44
45 if (parcurgere == 1)
46 {
47 fout << munti << ’\n’;
48 parcurgere++;
49 }
50
51 //elimin varfurile
52 i = 1;
53 while (i < n)
54 {
55 while (x[i] != MAX && i<n) i++;
56 for (j = i; j<n; ++j) x[j] = x[j+1];
57 }
58
59 if (gasit_munte) n -= cati;
60 }
61
62 fout << munti << ’\n’;
63 fout << n << ’\n’;
64 fout.close();
65
66 return 0;
67 }
5 ifstream f("munte.in");
6 ofstream g("munte.out");
7
8 int a[1000],b[1000],n,k,i,j,x,total,local,prima,ultim;
9
10 int main()
11 {
12 f >> n ;
13 f>>a[1];
14 k=1;
15
16 for( i =2 ; i <= n; i++ )
17 {
18 f >> x;
19 if(a[k]<=x)
20 {
21 k++;
22 a[k]=x;
23 }
24 else
25 if( k >= 2 and a[ k-1 ] < a[ k ] and ultim+1!=i )
26 {
27 a[k] = x ;
28 prima++;
29 ultim=i;
30 }
31 else
32 {
33 k++;
34 a[k]=x;
35 ultim=i;
36 }
37 }
38
39
40 total += prima ;
41 g<<prima<<’\n’;
42
43 do
44 {
45 n = k;
46 for( i=1 ; i<=n; i++) b[i] = a[i];
47 local = 0;
48
49 k=1; a[1]=b[1];
50 for( i=2; i<=n ; i++)
51 {
52 x=b[i];
53 if(a[k]<=x){k++;a[k]=x;}
54 else
55 if( k >= 2 and a[ k-1 ] < a[ k ] and ultim+1!=i )
56 {
57 a[k] = x ;
58 local++;
59 ultim=i;
60 }
61 else {k++;a[k]=x;}
62 }
63
64 total += local ;
65 } while(local);
66
67 g<<total<<’\n’<<n<<’\n’;
68 return 0;
69 }
8 ifstream f("munte.in");
9 ofstream g("munte.out");
10
11 int n,x[100],y[100],k,i,t=0,tot=0,poz,j;
12 int main()
13 {
14 f>>n;
15 k=-1;
16 for(i=0;i<n;i++)
17 f>>x[i];
18 do
19 {
20 t++;k=-1;
21 for(i=1;i<n-1;i++)
22 if (x[i]>x[i-1] && x[i]>x[i+1])
23 {
24 k++;
25 y[k]=i;
26 }
27
28 if (t==1)
29 g<<k+1<<endl;
30
31 //eliminare;
32 for(i=0;i<=k;i++)
33 {
34 poz=y[i]-i;
35 for(j=poz;j<n-1;j++)
36 x[j]=x[j+1];
37 n--;
38 }
39
40 tot=tot+k+1;
41 } while (k!=-1);
42
43 g<<tot<<endl;
44 g<<n<<endl;
45 return 0;
46 }
34 if (i<n)
35 {
36 k=i;
37 y[x[k]]=1;ok=1;
38 if (i<n)
39 {
40 while (i<n && x[i]<x[i+1]) i++;
41 nr++;
42 }
43 }
44 }
45 else i++;
46 }
47
48 if (ok)
49 {
50 if (t==1) g<<nr<<endl;
51 i=1;
52 while (i<=n)
53 {
54 if (y[x[i]])
55 {
56 for (j=i;j<=n-1;j++)
57 x[j]=x[j+1];
58 n--;
59 }
60 else i++;
61 }
62 }
63 }
64
65 while (ok==1);
66 g<<nr<<endl<<n<<endl;
67
68 f.close();
69 g.close();
70 return 0;
71 }
OJI 2013
- Crina lipeşte pe fiecare clădire câte un bileţel pe care scrie ı̂nălţimea turnurilor din care
aceasta este construită, ı̂n ordinea ı̂n care ea le vede când trece prin dreptul lor (de exemplu,
pentru imaginea de mai sus, Crina va lipi pe prima clădire un bileţel pe care va scrie numărul
3112 deoarece, primul turn e format din 3 cuburi, următoarele două turnuri ale acestei clădiri sunt
formate din câte un cub iar cel de-al patrulea turn e format din 2 cuburi);
- Rareş va proceda la fel, dar ı̂ncepe plimbarea din celălalt capăt al străzii. În exemplul din
imagine, el va lipi pe prima clădire pe care o ı̂ntâlneşte un bileţel pe care scrie numărul 2121.
La finalul plimbării, Crina şi Rareş ı̂şi dau seama că există clădiri pe care au lipit amândoi
bileţele cu numere identice.
Cerinţe
a) Care este ı̂nălţimea celui mai ı̂nalt turn şi care este numărul clădirilor care au ı̂n construcţia
lor un astfel de turn?
b) Care este numărul clădirilor pe care cei doi copii au lipit bileţele cu numere identice?
c) Care este cel mai mic număr de cuburi necesar pentru a completa clădirile astfel ı̂ncât, pe
fiecare clădire, bileţelul pe care ı̂l va lipi Crina să conţină acelaşi număr cu cel pe care ı̂l va lipi
Rareş? Cuburile din care a fost construită iniţial clădirea nu se pot muta.
Date de intrare
Din fişierul cladiri.in se va citi de pe prima linie un număr natural N , reprezentând numărul
clădirilor de pe stradă, iar de pe următoarele N linii câte un număr natural cu toate cifrele nenule,
reprezentând numerele scrise de Crina pe bileţele, ı̂n ordinea ı̂n care au fost lipite de ea pe clădiri.
142
CAPITOLUL 10. OJI 2013 10.1. CLADIRI - OJI 2013 143
Date de ieşire
În fişierul cladiri.out se vor scrie pe prima linie două numere naturale despărţite printr-un
singur spaţiu ce reprezintă, ı̂n ordine, valorile cerute la cerinţa a). Pe cea de-a doua linie a fişierului
se va scrie un număr natural, mai mare sau egal cu zero, reprezentând răspunsul la cerinţa b). Pe
cea de-a treia linie a fişierului se va scrie un număr natural, mai mare sau egal cu zero, reprezentând
răspunsul la cerinţa c).
Exemple
cladiri.in cladiri.out Explicaţii
6 73 Cel mai ı̂nalt turn este format din 7 cuburi. Sunt 3 clădiri
3112 2 care au ı̂n construcţia lor turnuri cu această ı̂nălţime, cele
2772 8 pe care Crina lipeşte numerele: 2772, 1741 şi 27372. Rareş
42422 lipeşte pe clădiri bileţele cu numerele: 2121, 27372, 1471,
1741 22424, 2772 şi 2113. Două dintre aceste clădiri au primit
27372 aceleaşi numere şi de la Crina: 2772 şi 27372. Valoarea
1212 determinată conform cerinţei c) este 8. Se adaugă un cub la
clădirea cu numărul 3112, 2 cuburi la cea cu numărul 42422,
3 cuburi la clădirea cu numărul 1741 şi 2 cuburi la cea cu
numărul 1212.
a) Pentru determinarea celui mai inalt turn si a numarului cladirilor care au in constructia lor
un astfel de turn se descompune in cifre fiecare numar citit din fisier si se determina cifra maxima,
precum si numarul valorilor din fisier care contin aceasta cifra maxima.
b) Numarul cladirilor care au lipite pe ele doua biletele cu numere identice se poate determina
prin contorizarea valorilor de tip palindrom din fisier.
c) Pentru determinarea celui mai mic numar de cuburi necesar pentru a completa cladirile
construite astfel incat pe fiecare cladire biletelul lipit de Crina sa contina acelasi numar cu biletelul
lipit de Rares vom identifica fiecare numar care nu este de tip palindrom si vom determina numarul
minim necesar pentru incrementarea fiecarei cifre astfel incat numarul obtinut in urma acestei
operatii sa fie palindrom.
7 FILE *f,*g;
8
9 int n,i,cif,cifinv,cmax,hmax,nrhmax,nrpal;
10 int nrcub;
11 int x,copyx,invx;
12
13 hmax=0;
14 nrhmax=0;
15 nrpal=0;
16 nrcub=0;
17
18 f=fopen("cladiri.in","r");
19 fscanf(f,"%i",&n);
20
21 for(i=0;i<n;i++)
22 {
23 fscanf(f,"%i",&x);
24
25 copyx=x;
26 invx=0;
27 cmax=0;
28
29 while(x>0)
30 {
31 cif=x%10;
32 x/=10;
33 invx=10*invx+cif;
34 if(cif>cmax)
35 cmax=cif;
36 }
37
38 if(cmax>hmax)
39 {
40 hmax=cmax;
41 nrhmax=1;
42 }
43 else
44 if(cmax==hmax)
45 nrhmax++;
46
47 if(invx==copyx)
48 nrpal++;
49 else
50 while(invx>0)
51 {
52 cif=copyx%10;
53 cifinv=invx%10;
54 copyx/=10;
55 invx/=10;
56 if(cif>cifinv)
57 nrcub+=cif-cifinv;
58 }
59 }
60
61 fclose(f);
62
63 g=fopen("cladiri.out","w");
64 fprintf(g,"%i %i\n",hmax,nrhmax);
65 fprintf(g,"%i\n",nrpal);
66 fprintf(g,"%i\n",nrcub);
67 fclose(g);
68
69 return 0;
70 }
9
10 int main()
11 {
12 f>>n;
13 Cmax=0;
14 na=np=ct=0;
15 for(i=1; i<=n; i++)
16 {
17 f>>a;
18 x=a;
19 inv=nc=Cx=0;
20 while (x)
21 {
22 if(x%10>Cx) Cx=x%10;
23 inv=inv*10 + x%10;
24 v[++nc]=x%10;
25 x/=10;
26 }
27
28 if(Cx==Cmax) na++;
29 else if(Cx>Cmax)
30 {
31 Cmax=Cx;
32 na=1;
33 }
34
35 if (inv==a) np++;
36 for(j=1; j<=nc/2; j++)
37 {
38 dif = (v[nc-j+1]>v[j]?v[nc-j+1]-v[j]:v[j]-v[nc-j+1]);
39 ct=ct + dif;
40 }
41 }
42
43 g<<Cmax<<" "<<na<<’\n’;
44 g<<np<<’\n’;
45 g<<ct<<’\n’;
46 g.close();
47 return 0;
48 }
33 {
34 maxim = cmax;
35 nrmaxim = 1;
36 }
37 else
38 if (cmax == maxim)
39 nrmaxim++;
40
41 if (x == inv)
42 nrpal++;
43
44 for (j=1;j<=p/2;j++)
45 {
46 if (x % 10 > inv % 10)
47 sum += (x%10-inv%10);
48 else
49 sum += (inv%10 - x%10);
50
51 x/=10;
52 inv/=10;
53 }
54 }
55
56 fprintf(fout,"%d %d\n%d\n%d\n",maxim,nrmaxim,nrpal,sum);
57
58 return 0;
59 }
46 else
47 sum += (inv%10 - x%10);
48
49 x/=10;
50 inv/=10;
51 }
52 }
53
54 fout<<maxim<<" "<<nrmaxim<<"\n"<<nrpal<<"\n"<<sum;
55
56 return 0;
57 }
1 #include<iostream>
2 #include<cstdio>
3 #include<cstdlib>
4
5 using namespace std;
6
7 int x,y,ogl,a,b,s;
8 short ap[10],i,n,j,cmax,cf,cm,nr,nrpal,nrcf;
9
10 int main()
11 {
12 freopen("cladiri.in","r",stdin);
13 freopen("cladiri.out","w",stdout);
14
15 cin>>n;
16 for(i=1;i<=n;i++)
17 {
18 cin>>x;for(j=0;j<=9;j++) ap[j]=0;
19 y=x;
20 ogl=0;
21 nrcf=1;
22
23 while(x)
24 { cf=x%10;
25 ogl=ogl*10+cf;
26 ap[cf]++;
27 x=x/10;
28 nrcf++;
29 }
30
31 j=9;
32 while(ap[j]==0)j--;
33 cmax=j;
34
35 if(y==ogl)nrpal++;
36
37 if(cm<cmax){cm=cmax;nr=1;}
38 else if(cm==cmax)nr++;
39
40 //trebuie determinat s
41 for(j=1;j<=nrcf/2;j++)
42 {s=s+abs(y%10-ogl%10);y=y/10;ogl=ogl/10;}
43 }
44
45 cout<<cm<<’ ’<<nr<<’\n’;
46 cout<<nrpal<<’\n’;
47 cout<<s;
48
49 return 0;
50 }
23 ogl=ogl*10+cf;
24 x=x/10;nrcf++;
25 if(cf>cmax)cmax=cf;
26 }
27
28 if(y==ogl)nrpal++;
29
30 if(cm<cmax){cm=cmax;nr=1;}
31 else
32 if(cm==cmax)nr++;
33
34 //trebuie determinat s
35 for(j=1;j<=nrcf/2;j++)
36 {
37 s=s+abs(y%10-ogl%10);
38 y=y/10;
39 ogl=ogl/10;
40 }
41 }
42
43 cout<<cm<<’ ’<<nr<<’\n’;
44 cout<<nrpal<<’\n’;
45 cout<<s;
46
47 return 0;
48 }
Cerinţe
Cunoscând numărul de galbeni aleşi de primul sătean, determinaţi numărul de galbeni pe care
ı̂l va primi al N -lea sătean.
Date de intrare
Fişierul galbeni.in conţine pe prima linie cele 3 numere naturale nenule S, K, N separate
prin câte un spaţiu, unde S reprezintă numărul de galbeni ales de primul sătean, K este numărul
de cifre ale numărului S, iar N reprezintă numărul de ordine al săteanului pentru care se cere să
determinaţi numărul de galbeni primiţi.
Date de ieşire
Fişierul galbeni.out conţine pe unica sa linie un număr natural reprezentând rezultatul de-
terminat.
Exemple
Solutia 1
Simulam modul de construire a urmatoarei valori asa cum este descris in enuntul problemei.
O implementare corecta obtine doar 45 de puncte, intrucat nu se va incadra in timp pe toate
testele.
Solutia 2
Se observa ca daca se intalneste pe pozitia X un numar care a mai fost generat anterior pe
pozitia Y , atunci numarul pe care il vom obtine pe pozitia X 1 va fi acelasi cu cel obtinut pe
pozitia Y 1.
Asadar secventa de numere dintre pozitiile Y si X 1 se va repeta.
Pentru a identifica secventa de numere care se repeta putem folosi un vector V cu indici pana
la 999 in care, la intalnirea unui numar Z, marcam pe pozitia V Z . Astfel, la intalnirea unui
numar deja marcat am identificat secventa care se repeta.
Pentru a afla care numar se gaseste pe o pozitie oarecare N este necesar sa cunoastem numerele
aflate inaintea pozitiei Y precum si pe cele din secventa care se repeta.
Daca N $ Y aflam direct valoarea. In caz contrar, putem scadea din N cantitatea Y 1
si, printr-o impartire, putem afla pe ce pozitie se gaseste numarul de cautat in secventa care se
repeta.
Acest algoritm se va incadra in timp pentru toate testele. El va detecta secventa care se repeta
in cel mult 10k pasi apoi se fac doar cateva operatii aritmetice elementare.
CAPITOLUL 10. OJI 2013 10.2. GALBENI - OJI 2013 151
5 ofstream g("galbeni.out");
6
7 int s,x,v[1000],w[1000];
8
9 int main()
10 {int k,n,i,p,ultim,ok=1,poz,x;
11 f>>s>>k>>n;ultim =1;w[ultim]=s;v[s]=1;
12
13 //p=pow(10,k);
14 if(k==1) p=10;
15 else if(k==2) p=100;
16 else if(k==3) p=1000;
17
18 for(i=1;i<=n-1 && ok;i++)
19 {
20 x=s;
21 while(x!=0)
22 {
23 if(x%10) s=s*(x%10);
24 x=x/10;
25 }
26 s=((s*8)/9)%p;
27
28 while(s<p/10) s=s*10+9;
29
30 if(v[s]) ok=0;
31 else {v[s]=1;w[++ultim]=s;}
32 }
33
34 if(i<n)
35 {
36 ok=0;
37 for(i=1;!ok;i++)
38 if(w[i]==s) {poz=i;ok=1;}
39 k=ultim-poz+1;
40 x=n-poz;
41 x=x%k;
42 g<<w[poz+x]<<’\n’;
43 }
44 else
45 g<<s<<’\n’;
46
47 f.close();
48 g.close();
49 return 0;
50 }
27 }
28 x = x/10;
29 }
30
31 //p = numarul format dupa inmultire
32 p = p*8;
33 p = p/9;
34
35 // while (p >= z)
36 // p/=10;
37
38 p = p%z;
39 while (p < z/10)
40 p = p*10 + 9;
41
42 s = p;
43 // if (i<=20)
44 // fout<<s<<"\n";
45 }
46
47 fout<<s<<"\n";
48 return 0;
49 }
50 {
51 N -= A[Nr] - 1;
52 rest = N % Lg;
53 if (!rest) rest =Lg;
54
55 g<<V[A[Nr] + rest - 1];
56 }
57
58 g.close();
59
60 return 0;
61 }
OJI 2012
Cerinţe
Realizaţi un program care, cunoscând poziţia iniţială a fiecărui disc dintre cele N discuri ale
cifrului, determină şi afişează:
a) cifra cea mai mare care apare pe discurile cifrului ı̂n forma iniţială;
b1) numărul minim de mutări necesare pentru ca numărul obţinut pe cifru să fie compus numai
din cifre identice, număr necesar deschiderii servietei;
b2) cifra cea mai mică ce se poate obţine ı̂n urma efectuării numărului minim de mutări
determinat;
b3) numărul de combinaţii formate din cifre identice, care se poate obţine ı̂n urma efectuării
numărului minim de mutări determinat.
Date de intrare
Date de ieşire
În fişierul cifru.out se vor afişa, pe linii separate, cele 4 valori solicitate.
a 1 $ N & 100000
a Un disc poate să rămână nemişcat.
a Pentru rezolvarea corectă a cerinţei a) se acordă 20% din punctajul fiecărui test.
a Pentru rezolvarea corectă a cerinţei b1) se acordă 40% din punctajul fiecărui test, pentru
rezolvarea corectă a cerinţelor b1) şi b2) se acordă 60% din punctajul fiecărui test, iar pentru
rezolvarea corectă a cerinţelor b1), b2) şi b3) se acordă 80% din punctajul fiecărui test.
Exemple
155
CAPITOLUL 11. OJI 2012 11.1. CIFRU - OJI 2012 156
Vom utiliza tabloul unidimensional Apar, cu 10 elemente, care memoreaza de cate ori se repeta
fiecare cifra in cifrul initial, deci:
Apari = numarul de aparitii al cifrei i in cifrul initial, unde i 0, 1, ..., 9
Valorile tabloului Apar pot fi calculate pe masura ce citim datele de intrare, nefiind nevoie de
memorarea celor N numere ce formeaza cifrul. Este suficient sa aflam cate discuri sunt pozitionate
initial pe cifra 0, cate pe cifra 1, ..., cate pe cifra 9, iar apoi sa calculam numarul minim de mutari
necesare pentru a pozitiona cifrul pe o anumita cifra. Astfel:
* Calculam pe rand, pentru fiecare cifra i 0, 1, ..., 9 care apare macar o data in cifru, numarul
de mutari necesare pentru ca toate discurile cifrului sa fie setate pe valoarea i, astfel:
(C++)
for(j=0;j<=9;j++)
if(Apar[j] && j!=i)
Nr += abs(j-i) <= 10-abs(j-i) ? Apar[j]*abs(j-i) : Apar[j]*(10-abs(j-i));
(PASCAL)
for j:=0 to 9 do
if (Apar[j]>0) and (j<>i) then
if abs(j-i) <= 10 - abs(j-i) then Nr := Nr+ Apar[j]*abs(j-i)
else Nr := Nr + Apar[j]*(10 - abs(j-i));
* Se tine cont de faptul ca fiecare disc poate fi mutat in doua directii deci, daca cifrul este
pozitionat pe cifra j, pentru a-l muta pe cifra i putem face abs j i mutari in sus sau 10 abs j i
mutari in jos. La fiecare pas consideram cea mai mica valoare dintre cele doua.
* Cand gasim un numar total de mutari mai mic actualizam minimul curent si retinem cifra
pentru care se obtine acesta. Atunci cand gasim un numar total de mutari egal cu minimul curent
incrementam numarul de solutii de valoare minima.
7 int N, K, H;
8 int h[100];
9 int S;
10
11 int main()
12 {
13 fin >> N >> H;
14 for ( int i = 0; i < N; ++i )
15 {
16 fin >> h[i];
17 S += h[i];
18 }
19
20 // Cerinta a)
21 for (int i = 1; i <= N; ++i )
22 S += i;
23 fout << S << ’\n’;
24
25 // Cerinta b)
26 bool ok = true;
27 while ( ok )
28 {
29 for ( int i = 0; i < N - 1; ++i )
30 for ( int j = i + 1; j < N; ++j )
31 if ( h[i] > h[j] )
32 {
33 int aux = h[i];
34 h[i] = h[j];
35 h[j] = aux;
36 }
37
38 for (int i = 0; i <= K && ok; ++i )
39 if ( h[i] + 1 >= H )
40 ok = false;
41
42 if ( ok )
43 {
44 for (int i = 0; i <= K; ++i )
45 h[i]++;
46 K++;
47 }
48 }
49
50 fout << K << ’\n’;
51
52 fin.close();
53 fout.close();
54 return 0;
55 }
24 poz=k+1;
25 while(val==h[poz] && poz<=n)
26 {
27 i=poz-1;
28 gasit=0;
29 while(i>=1 && !gasit)
30 if(val<h[i])
31 {
32 h[i+1]=h[i];
33 i--;
34 }
35 else gasit=1;
36
37 h[i+1]=val;
38 poz++;
39 }
40
41 k++;
42 } while(k<n);
43
44 return n;//nu e nevoie
45 }
46
47 int main()
48 {
49 freopen("flori.in","r",stdin);
50 freopen("flori.out","w",stdout);
51
52 cin>>n>>H;
53 for(i=1;i<=n;i++)
54 {
55 cin>>h[i];
56 s=s+h[i];
57 }
58
59 cout<<s+n*(n+1)/2<<endl;
60
61 qsort(h+1,n,sizeof(h[0]),cmp);
62
63 cout<<rez();
64
65 return 0;
66 }
Cerinţe
Date de intrare
CAPITOLUL 11. OJI 2012 11.2. FLORI - OJI 2012 159
Prima linie a fişierului flori.in conţine două numere naturale n şi H, separate printr-un spaţiu,
având semnificaţia din enunţ.
Linia a doua conţine n numere naturale: h1 , h2 , ..., hn , separate prin câte un singur spaţiu,
reprezentând ı̂nălţimile iniţiale ale plantelor.
Date de ieşire
Fişierul flori.out va conţine pe prima linie un număr natural S având semnificaţia descrisă ı̂n
cerinţa a).
A doua linie va conţine un număr natural K, având semnificaţia descrisă ı̂n cerinţa b).
Exemple
Cerinta a)
Se observa faptul ca inaltimea totala cu care cresc plantele la sfarsitul zilei n este:
1 + 2 + 3 + ... + n = n * (n + 1) / 2
La aceasta suma se adauga suma inaltimilor initiale ale plantelor: h1 + h2 + ... + hn.
Cerinta b)
Pentru a avea garantia ca maximul inaltimilor plantelor creste in fiecare zi cu o valoare cat
mai mica, trebuie ca in fiecare zi k trebuie sa fie udate primele k plante, in ordinea crescatoare a
inaltimilor (k 1, 2, ...K).
Se afiseaza cea mai mare valoare a lui k, pentru care nicio planta nu atinge inaltimea H.
Prin urmare, algoritmul de rezolvare este urmatorul:
Scrie k - 1
Stop
}
}
Incrementeaza k
}
OJI 2011
Cerinţe
Scrieţi un program care citeşte un număr natural n, reprezentând numărul paginilor din carte
şi n numere naturale distincte x1 , x2 , ..., xn , reprezentând ordinea ı̂n care sunt asezate cele n pagini
ı̂n carte, şi care determină:
a) numărul zilelor ı̂n care Rareş citeşte cartea;
b) prima zi ı̂n care Rareş a citit cele mai multe pagini şi numărul paginilor citite ı̂n acea zi.
Date de intrare
Fisierul de intrare carte.in conţine pe prima linie numărul n al paginilor din carte iar pe linia
următoare n numere ı̂ntregi distincte x1 , x2 , ..., xn , separate prin câte un spaţiu, reprezentând
ordinea ı̂n care sunt aşezate paginile ı̂n carte.
Date de ieşire
Fisierul de ieşire carte.out va conţine pe prima linie, separate prin câte un spaţiu, trei numere,
reprezentând, ı̂n ordine :
a numărul zilelor ı̂n care Rareş citeşte cartea;
a numărul primei zile ı̂n care Rareş a citit cele mai multe pagini;
a numărul maxim de pagini citite ı̂ntr-o zi.
a 0 $ n $ 10001
a paginile cărţii sunt numerotate cu numere naturale distincte de la 1 la n;
a citirea cărţii presupune citirea fiecărei pagini din carte, o singură dată;
a zilele ı̂n care Rareş citeşte cartea sunt numerotate consecutiv, ı̂ncepând cu numărul 1;
a pentru rezolvarea corectă a subpunctului a) se acordă 40% din punctaj şi pentru fiecare
cerinţă a subpunctului b) câte 30% din punctaj.
161
CAPITOLUL 12. OJI 2011 12.1. CARTE - OJI 2011 162
Exemple
carte.in carte.out Explicaţii
9 423 - ı̂n prima zi şi citeste paginile: 1, 2
713682495 - ı̂n a doua zi şi citeste paginile : 3, 4, 5
- ı̂n a treia zi şi citeste pagina 6
- ı̂n a patra zi şi citeste paginile: 7, 8, 9
A terminat de citit cartea ı̂n 4 zile iar ziua
2 este prima zi ı̂n care a citit cele mai multe
pagini (3).
Pentru fiecare pagina cu numarul x retinem pozitia ux in care se gaseste pagina in carte.
Citirea cartii incepe cu pagina cu numarul 1, aflata in pozitia u1.
O pagina cu numarul x 1 este citita in aceeasi zi cu pagina cu numarul x daca ux $ ux 1.
Pentru rezolvarea cerintei a) este suficient sa identificam elementele ui cu proprietatea ca
valoarea ui1 se gaseste inaintea pozitiei i in sir.
Pentru rezolvarea cerintei b) se parcurge sirul si pentru fiecare pagina i necitita (ui 0) se
marcheaza paginile citite in aceeasi zi cu pagina i, actualizand in acelasi timp numarul paginilor
citite si prima zi in care a citit cele mai multe pagini.
45 }
Cerinţe
CAPITOLUL 12. OJI 2011 12.2. GRAD - OJI 2011 165
Scrieţi un program care citeşte numerele n, k, x1 , x2 , ..., xn , cu semnificaţia din enunţ, şi apoi
determină:
a) gradul ı̂ntregului şir de numere;
b) poziţia primului element din prima secvenţă de lungime k ce are gradul maxim, precum şi
gradul acestei secvenţe.
Date de intrare
Fisierul de intrare grad.in conţine pe prima linie numerele n şi k, separate printr-un spaţiu, iar
pe linia următoare n numere naturale distincte x1 , x2 , ..., xn , corespunzătoare şirului de numere,
separate prin câte un spaţiu.
Date de ieşire
Fisierul de ieşire grad.out va conţine pe prima linie un număr natural reprezentând gradul
ı̂ntregului şir de numere, iar pe următoarea linie două numere naturale, separate printr-un singur
spaţiu, primul număr reprezentând poziţia primului element din prima secvenţă de lungime k ce
are grad maxim şi cel de-al doilea număr reprezentând gradul acestei secvenţe.
a 0 $ n $ 10001
a 0$k $n1
a Numerele din şir sunt numere naturale strict mai mici decât 32000.
a O secvenţă de numere din şir reprezintă o succesiune de numere din acel şir, aflate pe poziţii
consecutive.
a Gradul ı̂ntregului şir de numere este egal cu gradul secvenţei de n numere care ı̂ncepe cu
numărul de pe poziţia 1 si conţine toate cele n numere din şir.
a Pentru rezolvarea corectă a subpunctului a) se obţine 40% din punctaj.
a Pentru determinarea poziţiei primului element din prima secvenţă de lungime k ce are grad
maxim, se obţine 20% din punctaj, iar pentru determinarea gradului maxim de la subpunctul b)
se obţine 40% din punctaj.
Exemple
Pentru rezolvarea problemei vom folosi un vector auxiliar y, avand acelasi numar de compo-
nente ca si vectorul x ce memoreaza sirul x1 , x2 , ..., xn .
Pentru rezolvarea cerintei a) se copiaza x in y si se ordoneaza crescator y.
Gradul lui x se calculeaza numarand cati indici i, din multimea r1, 2, ..., nx, au proprietatea
xi y i.
Pentru rezolvarea cerintei b)
* memoram initial primele k elemente ale vectorului x in y, le ordonam crescator si determinam
gradul primei secvente de lungime k. Initializam gmax cu acest grad, iar pmax cu 1.
* Parcurgem apoi toate secventele urmatoare de lungime k, incepand cu indicele p din multimea
r2, 3, ..., n k 1x.
Vectorul y va memora, pe rand, in ordine crescatoare, elementele fiecarei secvente de lungime
k.
CAPITOLUL 12. OJI 2011 12.2. GRAD - OJI 2011 166
----------------------------
| |
x[1], ... , x[p-1], x[p-2], ..., x[p+k-2] , x[p+k-1] ,..., x[n].
| |
-------------------------------
57 for(i=1;i<=k;i++)
58 if(x[i]==y[i])
59 gmax++;
60
61 pmax=1;
62 for(i=2;i<=n-k+1;i++)
63 {
64 for(j=1;j<=k;j++)
65 if(y[j]==x[i-1])
66 break;
67 //ducem y[j] pe pozitia corespunzatoare a. i. y sa ramana ord. cresc.
68 y[j]=x[i+k-1];
69
70 while(j>1&&y[j-1]>y[j])
71 {
72 aux=y[j];
73 y[j]=y[j-1];
74 y[j-1]=aux;
75 j--;
76 }
77
78 while(j<k&&y[j]>y[j+1])
79 {
80 aux=y[j];
81 y[j]=y[j+1];
82 y[j+1]=aux;
83 j++;
84 }
85
86 //determin gradul secventei care incepe cu x[i]
87 gr=0;
88 for(j=1;j<=k;j++)
89 if(y[j]==x[i+j-1])
90 gr++;
91
92 if (gr>gmax)
93 {
94 gmax=gr;pmax=i;
95 }
96 }
97
98 fout<<pmax<<" "<<gmax;
99 fout.close();
100 return 0;
101 }
28 //a
29 ordo(n);
30 g<<egale(0,n)<<’\n’;
31
32 //b
33 for(i=1;i<=k;i++) w[i]=v[i];
34 ordo(k);
35 maxx=egale(0,k);
36
37 p=1;
38 for(i=k+1;i<=n;i++)
39 {
40 x=v[i-k],y=v[i],j=1;
41 while(w[j]!=x)j++;
42 w[j]=y;
43 while(j<k && y>w[j+1])w[j]=w[j+1],w[j+1]=y,j++;
44 while(j>1 && y<w[j-1])w[j]=w[j-1],w[j-1]=y,j--;
45 x=egale(i-k,k);
46 if(x>maxx) maxx=x,p=i-k+1;
47 }
48
49 g<<p<<’ ’<<maxx<<’\n’;
50 f.close();g.close();
51 return 0;
52 }
48 nr++;
49 }
50
51 if(b[i]+1==k)
52 nr++;
53
54 if(nr>ma)
55 {
56 ma=nr;
57 ind=i-k+1;
58 if(ma==k)
59 break;
60 }
61 }
62
63 for(i=1;i<=n;i++)
64 b[i]=0;
65
66 nr=0;
67 for(i=1;i<=n;i++)
68 {
69 for(j=1;j<i;j++)
70 if(a[i]>a[j])
71 b[i]++;
72 else
73 b[j]++;
74 }
75
76
77 for(i=1;i<=n;i++)
78 if(b[i]+1==i)
79 nr++;
80 }
81
82 ofstream g("grad.out");
83
84 if(k!=n)
85 g<<nr<<’\n’;
86 else
87 g<<ma<<’\n’;
88
89 g<<ma<<" "<<ind;
90 g.close();
91
92 return 0;
93 }
27
28 int grad(int p,int q)
29 { int nr=0;
30 for(i=p;i<=q;i++)
31 if(i-p+1==mic[i]) nr++;
32 return nr;
33 }
34
35 void golire()
36 { for (int i=1;i<=n;i++) mic[i]=0;
37 }
38
39 void o_solutie()
40 { int val1,val2;
41 int p,q;
42 int i,j;
43 mai_mici_egale(1,n);
44 g<<grad(1,n)<<endl;
45
46 golire();
47 mai_mici_egale(1,k);
48 maxx=grad(1,k);
49 poz=1;
50
51 for(i=2;i<=n-k+1;i++)
52 {p=i;
53 q=i+k-1; //secventa noua a[p..q] de lungime k
54 val1=a[p-1]; //elementul pierdut din secventa
55 val2=a[q]; //elementul nou din secventa
56 mic[q]=1;
57 for(j=p;j<=q-1;j++)
58 {
59 if(val1<=a[j]) mic[j]--;
60 if(val2<a[j]) mic[j]++;
61 else mic[q]++;
62 }
63 int gr=grad(p,q);
64
65 if(gr>maxx)
66 {maxx=gr;
67 poz=p;
68 }
69 }
70 }
71
72 int main()
73 { citire();
74 o_solutie();
75 g<<poz<<" "<<maxx;
76 g.close();
77 return 0;
78 }
21 int i,j,aux;
22 for(i=1;i<n;i++)
23 for(j=i+1;j<=n;j++)
24 if(x[i]>x[j]){
25 aux=x[i];x[i]=x[j];x[j]=aux;
26 }
27 }
28
29 int main()
30 {
31 int i,j,gr;
32 cit();
33
34 for(i=1;i<=n;i++)
35 y[i]=x[i];
36
37 ordonare(y,n);
38
39 g=0;
40 for(i=1;i<=n;i++)
41 if(x[i]==y[i])
42 g++;
43
44 fout<<g<<’\n’;
45
46 for(i=1;i<=k;i++)
47 y[i]=x[i];
48
49 ordonare(y,k);
50
51 gmax=0;
52 for(i=1;i<=k;i++)
53 if(x[i]==y[i])
54 gmax++;
55
56 pmax=1;
57 for(i=2;i<=n-k+1;i++)
58 {
59 for(j=1;j<=k;j++)
60 if(y[j]==x[i-1])
61 break;
62
63 //ducem y[j] pe pozitia corespunzatoare a. i. y sa ramana ord. cresc.
64 y[j]=x[i+k-1];
65
66 ordonare(y,k);
67
68 //determin gradul secventei care incepe cu x[i]
69 gr=0;
70 for(j=1;j<=k;j++)
71 if(y[j]==x[i+j-1])
72 gr++;
73
74 if (gr>gmax){
75 gmax=gr;pmax=i;
76 }
77 }
78
79 fout<<pmax<<" "<<gmax;
80 fout.close();
81 return 0;
82 }
11 {
12 int i;
13 fin>>n>>k;
14 for(i=1;i<=n;i++)
15 fin>>x[i];
16 fin.close();
17 }
18
19 void ordonare(int x[10002], int n)
20 {
21 int i,sw,aux;
22 do{
23 sw=0;
24 for(i=1;i<n;i++)
25 if(x[i]>x[i+1])
26 {
27 aux=x[i];x[i]=x[i+1];x[i+1]=aux;sw=1;
28 }
29 }while(sw);
30 }
31
32 int main()
33 {
34 int i,j,gr;
35 cit();
36
37 for(i=1;i<=n;i++)
38 y[i]=x[i];
39
40 ordonare(y,n);
41
42 g=0;
43 for(i=1;i<=n;i++)
44 if(x[i]==y[i])
45 g++;
46
47 fout<<g<<’\n’;
48
49 for(i=1;i<=k;i++)
50 y[i]=x[i];
51
52 ordonare(y,k);
53
54 gmax=0;
55 for(i=1;i<=k;i++)
56 if(x[i]==y[i])
57 gmax++;
58
59 pmax=1;
60 for(i=2;i<=n-k+1;i++)
61 {
62 for(j=1;j<=k;j++)
63 if(y[j]==x[i-1])
64 break;
65
66 //ducem y[j] pe pozitia corespunzatoare a. i. y sa ramana ord. cresc.
67 y[j]=x[i+k-1];
68
69 ordonare(y,k);
70
71 //determin gradul secventei care incepe cu x[i]
72 gr=0;
73 for(j=1;j<=k;j++)
74 if(y[j]==x[i+j-1])
75 gr++;
76
77 if (gr>gmax)
78 {
79 gmax=gr;pmax=i;
80 }
81 }
82
83 fout<<pmax<<" "<<gmax;
84 fout.close();
85 return 0;
86 }
CAPITOLUL 12. OJI 2011 12.2. GRAD - OJI 2011 173
OJI 2010
Exemple
loto.in loto.out Explicaţii
10 54 67 212 453 567 675 Şeful a ı̂nlocuit bila 32 cu bila
231 212 32 123 453 675 1321 54 67 567 54 şi bila 1321 cu bila având
212 32 67 567 675 1321 numărul cel mai apropiat de
ea, adică 453.
12 1 3 4 6 9 26 Şeful a ı̂nlocuit bila 2 cu bila 1.
3 4 6 7 8 9 2 1 10 18 22 26 Apoi a ı̂nlocuit bila 22 cu bila
2 9 3 4 22 6 26 (18 este la fel de apropiat ca
şi 26 de bila 22, dar 26 este mai
mare).
Timp maxim de executare/test: 1.0 secunde
174
CAPITOLUL 13. OJI 2010 13.1. LOTO - OJI 2010 175
57 close(output);
58 end.
Cerinţe
Date fiind rezultatele obţinute pe teste de Vasilică la fiecare soluţie trimisă, să se determine
punctajul maxim pe care el l-a obţinut la problema respectivă.
Date de intrare
Fişierul de intrare submit.in conţine pe prima linie numărul natural N reprezentând numărul
de teste pe care este evaluată soluţia.
Pe cea de a doua linie se află N numere naturale separate prin spaţii P1 P2 ...PN , reprezentând
ı̂n ordine punctajul acordat pentru fiecare dintre cele N teste.
Pe cea de a treia linie se află numărul natural B reprezentând bonusul (numărul de puncte
acordate ı̂n cazul ı̂n care pentru toate testele soluţia obţine punctaj pe toate testele).
Pe a patra linie este scris un număr natural M reprezentând numărul de soluţii trimise de
Vasilică la problemă.
Urmează M linii, fiecare linie conţinând rezultatele obţinute pe teste la cele M soluţii trimise
de Vasilică, ı̂n ordinea trimiterii lor. Pe cea de a i-a linie (1 & i & M ) dintre cele M sunt scrise N
valori din mulţimea r0, 1x, separate prin spaţii; a j-a valoare (1 & j & N ) este 0 dacă testul j nu
a fost rezolvat corect, respectiv 1 dacă testul j a fost corect rezolvat (obţinând punctajul maxim
alocat pe test).
Date de ieşire
Fişierul de ieşire submit.out va conţine o singură linie pe care va fi scris punctajul maxim
obţinut de Vasilică la problema respectivă.
Exemple
readln(fin, n);
for i:=1 to n do read(fin, pct[i]);
readln(fin);
readln(fin, bonus);
readln(fin, m);
max:=0;
for j:=1 to m do
begin
complet:=true;
crt:=0;
for i:=1 to n do
begin
read(fin, p);
if p=0 then complet:=false
else crt:=crt+pct[i];
end;
readln(fin);
crt:=crt - 2*(j-1);
writeln(fout, max);
179
Capitolul 14
ONI 2022
14.1 iluminat
Problema 1 - Iluminat 100 de puncte
Primarul oraşului X doreşte să aibă un iluminat public modern. Pentru aceasta, realizează
o schiţă sub forma unui pătrat cu n linii şi n coloane ı̂n care fiecare element situat la intersecţia
unei linii cu o coloană reprezintă un cartier.
Primarul a calculat pentru fiecare cartier care este numărul de stâlpi de iluminat public din
acel cartier.
Fiecare stâlp are un singur bec care iniţial este aprins. Acesta a observat un lucru interesant:
toate cartierele au un număr diferit de stâlpi de iluminare, iar valoarea maximă a numărului de
2
stâlpi dintr-un cartier este n .
Pentru a fi realizată ı̂ntr-un mod cât mai eficient, stingerea becurilor se realizează ı̂n următorul
mod:
ı̂n prima etapă se sting becurile din cartierul cu număr maxim de stâlpi de iluminat, ceea
ce duce la stingerea becurilor din cartierele de pe aceeaşi linie precum şi din cele pe aceeaşi
coloană cu cartierul cu număr maxim de stâlpi.
procedeul se reia la fiecare etapă pentru toate cartierele ı̂n care nu au fost stinse becurile,
până când rămâne un singur cartier iluminat.
Cerinţe
Cunoscând numerele naturale nenule n şi k, precum şi numărul de stâlpi de iluminat din fiecare
cartier, să se determine:
1. Câţi stâlpi de iluminat se află ı̂n cartierul cu număr maxim de stâlpi de iluminat la etapa
cu numărul k din procedeul de stingere a becurilor?
2. Câte becuri se sting, ı̂n total, la etapa cu numărul k?
3. Care este numărul maxim de becuri aprinse ı̂ntr-o zonă pătratică a oraşului de dimensiune
k k, ı̂nainte de a ı̂ncepe stingerea becurilor?
Date de intrare
Fişierul de intrare iluminat.in conţine pe prima linie o cifră c (1, 2 sau 3), reprezentând
cerinţa cerută.
Pe linia următoare se găsesc două numere naturale nenule n şi k, separate printr-un spaţiu.
2
Pe următoarele n linii se află n numere naturale distincte, câte n pe fiecare linie, separate
prin câte un spaţiu, cu semnificaţia din enunţ .
Date de ieşire
180
CAPITOLUL 14. ONI 2022 14.1. ILUMINAT 181
c " r1, 2, 3x
1 & k $ n & 1000
2
Numărul de becuri din fiecare cartier este mai mic sau egal cu n
# Punctaj Restricţii
1 28 c 1
2 36 c 2
3 36 c 3
Exemple:
iluminat.in iluminat.out
1 15
42
1234
16 13 5 6
12 9 7 14
10 11 8 15
2 52
42
1234
16 13 5 6
12 9 7 14
10 11 8 15
3 50
42
1234
16 13 5 6
12 9 7 14
10 11 8 15
Explicaţii:
Primul exemplu
Cerinţa este 1. Se sting becurile din cartierul având 16 stâlpi de iluminat, ceea ce duce la
stingerea becurilor de pe stâlpii din linia 2 şi din coloana 1. Tabloul devine:
0 2 3 4
0 0 0 0
0 9 7 14
0 11 8 15
La etapa a doua, primul cartier ı̂n care se sting becurile are 15 stâlpi de iluminat.
Al doilea exemplu
Cerinţa este 2. Se sting becurile din cartierul având 16 stâlpi de iluminat, ceea ce duce la
stingerea becurilor de pe stâlpii din linia 2 şi din coloana 1. Tabloul devine:
0 2 3 4
0 0 0 0
0 9 7 14
0 11 8 15
La etapa a doua, primul cartier ı̂n care se sting becurile are 15 stâlpi de iluminat, ceea ce duce
la stingerea becurilor din linia 4 şi din coloana 4 din noul tablou. Acesta devine:
CAPITOLUL 14. ONI 2022 14.1. ILUMINAT 182
0 2 3 0
0 0 0 0
0 9 7 0
0 0 0 0
Al treilea exemplu
Cerinţa este 3. Numărul maxim de becuri aprinse ı̂ntr-o zonă pătratică a oraşului de dimensiune
2 2 este 50, ı̂n zona cu colţul stânga-sus pe linia 2 şi coloana 2
16 13
12 9
Propusă de: prof. Violeta Grecea - Colegiul Naţional de Informatică ”Matei Basarab” Râmnicu Vâlcea
Cerinţele 1 şi 2. Rezolvarea acestor două cerinţe presupune simularea stingerii becurilor: pe
linia şi coloana pe care se află numărul maxim se sting toate becurile.
Soluţie brută. Constă ı̂n calcularea efectivă a maximului prin parcurgerea tuturor ele-
mentelor din matrice şi apoi, parcurgerea liniei şi a coloanei pe care se află acesta şi atribuirea
valorii 0 pentru toate elementele ı̂ntâlnite pe această linie şi această coloană. Procedeul se repetă
pentru fiecare etapă, până la etapa k de stingere a becurilor.
Apoi:
Pentru cerinţa 1 se afişează maximul găsit la etapa k.
Pentru cerinţa 2 se calculează suma elementelor de pe linia şi coloana maximului, prin
parcurgerea liniară a acestora. Maximul nu trebuie adăugat de 2 ori (o dată la parcugerea
liniei şi a doua oară la parcurgerea coloanei).
Această soluţie nu va lua punctaj maxim, deoarece nu se ı̂ncadrează ı̂n timp (complexitate
2
temporală O k n ), punctajul maxim posibil fiind de 36 de puncte pentru ambele cerinţe.
Soluţie brută. Constă ı̂n parcurgerea fiecărei submatrice cu k linii şi k coloane şi calcularea
sumei elementelor sale.
Soluţie optimă. Constă ı̂n precalcularea unor sume parţiale, utilizând formula pentru sume
parţiale 2D:
14.2 inundatie
Problema 2 - Inundaţie 100 de puncte
Fie un şir de N coloane de ciment (poziţiile lor fiind numerotate de la 1 la N ) de aceeaşi
lăţime şi diverse ı̂nălţimi. Ele sunt ı̂ncadrate la stânga (poziţia 0) şi la dreapta (poziţia N 1)
de ziduri foarte ı̂nalte. Apa ı̂ncepe să curgă de deasupra primei coloane, câte o pătrăţică de apă
pe secundă. Apa se acumulează dacă are pereţi ı̂n stânga şi ı̂n dreapta, altfel curge mai jos către
dreapta. Deasupra fiecărei coloane de ciment se poate forma astfel o coloană de apă, cu ı̂nălţimea
egală cu numărul de pătrăţele de la nivelul apei până la zona de contact cu coloana de ciment.
Cerinţe
1. Care este ı̂nălţimea H a celei mai ı̂nalte coloane de apă după ce apa a ajuns peste tot la
ı̂nălţimea celei mai ı̂nalte coloane de ciment?
2. Care este numărul T de secunde ı̂n care apa ajunge să acopere coloana cu numărul P ?
3. Care este poziţia D a celei mai din dreapta coloane acoperită de apă după S secunde?
4. Care este poziţia R a celei mai din stânga coloane pe care o putem reduce cu o unitate astfel
ı̂ncât apa să ajungă cât mai repede la coloana P ?
Date de intrare
Date de ieşire
C " r1, 2, 3, 4x
3 & N & 100 000
1 & ı̂nălţimea oricărei coloane din şir & 20 000
1&P &N
1 & S & 100 000
O coloană de ı̂nălţime h este acoperită de apă dacă apa a ajuns la ı̂nălţimea h.
CAPITOLUL 14. ONI 2022 14.2. INUNDATIE 184
# Punctaj Restricţii
1 11 C=1
2 25 C=2
3 33 C=3
4 31 C=4
Exemple:
inundatie.in inundatie.out
1 8
32 15 45
85543375 433543456544345432123459
2 21
32 15 45
85543375 433543456544345432123459
3 29
32 15 45
85543375 433543456544345432123459
4 7
32 15 45
85543375 433543456544345432123459
Explicaţii:
Toate exemplele se referă la figura de mai sus, diferă doar numărul cerinţei. În toate N 32,
P 15 şi S 45.
Primul exemplu: Linia portocalie de ı̂nălţime 9 este nivelul apei la momentul când toate
coloanele devin acoperite de apă. Cea mai ı̂naltă coloană de apă este cea cu numărul 27, având 8
pătrăţele de apă.
Al doilea exemplu: În imaginea de mai sus, liniile roşii arată nivelurile apei la momentul
când apa acoperă coloana de la poziţia P 15. Observăm că sunt 21 de pătrăţele de apă sub
linie, deci este nevoie de 21 de secunde pentru a acoperi coloana 15.
Al treilea exemplu: Linia verde arată nivelul apei după 42 de secunde. Ea acoperă coloana
numărul 29. Lăsând apa să curgă ı̂ncă 3 secunde (până la cele S 45 secunde) nivelul nu se ridică
suficient pentru a ajunge la coloana 30 deoarece ar mai fi nevoie de 5 pătrăţele de apă, adică ı̂ncă
5 secunde.
Al patrulea exemplu: Cea mai din stânga coloană pe care o vom reduce cu unu este coloana
numărul 7. Astfel apa va ajunge cu 5 secunde mai devreme la coloana P 15. Linia maro (linia
de apă de ı̂nălţime 6 care se ı̂ntinde de la coloana 2 la coloana 6) arată cele 5 pătrăţele cu care
reducem timpul. Orice altă coloană am reduce nu va ajunge aşa repede.
CAPITOLUL 14. ONI 2022 14.2. INUNDATIE 185
Cerinţa 1. Înălţimea maximă a unei coloane de apă când apa ajunge peste tot la nivelul
coloanei maxime.
La acest moment nivelul apei este uniform şi are exact ı̂nălţimea celei mai ı̂nalte coloane.
Deci cea mai ı̂naltă coloană de apă va fi deasupra ı̂nălţimii minime. Răspunsul este hmax hmin ,
diferenţa dintre ı̂nălţimea maximă şi cea minimă de la intrare.
Complexitate timp: O N , complexitate memorie: O N
Cerinţa 4. numărul celei mai din stânga ı̂nălţimi pe care o vom reduce cu o unitate pentru
ca apa să ajungă cât mai repede la coloana cu numărul P .
Mergând de la P către stânga vom număra distanţele dintre ı̂nălţimi despărţite de apă.
CAPITOLUL 14. ONI 2022 14.3. SIRURI 186
Distanţa maximă, D, este cea unde vom reduce coloana din dreapta, deoarece reducând acea
coloană cu unu timpul se scurtează cu D. Procedăm astfel:
Pornim de la coloana numărul P de ı̂nălţime H, parcurgând ı̂nălţimile către stânga. Ne
oprim la prima ı̂nălţime hi mai mare sau egală cu H şi reţinem distanţa dintre cele două
ı̂nălţimi, D P i 1, precum şi poziţia ı̂nălţimii din dreapta acelei distanţe, P . Distanţa
D este chiar diferenţa de timp cu care se scurtează timpul ı̂n care apa ajunge la coloana P ,
dacă reducem coloana P cu unu.
Actualizăm ı̂nălţimea curentă H ca fiind hi şi P ca fiind i şi continuăm deplasarea către
următoarea ı̂nălţime mai mare sau egală cu H, obţinând o nouă distanţă D. La fiecare pas
reţinem D dacă este mai mare sau egal cu cel de până acum, ı̂mpreună cu numărul coloanei
din dreapta distanţei D, adică P . Este necesar mai mare sau egal deoarece dorim cea mai
din stânga coloană pe care o putem reduce.
Trebuie să dăm, ı̂nsă, atenţie specială cazului când avem mai multe coloane de aceeaşi ı̂nălţime
despărţ ite de ı̂nălţimi mai mici, de exemplu cazul 6,3,3,3,3,3,6,3,3, 6. Reducând cel mai din
dreapta 6 la 5 vom reduce timpul cu 2 secunde, distanţa până la următorul 6. Dar dacă reducem
următorul 6 la 5 nu vom câş tiga nimic, de fapt vom pierde o secundă.
Pentru a trata acest caz, după fiecare deplasare şi calcul de distanţă D, dacă hi are aceeaşi
ı̂nălţime cu H ne vom deplasa la stânga suplimentar până ce găsim o coloană strict mai ı̂naltă
decât H.
Complexitate timp: O N , complexitate memorie: O N .
14.3 siruri
Problema 3 - Şiruri 100 de puncte
Se citeşte un număr natural N şi un şir de N numere naturale a1 , a2 , ..., aN . Numerele din şir
nu conţin cifra 0. Începând de la primul număr din şir către ultimul se vor efectua următoarele
modificări:
dacă ultima cifră a unui număr este egală cu prima cifră a următorului număr din şir cele două
numere se unesc, cel de-al doilea lipindu-se de primul. Acest număr nou format se transformă,
oprindu-se doar o dată fiecare cifră care apare ı̂n număr: cea mai din stânga apariţie a cifrei
se păstrează, următoarele apariţii fiind eliminate. De exemplu, putem uni numerele 21245
şi 51278 rezultând numărul 2124551278. Se iau cifrele o singură dată rezultând 214578.
Numărul nou format se poate uni la rândul lui cu următorul şi aşa mai departe.
dacă ultima cifră a unui număr nu este egală cu prima cifră a următorului număr din şir
cele două numere nu se unesc, dar primul număr din cele două se va transforma, păstrându-
se doar o dată fiecare cifră care apare ı̂n număr: cea mai din stânga apariţie a cifrei se
păstrează, următoarele apariţii fiind eliminate.
Cerinţe
Date de intrare
Fişierul de intrare siruri.in conţine pe prima linie un număr natural c (1, 2 sau 3).
Pe a doua linie se găseşte un număr natural nenul N .
Pe a treia linie se află N numere naturale separate de câte un spaţiu reprezentând şirul iniţial.
CAPITOLUL 14. ONI 2022 14.3. SIRURI 187
Date de ieşire
c " r1, 2, 3x
1 & N & 100 000
1 & ai & 1 000 000 000
ai conţine doar cifre nenule, pentru oricare 1 & i & n
# Punctaj Restricţii
1 18 c 1
2 40 c 2
3 42 c 3
Exemple:
siruri.in siruri.out
1 3
8
21245 51278 869 33447 723 397897 545786 6783221
2 4
8
21245 51278 869 33447 723 397897 545786 6783221
3 83
9
21245 51278 869 33447 723 397897 545786 6783221
235788946
Explicaţii:
În primul exemplu cerinţa este 1. Sunt 8 numere ı̂n şir, dintre care doar 3 au cifre distincte:
[51278, 869, 723].
În al doilea exemplu cerinţa este 2. Sunt 8 numere ı̂n şir, după transformări şirul va arăta
astfel: [21457869, 3472, 3978, 54786321].
În al treilea exemplu cerinţa este 3. Sunt 9 numere ı̂n şir, după transformări şirul va arăta
astfel: [21457869, 3472, 3978, 54786321, 23578946]. Numărul maxim de cifre ale unui număr din
noul şir este 8 şi sunt 3 numere ı̂n noul şir care au 8 cifre: [21457869, 54786321, 23578946].
Propusă de: prof. Prof. Flavius Boian Colegiul Naţional ”Spiru Haret” Târgu-Jiu
Cerinţa 1. O soluţie eficientă este marcarea ı̂ntr-un vector de frecvenţă a cifrelor existente
pentru fiecare număr şi oprirea ı̂n cazul ı̂n care o cifră este deja marcată.
Cerinţa 2. Se verifică dacă ultima cifră a numărului curent este egală cu prima cifră a
numărului următor. Dacă acest lucru este adevărat se lipesc cele două numere, se elimină cifrele
care apar de mai multe ori, păstrându-se doar prima apariţie şi se repetă procedeul atât timp cât
este posibil.
CAPITOLUL 14. ONI 2022 14.3. SIRURI 188
Verificarea dacă numărul nou format se va uni cu următorul se face după ce ı̂n număr cifrele
rămân o singură dată. Dacă un număr nu are ultima cifră egală cu a următorului, acesta se
transformă prin s,tergerea cifrelor care apar de mai multe ori şi păstrarea celei mai din stânga
apariţii a acestora.
Cerinţa 3. Problema se reduce la a determina, ı̂n şirul nou format, câte numere cu număr
maxim de cifre există. Se parcurge şirul, se reţine numărul cu număr maxim de cifre şi numărul
de apariţii al unui astfel de număr. Rezolvarea cerinţei se poate face printr-o singură parcurgere a
şirului. Complexitate timp: O N Lmax, complexitate memorie: O N , unde Lmax reprezintă
numărul maxim de cifre ale unui număr.
ONI 2021
15.1 Butoi
Problema 1 - Butoi 100 de puncte
Vară, căldură mare. Gigel se joacă ı̂n curte udând florile. După ce
a terminat, mama lui ı̂i dă o sarcină mai grea.
Gigel trebuie să umple un butoi cu apă de rezervă ı̂n caz de secetă.
Dar nu oricum! El are la dispoziţie un şir de găleţi de diferite capacităţi
şi trebuie să le folosească doar pe acestea pentru umplerea completă a
butoiului. O operaţie constă ı̂n umplerea completă a unei o găleţi de la
sursa de apă şi golirea ei ı̂n butoi. Desigur, o găleată se poate folosi de
mai multe ori. Butoiul are capacitate de V litri, Gigel are N găleţi de
capacităţi c1 , c2 , ..., cN litri, numere ı̂ntregi şi distincte şi poate folosi
o găleată de cel mult K ori. Ajutaţi-l pe Gigel să umple butoiul.
Cerinţe
Date de intrare
Fişierul de intrare butoi.in conţine pe prima linie, un număr natural C care poate avea valorile
1, 2 sau 3 şi reprezintă numărul cerinţei. Linia a doua conţine patru valori naturale V N K P ,
separate prin câte un spaţiu, reprezentând ı̂n ordine capacitatea butoiului, numărul de găleţi,
numărul maxim de operaţii care poate fi efectuat cu o găleată, ı̂n cazul cerinţelor 1 şi 2, iar
ultimul număr reprezintă lungimea secvenţei norocoase căutate la cerinţa 3. Linia a treia conţine
N valori naturale distincte c1 , c2 , ..., cN , separate prin câte un spaţiu, reprezentând, ı̂n ordine,
capacităţile celor N găleţi din şir.
Date de ieşire
Fişierul de ieşire butoi.out conţine pentru cerinţa 1, pe prima linie, un ı̂ntreg reprezentând
numărul de modalităţi de a umple butoiul. Pentru cerinţa 2 prima linie va conţine N valori
naturale separate prin câte un spaţiu, reprezentând numărul de utilizări a fiecărei găleţi iar pentru
cerinţa 3 prima linie va conţine un număr natural reprezentând poziţia din şir a primei găleţi din
secvenţa norocoasă determinată.
189
CAPITOLUL 15. ONI 2021 15.1. BUTOI 190
Exemple:
V t1 c1 t2 c2 ... tn cn (15.1.5)
n
După fiecare dintre cele k adunări cu 1 trebuie să verificăm care este volumul total (folosim
formula (15.1.5)).
CAPITOLUL 15. ONI 2021 15.2. PĂSĂRI 191
Simularea tuturor combinaţiilor posibile folosind 1, 2..9 structuri repetitive incluse una ı̂n
alta.
Soluţie de tip backtracking (care nu se ı̂ncadrează ı̂n materia clasei a 6-a)
Se fixează capătul stânga al unui interval de lungime p şi se face suma elementelor. (scor
obţinut 66% puncte pe cerinţa 3)
Se calculează suma primelor p elemente, iar apoi se mişcă intervalul câte un singur pas la
dreapta. Pentru un intervalul st, dr se preia S- ul de la intervalul precedent st1, dr1,
se scade elementul eliminat cst1 şi se adaugă elementul nou introdus cdr (scor obţinut
100% puncte pe cerinţa 3)
Se folosesc sume parţiale pe prefixe. Notăm cu partiali c1 c2 ... ci. Suma
elementelor pe intervalul st; dr partialdr partialst 1 (scor obţinut 100% puncte
pe cerinţa 3)
1.4 Observaţii
Problema testează cunoştinţe despre:
15.2 Păsări
Problema 2 - Păsări 100 de puncte
2
În grădina lui Macarie, există N pomi fructiferi, de diferite ı̂nălţimi, plantaţi sub forma unui
caroiaj de N linii şi N coloane, numerotate de la 1 la N . Cum există păsări care mănâncă fructele
lor, Macarie s-a gândit să plaseze sisteme de supraveghere, care asigură protecţie ı̂ntr-o oarecare
măsură a pomilor situaţi pe linia şi coloana unde a fost amplasat, ı̂n toate cele 4 sensuri de
deplasare Nord, Sud, Est şi Vest, adică la stânga şi la dreapta ı̂n cadrul liniei şi ı̂n sus şi ı̂n jos ı̂n
cadrul coloanei. În oricare din aceste patru sensuri de deplasare, supravegherea asigurată de un
sistem se ı̂ntrerupe când ı̂ntâlneşte un pom de ı̂nălţime strict mai mare decât a pomului ı̂n care a
fost amplasat.
CAPITOLUL 15. ONI 2021 15.2. PĂSĂRI 192
Cerinţe
2
Cunoscând ı̂nălţimile tuturor celor N pomi, scrieţi un program care:
1. Presupunând că Macarie are un singur sistem de supraveghere determinaţi pentru o linie
dată L, care este coloana pomului ı̂n care trebuie amplasat sistemul de supraveghere astfel
ı̂ncât să fie protejaţi un număr maxim de pomi. Dacă există mai multe soluţii, se va afişa
coloana minimă.
2. Presupunând că Macarie a amplasat ı̂n fiecare pom al grădinii sale, câte un sistem de
supraveghere, determinaţi linia şi coloana pomului protejat de cele mai multe sisteme de
supraveghere. Dacă există mai multe soluţii se va afişa soluţia cu linia minimă, iar ı̂n cazul
ı̂n care liniile sunt egale, cea cu coloana minimă.
Date de intrare
Fişierul de intrare pasari.in conţine pe prima linie, un număr natural C care poate avea
valorile 1, sau 2 şi reprezintă numărul cerinţei care trebuie rezolvată. Dacă C 1 atunci pe a
doua linie se află perechea de numere naturale N şi L separate printr-un spaţiu, iar dacă C 2,
pe cea de-a doua linie se află un număr natural N având semnificaţia din enunţ. Pe următoarele
N linii, câte numere N naturale despărţite prin câte un spaţiu, reprezentând ı̂n ordine, ı̂nălţimile
pomilor de pe fiecare rând, ı̂ncepând cu primul până la ultimul.
Date de ieşire
Exemple:
H ij (1 & i & N ; 1 & j & N ) = ı̂nălţimea pomului amplasat pe linia i şi coloana j.
Matricea H este citită din fiş ierul de intrare;
N ordij x (1 & i & N ; 1 & j & N ; x $ i) x este indicele maxim al unei linii, astfel
ı̂ncât H xj % H ij ; dacă nu există niciun astfel de x, se consideră că N ordij 0.
Mai informal spus, x reprezintă indicele liniei pomului de pe coloana j care va ı̂ntrerupe
supravegherea, pe direcţia N ord, generată de un sistem situat ı̂n pomul de pe linia i şi
coloana j (adică, primul pom strict mai ı̂nalt decât acesta, ı̂n sus);
Sudij x (1 & i & N ; 1 & j & N ; x % i) x este indicele minim al unei linii, astfel ı̂ncât
H xj % H ij ; dacă nu există niciun astfel de x, se consideră că Sudij N 1.
Mai informal spus, x reprezintă indicele liniei pomului de pe coloana j care va ı̂ntrerupe
supravegherea, pe direcţia Sud, generată de un sistem situat ı̂n pomul de pe linia i şi coloana
j (adică, primul pom strict mai ı̂nalt decât acesta, ı̂n jos);
V estij y (1 & i & N ; 1 & j & N ; y $ j) y este indicele maxim al unei coloane, astfel
ı̂ncât H iy % H ij ; dacă nu există niciun astfel de y, se consideră că V estij
0. Mai informal spus, y reprezintă indicele liniei pomului de pe linia i care va ı̂ntrerupe
supravegherea, pe direcţia V est, generată de un sistem situat ı̂n pomul de pe linia i şi
coloana j (adică, primul pom strict mai ı̂nalt decât acesta, la stânga);
Estij y (1 & i & N ; 1 & j & N ; y % j) y este indicele minim al unei coloane,
astfel ı̂ncât H iy % H ij dacă nu există niciun astfel de y, se consideră că Estij
N 1. Mai informal spus, y reprezintă indicele liniei pomului de pe linia i care va ı̂ntrerupe
supravegherea, pe direcţia Est, generată de un sistem situat ı̂n pomul de pe linia i şi coloana
j (adică, primul pom strict mai ı̂nalt decât acesta, la dreapta);
Prin urmare, pentru a rezolva corect cerinţa, trebuie să identificăm cel mai mic indice al
unei coloane j, pentru care ExtindereLj este maxim, după cum urmează:
Având ı̂n vedere că sistemul de supraveghere trebuie amplasat pe linia L, primită ı̂n cadrul
datelor de intrare, ı̂nseamnă că ne vor interesa doar valorile de pe linia L din matricele
N ord , Sud , V est , Est , şi implicit Extindere .
Valorile N ordLj , SudLj , V estLj , EstLj (1 & j & N ); j-fixat se pot calcula
ı̂n complexitatea de timp O N , utilizând o structură repetitivă, iterând un indice până
când am ı̂ntâlnit un pom mai ı̂nalt decât cel curent (linia L, coloana j), sau am ieşit din
matrice.
CAPITOLUL 15. ONI 2021 15.2. PĂSĂRI 194
Pentru a calcula N ordLj şi SudLj pentru un j-fixat (1 & j & N ), putem proceda
astfel:
Nord[L][j] = 0, Sud[L][j] = N + 1;
for(int x = L - 1; x >= 1; --x)
if(H[x][j] > H[L][j])
{
Nord[L][j] = x;
break;
}
for(int x = L + 1; x <= N; ++x)
if(H[x][j] > H[L][j])
{
Sud[L][j] = x;
break;
}
În mod similar, se pot calcula valorile V estLj şi EstLj pentru un j-fixat (1 & j & N ).
O soluţie care are complexitatea totală de timp O N N obţine punctajul maxim pentru
C 1.
În cadrul acestei cerinţe, se ştie faptul că ı̂n fiecare pom dintre cei N N este amplasat câte un
dispozitiv de supraveghere. Aşadar, pentru fiecare linie i şi coloană j (1 & i & N ; 1 & j & N )
avem că: Extindere[i][j] C 1 (dispozitivul va supraveghea, cu siguranţă, cel puţin un pom, şi
anume pomul de pe linia i şi coloana j).
Se cere să se afle care sunt coordonatele (adică linia şi coloana) pomului care este supraveg-
heat de cele mai multe dispozitive.
Dispozitivul de supraveghere amplasat ı̂n pomul de pe linia i şi coloana j (1 & i & N; 1 &
j & N ) va supraveghea pomii:
- pe verticală (direcţia N ord Sud):
* (Nord[i][j] + 1; j);
* (Nord[i][j] + 2; j);
. . .
* (i 1; j);
* (i + 1; j);
. . .
* (Sud[i][j] 2; j);
* (Sud[i][j] 1; j).
3
O soluţie care are complexitatea de timp O N , asemănătoare cu cea de la cerinţa 1, prin
care se utilizează O N operaţii pentru fiecare dintre cele N N dispozitive, şi marchează
corespunzător modificările ı̂n matricea cnt , nu va reuşi să obţină punctajul maxim,
ı̂ntrucât va depăşi considerabil limita de timp alocată.
Pentru a obţine punctajul maxim, vom alege să calculăm ı̂ntr-un mod mai eficient matricele
N ord , Sud , V est , Est . Ne propunem ca fiecare linie din aceste matrice să
fie corect calculată folosind doar O N paşi reducând astfel complexitatea totală la O N N .
Pentru a calcula cum va arăta linia i din matricea Est, vom folosi un vector auxiliar,
procedând astfel:
int K = 0;
for(int j = 1; j <= N; ++j)
{
while(K && H[i][j] > H[i][V[K]])
Est[i][V[K]] = j, --K;
V[++K] = j;
}
for(int j = 1; j <= K; ++j)
Est[i][V[j]] = (N + 1);
15.3 Puternic
Problema 3 - Puternic 100 de puncte
Un număr puternic este un număr natural mai mare decât 1 care are proprietatea că dacă
2
este divizibil cu numărul prim p atunci este divizibil şi cu p . De exemplu, 36 şi 27 sunt numere
puternice, ı̂n timp ce 12 nu este număr puternic deoarece este divizibil cu 3 şi nu este divizibil cu
2
3 . La ora de matematică, elevii au aflat ce ı̂nseamnă un număr puternic. Pentru a verifica dacă
elevii au ı̂nţ eles, domnul profesor a scris pe tablă un şir de N numere naturale, X1 , X2 , X3 , ..., XN
şi l-a rugat pe Mihai să ştergă din şir numerele puternice.
Analizând numerele rămase, Mihai a observat că se poate obţine un număr puternic prin
concatenarea a două numere din şirul rămas, numere egal depărtate de capetele acestui nou şir.
Concatenarea presupune lipirea numărului din a doua jumătate a şirului la finalul celui aflat ı̂n
prima jumătate. Dacă noul şir are număr impar de elemente, elementul din mijloc se ignoră. De
exemplu, dacă şirul obţinut după ştergerea numerelor puternice este: 12, 1, 19, 13, 3, 21, 5 atunci
numerele obţinute prin concatenare sunt 125, 121, 193.
Cerinţe
Scrieţi un program care citeşte un număr natural N şi apoi un şir de N numere naturale şi
determină:
CAPITOLUL 15. ONI 2021 15.3. PUTERNIC 196
Date de intrare
Fişierul de intrare puternic.in conţine pe prima linie un număr natural C. Pentru toate
testele de intrare, numărul C poate avea doar valoarea 1 sau 2. Pe a doua linie a fişierului se
găseşte numărul natural N . Pe a treia linie se găsesc N numere naturale separate prin câte un
spaţiu.
Date de ieşire
Dacă C 1, se va rezolva cerinţa 1. În acest caz, fişierul de ieşire puternic.out va conţine pe
prima linie un număr natural reprezentând numărul de numere puternice din şirul dat.
Dacă C 2, se va rezolva cerinţa 2. În acest caz, fişierul de ieşire puternic.out va conţine
perechile de numere egal depărtate de capetele şirului obţinut după ştergere, prin concatenarea
cărora se obţine un număr puternic. Fiecare pereche se scrie pe câte un rând, iar numerele din
pereche se scriu separate printr-un spaţiu, primul număr fiind cel din stânga. Dacă sunt mai multe
astfel de perechi se vor afişa, ı̂n ordine, ı̂ncepând cu cea apropiată de capetele noului şir. Dacă nu
există nicio astfel de pereche, ı̂n fişierul puternic.out se va afiş 1.
Exemple:
Propunător: Prof. Ana-Maria Arişanu, Colegiul Naţional ”Mircea cel Bătrân”, Rm. Vâlcea
3.1 Cerinţa 1
Descompunem n̂ factori primi fiecare număr mai mare decât 1 din şir pentru a verifica dacă
este puternic.
Dacă prin descompunere obţinem un factor prim la puterea 1, numărul respectiv nu e puternic.
3.2 Cerinţa 2
Memorăm ı̂ntr-un vector numerele din şir care nu sunt puternice.
Concatenăm numerele egal depărtate de capetele noului şir şi verificăm dacă numărul obţinut
prin concatenare este puternic. Numerele din şirul iniţial sunt & 10 , prin urmare ı̂n urma con-
9
Pentru a verifica eficient dacă un număr x este puternic ţinem cont de următoarele observaţii
matematice:
CAPITOLUL 15. ONI 2021 15.3. PUTERNIC 197
1.024.000.000.000.000.000 10
5 18
4000
numărul x trebuie ı̂mpărţit, de câte ori este posibil, la toate numere prime mai mici sau
egale cu 4000. Dacă ı̂n timpul acestei descompuneri obţinem un factor prim la putere 1,
atunci numărul x nu este puternic
După ı̂mpărţiri rămânem cu x fie 1 (şi e puternic), fie produs de numere prime mai mari
decât 4000. Mai exact x poate fi produs de până la 4 numere prime mai mari decât 4000:
Putem folosi Ciurul lui Eratostene până la 4000, pentru a verifica dacă un număr obţinut prin
concatenare este puternic.
Pentru a verifica dacă numărul rămas este pătrat perfect sau cub perfect putem folosi o căutare
binară ori biblioteca cmath şi calcula direct rădăcina pătrată (sqrt) şi radical de ordin 3 (cbrt)
(atenţie la erorile de precizie, se poate ca uneori sqrt(16) = 3:99999).
198
Capitolul 17
ONI 2019
Cerinţe
Ştiind care sunt adresele celulelor din care va pleca Maya, se cere:
1. Să se afişeze coloanele care conţin cele mai multe celule iniţiale.
2. Cunoscând, ı̂n plus, secvenţele de mutări pe care le va executa Maya, pentru a ajunge la
fiecare albinuţă, se cer adresele celor N celule destinaţie.
Date de intrare
Fişierul de intrare maya.in conţine pe prima linie numărul natural C (1 sau 2) reprezentând
cerinţa problemei. Pe linia următoare va fi numărul natural N reprezentând numărul de celule
iniţiale. Pe următoarea linie vor fi N adrese separate prin câte un spaţiu, o adresă fiind de forma
ColoanăNumăr.
Pentru cerinţa 2, vor mai exista, ı̂n continuare, N linii conţinând fiecare: un număr natural
reprezentând numărul de mişcări, urmat, după un spaţiu, de o secvenţă de cifre 1, 2, 3, 4, 5 sau 6
(fără spaţii ı̂ntre ele) reprezentând direcţiile ı̂n care se va deplasa Maya pentru a ajunge la celula
destinaţie.
Date de ieşire
199
CAPITOLUL 17. ONI 2019 17.1. MAYA - ONI 2019 200
Exemple
Cerinta 1:
Pentru determinarea coloanelor care contin cele mai multe celule initiale se poate folosi un
vector de frecventa pentru literele mari ale alfabetului englez.
In C/C++, pozitia din vectorul de frecventa se va determina folosind codul ASCII al literelor.
¬ ¬
Astfel, daca vectorul de frecventa este v atunci v carater A va contine de cate ori apare
caracter in sirul celor n cellule citite.
Cerinta 2:
Pentru fiecare celula de inceput exista o secventa de mutari. Se va citi caracter cu caracter
aceasta secventa. Se va tine cont de faptul ca prelucrarea se face separat pentru celulele din
coloanele A, C, E, G, .. si pentru celulele din coloanele B, D, F, H, ...
75 valfin = valin - 1;
76 break;
77 case 5:
78 urm = (char)(ant - 1);
79 valfin = valin;
80 if(urm < ’A’)
81 urm = ’Z’;
82 break;
83 case 6:
84 urm = (char)(ant - 1);
85 valfin = valin + 1;
86 if(urm < ’A’)
87 urm =’Z’;
88 break;
89 }
90 }
91 else
92 {
93 switch(val)
94 {
95 case 1:
96 urm = ant;
97 valfin = valin + 1;
98 break;
99 case 2:
100 urm = (char)(ant + 1);
101 valfin = valin;
102 if(urm > ’Z’)
103 urm = ’A’;
104 break;
105 case 3:
106 urm = (char)(ant + 1);
107 valfin = valin - 1;
108 if(urm > ’Z’)
109 urm = ’A’;
110 break;
111 case 4:
112 urm = ant;
113 valfin = valin - 1;
114 break;
115 case 5:
116 urm = (char)(ant - 1);
117 valfin = valin - 1;
118 break;
119 case 6:
120 urm = (char)(ant - 1);
121 valfin = valin;
122 break;
123 }
124 }
125 ant = urm;
126 valin = valfin;
127 }
128 fout << ant << valin << ’\n’;
129 }
130 }
131
132 int main()
133 {
134 int pr;
135 fin >> pr;
136 if(pr == 1)
137 cerinta_1();
138 else
139 cerinta_2();
140 return 0;
141 }
82 else if(s[j]==’2’)
83 {
84 if(cod%2==1) y++;
85
86 cod++;
87 if(cod==ref2)
88 cod=’A’;
89 }
90 else if(s[j]==’3’)
91 {
92 if(cod%2==0) y--;
93
94 cod++;
95 if(cod==ref2)
96 cod=’A’;
97 }
98
99 else if(s[j]==’4’)
100 {
101 y--;
102 }
103
104 else if(s[j]==’5’)
105 {
106 if(cod%2==0) y--;
107
108 cod--;
109 if(cod==ref1)
110 cod=’Z’;
111 }
112
113 else if(s[j]==’6’)
114 {
115 if(cod%2==1) y++;
116
117 cod--;
118 if(cod==ref1)
119 cod=’Z’;
120 }
121
122 }
123 //-------------------------------
124
125 g<<char(cod)<<y<<’\n’;
126
127 } //end for(i=1;i<=N;i++)
128
129 }
130
131 return 0;
132 }
din şir. Studiind numerele din tabel, constată că printre acestea se află şi
numere care nu sunt prime.
De exemplu, pentru k 4, tabelul arată ca ı̂n imaginea din dreapta.
Cerinţe
Date de intrare
Fişierul de intrare optime.in conţine pe prima linie o cifră c care poate să fie doar 1 sau 2.
Dacă c 1, pe linia a doua se găseşte un număr natural nenul k cu semnificaţia din enunţ. Dacă
c 2, pe linia a doua se află două numere naturale nenule, k şi x, cu semnificaţia din enunţ.
Date de ieşire
Dacă valoarea lui c este 1, atunci se va rezolva numai punctul 1 din cerinţă. În acest caz,
fişierul de ieşire optime.out va conţine pe prima linie un număr natural reprezentând valoarea
sumei determinate.
Dacă valoarea lui c este 2, se va rezolva numai punctul 2 din cerinţă. În acest caz, fişierul de
ieşire optime.out va conţine pe prima linie un număr natural reprezentând numărul de ordine al
primei coloane conform cerinţei, iar pe linia a doua numărul de numere prime, conform cerinţei.
Exemple
Pentru prima cerinta, se parcurge ciurul pana cand se intalnesc 2 k k numere care indeplinesc
conditiile de a le pune in tabel, dintre acestea cele care nu sunt prime adaugandu-se la suma.
Pentru rezolvarea celei de-a doua cerinte, se parcurg numerele prime din ciur care indeplinesc
conditiile pentru a fi puse in tabel, pana cand se gasesc 2 k k astfel de numere, calculandu-
se in acelasi timp numarul de numere prime de pe fiecare coloana. Pentru valorile obtinute, se
calculeaza secventa de suma maxima, de lungime x.
Sugeram determinarea coloanei careia ii apartine un numar prin calcul, nu prin plasarea lui
intr-o matrice.
Structurile de date utilizate: vectori.
VARIANTA 2 - 100 PUNCTE
PROF. FLAVIUS BOIAN - Colegiul National ”Spiru Haret” Targu Jiu
Se pregenereaza un vector care contine numerele prime, pentru a verifica optim daca un numar
este prim. Cream un vector de aparitii in care fiecare element apj reprezinta numarul de numere
prime de pe coloana j. Se afla secventa de lungime x si suma maxima din vectorul ap.
51 s=s+d%100;
52 d=d+2;
53 }
54 g<<s<<endl;
55 }
56
57 if(C==2)
58 {
59 f>>k>>x;
60 d=11;
61
62 for(i=1; i<=2*k; i++)
63 for(j=1; j<=k; j++)
64 {
65 while(prim(d)==0 or (d/10)%10==0)
66 d=d+2;
67 if(prim(d%100)==1)
68 ap[j]++;
69 d=d+2;
70 }
71
72 for(i=1; i<=x; i++)
73 suma=suma+ap[i];
74
75 incepe=1;
76 maxim=suma;
77 for(i=x+1; i<=k; i++)
78 {
79 suma=suma+ap[i]-ap[i-x];
80 if(suma>=maxim)
81 {
82 maxim=suma;
83 incepe=i-x+1;
84 }
85 }
86
87 g<<incepe<<endl<<maxim;
88 }
89
90 return 0;
91 }
32 for(i=3;i<=x;i=i+2)
33 if(a[i]==0)
34 for(j=i*i;j<N;j=j+i)
35 a[j]=1;
36 /***********************************/
37
38 f>>p;
39 f>>k;
40 stop=2*k*k;
41
42
43 if(p==1)
44 {
45 nr=0;
46 for(i=11;i<=N;i=i+2)
47 {
48 if(a[i]==0)
49 {
50 x=i%100;
51 if(x>9)
52 {
53 ++nr;
54 //g<<i<<’\n’;
55 if(a[x]==1)
56 {
57 S=S+x;
58 }
59 }
60
61 }
62
63 if(nr==stop) break;
64 }
65
66 g<<S;
67 }
68
69 if(p==2)
70 {
71 f>>x;
72 for(i=11;i<=N;i=i+2)
73 {
74 if(a[i]==0)
75 {
76 y=i%100;
77 if(y>9)
78 {
79 ++nr;
80 //g<<i<<’\n’;
81 if(a[y]==0)
82 {
83 poz=nr%k;
84 if(poz==0)
85 poz=k;
86 v[poz]++;
87 }
88 }
89 }//end if(a[i]==0)
90
91 if(nr==stop) break;
92 }
93
94 /*********************************/
95 // for(i=1;i<=k;i++)
96 // g<<v[i]<<’\n’;
97 // g<<’\n’<<’\n’;
98 /*********************************/
99
100 S=0;
101 for(i=1;i<=x;i++)
102 S=S+v[i];
103 gasit=1;
104 Smax=S;
105
106 //g<<Smax<<’\n’;
107 for(i=x+1;i<=k;i++)
CAPITOLUL 17. ONI 2019 17.2. OPTIME - ONI 2019 209
108 {
109 S=S+v[i]-v[i-x];
110 if(Smax<=S)
111 {
112 Smax=S;
113 gasit=i-x+1;
114 }
115 }
116
117 g<<gasit<<’\n’<<Smax<<’\n’;
118 }
119
120 return 0;
121 }
59 else
60 if(ciur[i%100]==0) v[k]++;
61 }
62
63 i=i+2;
64 }
65
66 s=0;
67 for(i=1;i<=x;i++) s=s+v[i];
68
69 mx=s;
70 p=1;
71 for(i=x+1;i<=k;i++)
72 {
73 s=s+v[i]-v[i-x];
74 if(s>=mx)
75 {
76 mx=s;
77 p=i-x+1;
78 }
79
80 }
81
82 g<<p<<’\n’<<mx;
83 }
84
85 }
Cerinţe
Cunoscându-se numărul N de elevi, precum şi numerele de pe tricouri, ı̂n ordinea ı̂n care elevii
se află iniţial ı̂n roată, să se determine N numere reprezentând poziţiile cu care roata se mişcă
circular pentru a coborı̂ fiecare elev, astfel ı̂ncât elevii să coboare din roată ı̂n ordinea crescătoare
a numerelor de pe tricou. Cele N numere de poziţii trebuie să fie ı̂n ordine strict crescătoare, iar
numărul total de poziţii trebuie să fie minim.
Date de intrare
Din fişierul roata.in se citeşte de pe prima linie N , reprezentând numărul de elevi, şi apoi se
citesc de pe linia a doua N numere naturale distincte, separate prin câte un spaţiu, reprezentând
numerele de pe tricouri.
Date de ieşire
În fişierul roata.out se vor scrie N numere, ı̂n ordine strict crescătoare, reprezentând numerele
de poziţii cerute.
Exemple
35 // g<<i<<" "<<ord[i]<<’\n’;
36 //}
37 /**********************************/
38
39 nr=ord[1]-1;
40
41 if(nr==0)
42 nr=nr+N;
43 g<<nr<<’ ’;
44
45 for(i=2;i<=N;i++)
46 {
47 cat=nr/N;
48 dif=ord[i]-ord[i-1];
49 if(dif<0)
50 dif=dif+N;
51
52 x=cat*N+dif;
53 if(x<=nr)
54 x=x+N;
55
56 nr=x;
57
58 g<<nr<<’ ’;
59 }
60
61 //g<<’\n’;
62
63 return 0;
64 }
ONI 2018
Cerinţe
Să se determine:
1. numărul total de divizori naturali ai lui X
2. divizorii lui X care aparţin intervalului A, B , unde A şi B sunt două numere naturale
date.
Date de intrare
Fişierul de intrare descmult.in conţine pe prima linie un număr natural C care reprezintă
cerinţa ce trebuie rezolvată (C 1 sau C 2).
A doua linie conţine, despărţite prin câte un spaţiu, trei numere naturale n A B, cu semnificaţia
din enunţ.
Pe linie a treia se află n numere naturale, separate prin câte un spaţiu, ce reprezintă factorii
primi D1 D2 ... Dn din descompunerea lui X.
Pe linia a patra se află n numere naturale, separate prin câte un spaţiu, ce reprezintă puterile
la care apar aceşti factori E1 E2 ... En .
Date de ieşire
Pentru C 1 se va rezolva doar prima cerinţă. În acest caz, fişierul de ieşire descmult.out
va conţine pe prima linie un singur număr natural nenul ce reprezintă numărul total de divizori
naturali ai lui X.
Pentru C 2 se va rezolva cea de-a doua cerinţă. În acest caz, fişierul de ieşire descmult.out
va conţine, separaţi prin câte un spaţiu, divizorii lui X ce aparţin intervalului A, B .
- 2 & n & 20
- 1 & A & B & 10
7
214
CAPITOLUL 18. ONI 2018 18.1. DESCMULT - ONI 2018 215
Exemple
Cerinţa 1
nrdiv E 1 1 E 2 1 ... E n 1
Cerinţa 2
Este o problemă de construcţie a soluţiei.
Vom construi pas cu pas vectorul divizorilor lui X, fie el SOL.
Prin parcurgerea factorilor primi Di, 1 & i & n, vom calcula toate puterile acestora & B.
E i
pi Di .
Fiecare putere generează la rândul ei, alţi divizori prin ı̂nmulţirea cu divizori existenţi ı̂n SOL:
9
10 int main()
11 {
12 freopen("descmult.in", "r", stdin);
13 freopen("descmult.out","w", stdout);
14
15 scanf("%d", &c);
16 scanf("%d%d%d", &n, &a, &b);
17 for(i=1; i<=n; ++i)
18 scanf("%d", &D[i]);
19 for(i=1; i<=n; ++i)
20 scanf("%d", &E[i]);
21
22 if (c == 1)
23 {
24 nrd = 1;
25 for(i=1; i<=n; ++i)
26 nrd *= (E[i] + 1);
27 printf("%llu\n", nrd);
28 }
29 else
30 {
31 F[1] = k = 1;
32 if (a == 1)
33 printf("1 ");
34 for(i=1; i<=n; ++i)
35 {
36 p = 1;
37 m = k;
38 while(E[i]--)
39 {
40 p *= D[i];
41 if (p > b)
42 break;
43 for(j=1; j<=k; ++j)
44 {
45 y = F[j] * p;
46 if (y <= b) {
47 if (y >= a)
48 printf("%d ", y);
49 F[++m] = y;
50 }
51 }
52 }
53 k = m;
54 }
55 printf("\n");
56 }
57
58 return 0;
59 }
http://algopedia.ro/wiki/index.php/Clasa_a_VI-a_lec%C8%9Bia_37_-_29_mai_2019
”Ce complexitate are această soluţie? Observăm că ea generează toţi divizorii mai mici sau
egali cu B ı̂n O 1, deci timpul va fi O M AXDIV . În practică el este ceva mai mare, deoarece
se testează mulţi divizori care vor depăşi B. Memoria este O M AXDIV deoarece divizorii mai
mici ca B sı̂nt şi stocaţi. Oare ne ı̂ncadrăm ı̂n timp şi memorie?
Ni se garantează că numărul de divizori ı̂ntre A şi B este maxim un milion. Ne foloseşte
acest lucru? Nu, deoarece ı̂n calculele de complexitate intervine doar numărul de divizori mai mici
decât B, independent de A. Acest număr ar putea fi suficient de mare ı̂ncât să depăşim memoria
(timpul e puţin probabil deoarece avem foarte mult). Aici cred că autorul a greşit, probabil a vrut
să spună că numărul de divizori mai mici decât B este maxim un milion. O greşeală destul de
gravă care ar putea duce un rezolvitor la ignorarea acestei soluţii de greutate medie şi căutarea
unei soluţii mai bune care poate nu există. Ţ, ţ, nu-i prea bine, nu?
Însă, deoarece soluţia autorului se ı̂ncadrează ı̂n memorie, aceasta ne ı̂mpinge să analizăm
matematic problema. Putem să ne dăm seama relativ uşor că numărul de divizori mai mici decât
B este, ı̂n fapt sub 200 000 şi deci soluţia se ı̂ncadrează ı̂n memorie.
Rezolvare mai rapidă
CAPITOLUL 18. ONI 2018 18.1. DESCMULT - ONI 2018 217
Putem să eliminăm aceste două probleme? Oare cum arată aceşti divizori? Ei vor fi descrişi
de un şir de puteri ale factorilor primi. Orice combinaţie de puteri este un posibil divizor. De aici
şi ideea: să generăm aceste puteri ca pe un număr mare, numărı̂nd. Pe fiecare poziţie vom avea
o putere cuprinsă ı̂ntre 0 şi Ei . Dacă ordonăm crescător puterile atunci vom putea incrementa
numărul mare cu unu pı̂nă ce nu mai putem incrementa căci depăşim B.
Iată o soluţie posibilă:”
Cerinţe
Scrieţi un program care citeşte dimensiunile curţii, dimensiunea unei dale, precum şi cele 3
costuri, cd, ct şi cm, şi rezolvă următoarele trei cerinţe:
1. determină numărul de dale ı̂ntregi montate ı̂n curte şi aria minimă a cuştii câinelui (amin);
2. determină numărul total minim de dale de gazon necesare pentru a acoperi ı̂ntreaga curte;
3. determină suma minimă pe care trebuie să o plătească Tudorel pentru a acoperi ı̂ntreaga
curte.
Date de intrare
Prima linie a fişierului de intrare gazon.in conţine un număr natural C, reprezentând cerinţa
care trebuie rezolvată (1, 2 sau 3).
A doua linie a fişierului conţine trei numere naturale separate prin câte un spaţiu, a b d,
reprezentând dimensiunile curţii şi dimensiunea unei dale de gazon.
Pe a treia linie a fişierului de intrare se găsesc trei numere naturale separate prin câte un
spaţiu, cd ct cm, reprezentând costurile unei dale, unei tăieturi, respectiv a montării unei dale sau
fâşii.
CAPITOLUL 18. ONI 2018 18.2. GAZON - ONI 2018 219
Date de ieşire
Fişierul de ieşire gazon.out va conţine o singură linie pe care va fi scris răspunsul la cerinţa
indicată ı̂n fişierul de intrare.
Dacă cerinţa este 1, răspunsul va fi format din două numere naturale separate printr-un spaţiu,
nr amin, unde nr reprezintă numărul de dale ı̂ntregi montate ı̂n curte, iar amin aria minimă a
cuştii câinelui.
Pentru cerinţele 2 sau 3, răspunsul va fi un singur număr natural (numărul total minim de
dale necesare pentru cerinţa 2, respectiv suma minimă pentru cerinţa 3).
Exemple:
gazon.in gazon.out Explicaţii
1 92 9 dale ı̂ntregi
13 14 4 zona care nu poate fi acoperită are aria 2 (2 x 1)
111
2 14 14 dale (9 ı̂ntregi + 5 tăiate)
13 14 4 5 tăieturi
111
3 34 14 dale (9 ı̂ntregi şi 5 tăiate)
13 14 4 5 tăieturi
111 15 montări
6. a % d + b % d = d şi a % d = d / 2 şi b % d = d / 2
7. a % d j 0 şi b % d j 0 şi a % d + b % d j d
Pentru cerinţa 3 trebuie avut grijă la faptul că, la limită, valorile pot depăşi tipul int (long),
deci trebuie utilizat tipul long long.
În acelaşi timp, prin multitudinea de cazuri care pot să apară, cazuri tratate ı̂n teste, orice
concurent poate lua/pierde puncte.
Structurile de date utilizate - date simple
Tipul problemei - divizibilitate, testează puterea de analiză a concurentului
Gradul de dificultate: 3-4
http://algopedia.ro/wiki/index.php/Clasa_a_VI-a_lec%C8%9Bia_22_-_28_feb_2019#
Problema_gazon
”... este o problemă strict de organizare şi atenţie, ea necesitând să navigăm cu succes prin
multiple cazuri particulare.
Problema cere să pavăm o suprafaţă cu dale. Putem tăia dalele, dar o singură dată. Dorim să
refolosim bucăţile de dale la maxim.
Vom aplica două reguli generale de rezolvare a oricărei probleme:
- Dacă introducem o ordine ı̂n obiectele de la intrare de obicei problema se simplifică.
- Trebuie să observăm toţi operatorii (mutările) pe care le putem face.
Pornind cu regula a doua, să nu ratăm operatori! De exemplu, când tăiem o dală este posibil:
- Ca una din bucăţi să se potrivească pe o latură, iar cealaltă bucată pe cealaltă latură.
- Ca ambele bucăţi să se potrivească pe aceeaşi latură
- Ca ambele bucăţi să se potrivească pe ambele laturi
Toate acestea combinat cu faptul că putem să nu avem nevoie de dale tăiate pe una sau pe
ambele laturi complică mult hăţişul de cazuri. În fapt, toate soluţiile oficiale au peste 100 de linii
(care scrise corect, o instrucţiune pe linie, se transformă ı̂n peste 120 linii). Pare că comisia nu
s-a descurcat prea bine ı̂n hăţişul de cazuri al propriei probleme, dat fiind că soluţia poate avea
sub 50 de linii.
Să aplicăm prima regulă: să introducem o ordine. Cum putem face acest lucru? Calculı̂nd
lăţimile dalelor parţiale necesare pe cele două laturi şi combinı̂ndu-le dacă ele sı̂nt identice. După
această operaţie vom avea:
- zero dale necesare, dacă zona se poate pava perfect
- un tip de dale necesare, cı̂nd fie doar o latură necesită pavare extra, fie dalele parţiale pe
ambele laturi sı̂nt identice
- două tipuri de dale necesare, cı̂nd ambele laturi necesită dale parţiale şi ele sı̂nt diferite
În realitate putem trata cazul cu zero dale suplimentare ca un caz particular al cazului cu un
singur tip de dale.
Deoarece dalele pot fi tratate la fel şi deoarece putem avea 0, 1, sau 2 tipuri, vom folosi doi
vectori de două elemente pentru a simplifica codul:
- ddale[i] este dimensiunea (lăţimea) dalei i
- ndale[i] este numărul de dale de tip i
Să presupunem că avem aceşti vectori. Atunci vom avea două cazuri:
- Avem două tipuri de dale iar cele două tipuri pot forma o dală completă. În acest caz vom
avea nevoie de numărul maxim de dale dintre cele două tipuri pentru a obţine necesarul de dale
extra.
- Avem zero, unul sau două tipuri de dale, dar care nu se pot combina ı̂ntre tipuri diferite.
ı̂n acest caz vom lua la rı̂nd tipurile de dale şi vom testa dacă se pot combina ı̂n cadrul tipului.
Aici vom avea iarăşi două cazuri:
` Dacă se pot combina ı̂n cadrul tipului (dala parţială este jumate din dala mare), vom
aduna acel număr de dale ı̂mpărţit la doi.
` În caz contrar vom aduna chiar numărul de dale de acel tip
”Desigur că soluţia, neavı̂nd bucle dependente de intrare, este O(1) atı̂t ca timp cı̂t şi ca
memorie.”
CAPITOLUL 18. ONI 2018 18.3. PIETRE - ONI 2018 222
Cerinţe
Să se determine numărul pietrei care efectuând sărituri ı̂n conformitate cu succesiunea dată,
conduce la o configuraţie finală formată dintr-un număr minim de pietre pe tablă. Dacă există
mai multe pietre care ar conduce la acelaşi număr minim de pietre ı̂n configuraţia finală, se va
afişa valoarea cea mai mică dintre numerele de identificare ale pietrelor respective.
Date de intrare
Date de ieşire
coloana cea mai din stânga (coloana cea mai mică) şi până la piatra cea mai de jos cu linia cea
mai de jos (cea mai mare) şi coloana cea mai din dreapta (cea mai mare).
Restricţii şi precizări
a 2 & n, m & 100;
a 2 & k & n m 1;
a 0 & g & n m 1.
a Se garantează că ı̂n fiecare test există cel puţin o piatră care efectuează cel puţin o săritură.
Exemple
pietre.in pietre.out Explicaţii
5462 5 Configuraţia iniţială este ı̂n figura alăturată.
11 4 Piatra 1: nu poate efectua săritura
12 11 V (deoarece ar părăsi tabla de joc),
22 12 nici săritura S (pentru că nu există
32 22 nicio piatră ı̂n celula vecină aflată ı̂n
33 51 direcţia sud), efectuează săritura E,
41 deci configuraţia finală a tabelei va Figura 18.4: piatra1
34 conţine 5 pietre.
53 Pentru piatra 2 se obţine configuraţia finală identică celei iniţiale,
VSE deoarece nu poate efectua nicio săritură.
Piatra 3 poate efectua doar săritura S. Configuraţia finală conţine 5
pietre.
Piatra 4 nu poate efectua nicio săritură. Configuraţia finală conţine
6 pietre.
Piatra 5 poate efectua săriturile: V
şi dispare piatra 4, S şi dispare pi-
atra şi nu poate efectua săritura E .
Configuraţia finală are 4 pietre şi este
ı̂n figura alăturată. Figura 18.5: piatra2
Piatra 6 nu poate efectua nicio săritură. Configuraţia finală conţine
6 pietre.
ONI 2017
Cerinţe
Scrieţi un program care să determine numărul minim de dale deteriorate ce trebuie ı̂nlocuite
astfel ı̂ncât faleza să poată fi parcursă de la un capăt la altul.
Date de intrare
Fişierul de intrare faleza.in are pe prima linie un număr natural n ce reprezintă lungimea
falezei.
Pe linia a doua şi a treia se află câte n numere care pot fi 0 sau 1. Pe aceeaşi linie, numerele
sunt separate prin câte un spaţiu. O valoare 1 semnifică prezenţa unei dale bune ı̂n acel loc iar
valoarea 0 semnifică o dală deteriorată. Pe linia a doua a fişierului se află codificarea unei părţi
din faleză (să spunem că aceea aflată către apă), iar pe linia a treia se află codificarea celeilalte
părţi a falezei.
Dalele sunt lipite una de alta ı̂n cadrul aceleiaşi linii, şi două câte două pe coloane.
Date de ieşire
Fişierul de ieşire faleza.out conţine un singur număr natural ce reprezintă numărul minim de
dale deteriorate ce trebuie ı̂nlocuite pentru a putea fi parcursă faleza de la un capăt la celălalt.
Exemple
224
CAPITOLUL 19. ONI 2017 19.1. FALEZA - ONI 2017 225
Construim două tablouri pe care le notăm A şi B, cu numerele din fişier, ı̂n A cele de pe o
parte a falezei şi ı̂n B cele de pe cealaltă.
Pentru simplificarea implementării, dacă avem poziţii i ı̂n care Ai 1 şi B i 1 putem
să analizăm doar ce se ı̂ntı̂mplă ı̂ntre două astfel de poziţii consecutive. Parcurgem element cu
element şi păstrăm mereu ultima poziţie pe care se află o dală bună pentru şirul A respectiv pentru
şirul B, alegând, ı̂n funcţie de acestea, modul de a completa dalele deteriorate.
Timpul de executare este liniar.
33 v[0][i+1]=1;
34 t++;
35 }
36 else if(v[0][i]==0&&v[1][i]==1&&v[1][i+1]==0)
37 {
38 v[1][i+1]=1;
39 t++;
40 }
41 else if(v[0][i+1]==0&&v[1][i+1]==0)
42 {
43 t++;
44 }
45 }
46
47 fout<<t<<’\n’;
48 fin.close();
49 fout.close();
50 return 0;
51 }
54 i++;
55 if(i==n+1)
56 break;
57 }
58
59 if(a[i]==1)
60 {
61 poza=1; // marchez randul pe care ma deplasez, cel in care
62 // am gasit primul 1 dupa secventa de 0
63 pozb=0;
64 }
65 else
66 if(b[i]==1)
67 {
68 pozb=1;
69 poza=0;
70 }
71
72 if(poza==1)
73 {
74 while(a[i+1]==1 and i!=n+1) // ma deplasez pe linia curenta pana
75 // la capatul secventei de 1
76 i++;
77
78 if(i==n) break;
79 else
80 if(a[i+1]==0 and b[i]==0) // daca urmatorul element e 0 si nu pot
81 // sa ma duc nici jos
82 {
83 i++;
84 k++; //creste nr de patratele necesare
85 a[i]=b[i-1]=k;
86 }
87 else
88 if(a[i+1]==0 and b[i]!=0) // daca urmatorul element e 0, dar
89 // am 1 pe linia cealalta
90 {
91 i++;
92 poza=0;
93 pozb=1; // schimb randul
94 }
95 else
96 if(a[i+1]==0 and b[i]!=0 and b[i+1]!=0) //ma duc jos si la dreapta
97 // pe randul 2, daca acolo am elemente nenule
98 {
99 i++;
100 poza=0;
101 pozb=1;
102 }
103
104 if(i==n && a[i]==0 && b[i]==0) // daca am ajuns pe ultima pozitie
105 // si am 0 pe amandoua liniile
106 k++; // creste numarul de placute
107 }
108 else
109 if(pozb==1) // daca sunt pe randul 2
110 {
111 while(b[i+1]==1 and i!=n+1) // fac aceleasi verificari ca
112 // la randul 1
113 i++;
114
115 if(i==n) break;
116
117 if(b[i+1]==0 and a[i]==0)
118 {
119 i++;
120 k++;
121 b[i]=a[i-1]=k;
122 }
123 else
124 if(b[i+1]==0 and a[i]!=0)
125 {
126 i++;
127 poza=1;
128 pozb=0;
129 }
CAPITOLUL 19. ONI 2017 19.1. FALEZA - ONI 2017 228
130 else
131 if(b[i+1]==0 and a[i]!=0 and a[i+1]!=0)
132 {
133 i++;
134 poza=1;
135 pozb=0;
136 }
137
138 if(i==n && a[i]==0 && b[i]==0)
139 k++;
140 }
141 }
142
143 g<<k;
144
145 return 0;
146 }
56 if(i==n+1) break;
57
58 if(a[i]==1)
59 {
60 poza=1; // marchez randul pe care ma deplasez, cel in care
61 // am gasit primul 1 dupa secventa de 0
62 pozb=0;
63 }
64 else
65 if(b[i]==1)
66 {
67 pozb=1;
68 poza=0;
69 }
70
71 if(poza==1)
72 {
73 while(a[i+1]==1 and i!=n+1) // ma deplasez pe linia curenta pana
74 // la capatul secventei de 1
75 i++;
76
77 if(i==n) break;
78 else
79 if(a[i+1]==0 and b[i]==0) // daca urmatorul element e 0 si nu pot
80 // sa ma duc nici jos
81 {
82 i++;
83 k++; //creste nr de patratele necesare
84 a[i]=b[i-1]=k;
85 }
86 else
87 if(a[i+1]==0 and b[i]!=0) // daca urmatorul element e 0, dar
88 // am 1 pe linia cealalta
89 {
90 i++;
91 poza=0;
92 pozb=1; // schimb randul
93 }
94 else
95 if(a[i+1]==0 and b[i]!=0 and b[i+1]!=0)// ma duc jos si la dreapta
96 // pe randul 2, daca acolo am elemente nenule
97 {
98 i++;
99 poza=0;
100 pozb=1;
101 }
102
103 if(i==n && a[i]==0 && b[i]==0) // daca am ajuns pe ultima pozitie
104 // si am 0 pe amandoua liniile
105 k++; // creste numarul de placute
106 }
107 else
108 if(pozb==1) // daca sunt pe randul 2
109 {
110 while(b[i+1]==1 and i!=n+1) // fac aceleasi verificari
111 // ca la randul 1
112 i++;
113
114 if(i==n) break;
115
116 if(b[i+1]==0 and a[i]==0)
117 {
118 i++;
119 k++;
120 b[i]=a[i-1]=k;
121 }
122 else
123 if(b[i+1]==0 and a[i]!=0)
124 {
125 i++;
126 poza=1;
127 pozb=0;
128 }
129 else
130 if(b[i+1]==0 and a[i]!=0 and a[i+1]!=0)
131 {
CAPITOLUL 19. ONI 2017 19.1. FALEZA - ONI 2017 230
132 i++;
133 poza=1;
134 pozb=0;
135 }
136
137 if(i==n && a[i]==0 && b[i]==0)
138 k++;
139 }
140 }
141
142 g<<k;
143
144 return 0;
145 }
59 return 0;
60 }
61 // sirul se reduce la secventa de la p la u
62
63 //parcurg secventa de la p la u, memorand ultima pozitie din a si din b unde
64 // am 1 sau unde ar trebuie sa pun 1
65
66 if (a[p]==1) {ua=p; ub=0;}
67 else{ ua=0; ub=p;}
68
69 for(i=p+1;i<=u;i++)
70 {
71 if (a[i]==1 && b[i]==1) ua=ub=i;
72 else
73 if (a[i]==0 && b[i]==0)
74 {
75 if (ua==i-1) ua=i;
76 if (ub==i-1) ub=i;
77 nr++;
78 }
79 else
80 if (a[i]==1)
81 {
82 if (ua==i-1) ua=i;
83 else
84 {
85 ua=i; nr++;ub=i;
86 }
87 }
88 else
89 {
90 if (ub==i-1) ub=i;
91 else
92 {
93 ub=i; nr++; ua=i;
94 }
95 }
96 }
97
98 g<<nr;
99 }
32 {
33 if (a[i] == 1 && b[i] == 1)
34 {
35 sol += i-max(lasta, lastb)-1;
36 lasta = lastb = i;
37 lena = lenb = 0;
38 continue;
39 }
40
41 // continui o secventa de sus
42 if (a[i] == 1 && lasta == i-1)
43 {
44 lena++;
45 lasta = i;
46 continue;
47 }
48
49 //continui o secventa de jos
50 if (b[i] == 1 && lastb == i-1)
51 {
52 lenb++;
53 lastb = i;
54 continue;
55 }
56
57 if (a[i] == 1)
58 {
59 if (lasta >=lastb)
60 {
61 sol += i-lasta-1;
62 }
63 else
64 {
65 // lastb > lasta
66 sol += i-lastb;
67 lastb = i;
68 }
69
70 lasta = i;
71 continue;
72 }
73
74 if (b[i] == 1)
75 {
76 if (lastb >= lasta)
77 {
78 sol += i-lastb-1;
79 }
80 else
81 {
82 sol += i-lasta;
83 lasta = i;
84 }
85
86 lastb = i;
87 continue;
88 }
89 }
90
91 fout<<sol;
92
93 return 0;
94 }
10
11 void citeste()
12 {
13 int i,j;
14 char ch;
15 f>>n;
16
17 for(i=1;i<=2;i++)
18 for(j=1;j<=n;j++)
19 {
20 f>>ch;
21 a[i][j]=ch-’0’;
22 b[i][j]=0;
23 }
24 }
25
26 void calculeaza()
27 { int i,j,t;
28 b[1][0]=0;
29 b[2][0]=0;
30
31 for(j=1;j<=n;j++)
32 {
33 for(i=1;i<=2;i++)
34 if (a[i][j]==0)
35 b[i][j]=b[i][j-1]+1;
36 else
37 b[i][j]=b[i][j-1];
38
39 t=min(b[1][j],b[2][j]);
40
41 if (a[2][j]==0 && a[1][j]==0)
42 {
43 if (b[1][j]==t && b[2][j]!=t)
44 b[2][j]=t+1;
45 else
46 if (b[2][j]!=t)
47 b[1][j]=t+1;
48 }
49 else
50 if (a[2][j]==1 && a[1][j]==1)
51 {
52 if (b[1][j]==t)
53 b[2][j]=t;
54 else
55 b[1][j]=t;
56 }
57 else
58 if (a[2][j]==0 && a[1][j]==1)
59 {
60 if (b[1][j]!=b[2][j])
61 if (b[1][j]==t)
62 b[2][j]=t+1;
63 else
64 b[1][j]=t;
65 }
66 else
67 if (a[2][j]==1 && a[1][j]==0)
68 {
69 if (b[1][j]!=b[2][j])
70 if (b[1][j]==t)
71 b[2][j]=t;
72 else
73 b[1][j]=t+1;
74 }
75
76 }
77
78 t=min(b[1][n],b[2][n]);
79 g<<t;
80 }
81
82 int main()
83 {
84 citeste();
85 calculeaza();
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 234
86 return 0;
87 }
Cerinţe
Date de intrare
Fişierul de intrare peste.in conţine pe prima linie numărul natural P care poate avea valoarea
1 sau 2 şi reprezintă numărul cerinţei.
Cea de-a doua linie conţine un număr natural N cu semnificaţia din enunţ, iar pe următoarele
N linii, cele N numere scrise pe foaia ce i-a dat-o vulpea ursului, câte un număr natural pe fiecare
linie a fişierului.
Date de ieşire
Fişierul de ieşire peste.out conţine pe prima linie un singur număr natural determinat conform
cerinţei problemei.
a 1 & N & 100, fiecare dintre cele N numere au cel puţin 3 şi cel mult 18 cifre;
a pentru rezolvarea corectă a cerinţei 1 se acordă 40 de puncte, iar pentru rezolvarea corectă
a cerinţei 2 se acordă 60 de puncte;
a pentru cazul P 2, vor exista şi teste ı̂n valoare de 25 de puncte ı̂n care cele N numere
9
naturale au valori mai mici decât 10 şi alte teste ı̂n valoare de 10 puncte ı̂n care cele N numere
9
din fişierul de intrare sunt mai mici decât 10 şi au acelaşi număr de cifre.
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 235
Exemple
peste.in peste.out Explicaţii
1 2 Se va rezolva cerinţa 1 şi ı̂n fişier sunt patru numere cu care
4 vom proceda astfel: din 1791 eliminăm cifrele 1 şi 7 iar numărul
1791 rezultat este 91
802 din 802 eliminăm cifrele 0 şi 2 iar numărul rezultat este 8
777 din 777 eliminăm cifrele 7 şi 7 iar numărul rezultat este 7
77196
din 77196 eliminăm 7 şi 1 iar numărul rezultat este 796
S-au efectuat două eliminări cu aceleaşi două cifre alăturate: 1
şi 7.
2 9187967 Cu aceleaşi patru numere din exemplul precedent, vom rezolva
4 cerinţa 2.
1791 În urma eliminărilor efectuate s-au obţinut numerele:
802 91 8 7 796
777 Cel mai mare număr posibil, obţinut prin lipirea acestor numere
77196 este 9187967.
Cerinţa 1
a pentru fiecare număr citit din fişierul de intrare se memorează cifrele sale ı̂ntr-un tablou
unidimensional;
a se parcurge tabloul pentru a identifica cele două cifre alăturate ce trebuie eliminate;
a pentru eliminarea cifrelor se poate identifica o relaţie de ordine ce trebuie să existe ı̂ntre
cifrele eliminate şi celelate cifre sau se pot genera toate eliminările posibile pentru a calcula cel
mai mare număr obţinut ı̂n urma efectuării acestor operaţii;
a se marchează ı̂n tablou cu o valoare nesemnificativă cele două cifre eliminate, pentru a obţine
cel mai mare număr posibil ce se poate forma cu celelalte cifre rămase după eliminare;
a se construieşte un vector de frecvenţă pentru perechile de cifre c1 şi c2 ţinând cont că
eliminarea cifrelor c1 şi c2 are aceeaşi semnificaţie cu eliminarea cifrelor c2 şi c1;
a se determină valoarea maximă a vectorului de frecvenţă construit anterior.
Cerinţa 2
a se sortează numerele obţinute ı̂n urma eliminărilor cifrelor astfel ı̂ncât prin alăturarea lor să
se obţină cel mai mare număr posibil. Sortarea va avea drept criteriu semnificaţia fiecărei cifre şi
numărul cifrelor fiecărui număr (De exemplu, dacă ı̂n urma eliminărilor obţinem numerele 9, 9995
şi 9998, ele vor fi sortate astfel: 9 9998 9995 şi aceasta va fi de la stânga la dreapta, ordinea lipirii.
Se obţine astfel, cel mai mare număr posibil 999989995).
80 {
81 y = x/(p*100) * p + x % p;
82 cf = x/p % 100;
83 c1 = cf/10;
84 c2 = cf%10;
85 if (c1 > c2)
86 {
87 aux = c1;
88 c1 = c2;
89 c2 = aux;
90 }
91
92 cf = c1 * 10 + c2;
93 if (y > maxim)
94 {
95 maxim = y;
96 cod = cf;
97 }
98
99 p = p*10;
100 }
101
102 f[cod]++;
103 if (f[cod] > sol1)
104 sol1 = f[cod];
105
106 v[i] = maxim;
107 }
108
109 if (t == 1)
110 {
111 fout<<sol1;
112 return 0;
113 }
114
115 for (i=1;i<n;i++)
116 for (j=i+1;j<=n;j++)
117 if (!compare(v[j], v[i]))
118 {
119 aux = v[j];
120 v[j] = v[i];
121 v[i] = aux;
122 }
123
124 for (i=1;i<=n;i++)
125 fout<<v[i];
126
127 return 0;
128 }
24 nr1[++N1]=v[k2][i];
25
26 short int N2=0,nr2[40];// lipesc k2k1 si obtin nr2
27
28 for(i=1;i<=v[k2][0];i++)
29 if(v[k2][i]!=-1)
30 nr2[++N2]=v[k2][i];
31
32 for(i=1;i<=v[k1][0];i++)
33 if(v[k1][i]!=-1)
34 nr2[++N2]=v[k1][i];// compar nr1 si nr2 cifra cu cifra de la
35 // stanga la dreapta
36 i=1;
37 while(i<=N1)
38 if(nr1[i]<nr2[i])
39 return 1;
40 else
41 if(nr1[i]>nr2[i])
42 return 0;
43 else i++;
44
45 return 0;
46 }
47
48 void schimb_linia(int k1,int k2)
49 { int l=max(v[k1][0],v[k2][0]);
50
51 for(int j=0;j<=l;j++)
52 swap(v[k1][j],v[k2][j]);
53 }
54
55 void sortare_ptr_lipire()
56 { int k1,k2;
57
58 for(k1=1;k1<n;k1++)
59 for(k2=k1+1;k2<=n;k2++)
60 if(maimare(k1,k2)==1)
61 schimb_linia(k1,k2);
62 }
63
64 void afisare()
65 { int i,j;
66
67 for(i=1;i<=n;i++)
68 for(j=1;j<=v[i][0];j++)
69 if(v[i][j]!=-1) fout<<v[i][j];
70
71 fout<<’\n’;
72 }
73
74 int main ()
75 {
76 int i,j,k,m,p1,p2;
77 long long x,cut,xmax;
78
79 fin>>cerinta;
80 fin>>n;
81 fin.get();
82
83 for(i=1;i<=n;i++)
84 {
85 j=1;
86 while(1)
87 {
88 fin.get(c);
89 if(c!=’\n’)
90 {
91 v[i][j]=c-’0’;
92 j++;
93 }
94 else
95 break;
96 }
97 v[i][0]=j-1;
98 }
99
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 240
100 for(i=1;i<=n;i++)
101 {
102 for(j=1,xmax=0;j<=v[i][0]-1;j++)
103 {
104 for(k=1;k<=v[i][0];k++)
105 d[k]=v[i][k];
106
107 m=v[i][0]-2;
108 for(k=j;k<=m;k++)
109 d[k]=d[k+2];
110
111 for(k=1,x=0;k<=m;k++)
112 x=x*10+d[k];
113
114 if(x>xmax)
115 {
116 xmax=x;
117 p1=j;p2=j+1;
118 if(v[i][j]>v[i][j+1])
119 cut=v[i][j]*10+v[i][j+1];
120 else
121 cut=v[i][j+1]*10+v[i][j];
122 }
123 }
124
125 v[i][p1]=-1;v[i][p2]=-1;
126 f[cut]++;
127 }
128
129 for(i=0,maxi=0;i<=99;i++)
130 if(f[i]>maxi)
131 maxi=f[i];
132
133 if(cerinta==1)
134 fout<<maxi<<’\n’;
135 else
136 {
137 sortare_ptr_lipire();
138 afisare();
139 }
140
141 fin.close();
142 fout.close();
143 return 0;
144 }
50 {
51 int l=max(v[k1][0],v[k2][0]);
52
53 for(int j=0;j<=l;j++)
54 swap(v[k1][j],v[k2][j]);
55 }
56
57 void sortare_ptr_lipire()
58 {
59 int k1,k2;
60 for(k1=1;k1<n;k1++)
61 for(k2=k1+1;k2<=n;k2++)
62 if(maimare(k1,k2)==1)
63 schimb_linia(k1,k2);
64 }
65
66 void afisare()
67 {
68 int i,j;
69 for(i=1;i<=n;i++)
70 for(j=1;j<=v[i][0];j++)
71 if(v[i][j]!=-1) fout<<v[i][j];
72
73 fout<<’\n’;
74 }
75
76 int main ()
77 {
78 int i,j,k,m,p1,p2;
79 int x,cut,xmax;
80
81 fin>>cerinta;
82 fin>>n;
83 fin.get();
84
85 for(i=1;i<=n;i++)
86 {
87 j=1;
88 while(1)
89 {
90 fin.get(c);
91 if(c!=’\n’)
92 {
93 v[i][j]=c-’0’;
94 j++;
95 }
96 else
97 break;
98 }
99
100 v[i][0]=j-1;
101 }
102
103 for(i=1;i<=n;i++)
104 {
105 for(j=1,xmax=0;j<=v[i][0]-1;j++)
106 {
107 for(k=1;k<=v[i][0];k++)
108 d[k]=v[i][k];
109
110 m=v[i][0]-2;
111 for(k=j;k<=m;k++)
112 d[k]=d[k+2];
113
114 for(k=1,x=0;k<=m;k++)
115 x=x*10+d[k];
116
117 if(x>xmax)
118 {
119 xmax=x;
120 p1=j;p2=j+1;
121
122 if(v[i][j]>v[i][j+1])
123 cut=v[i][j]*10+v[i][j+1];
124 else
125 cut=v[i][j+1]*10+v[i][j];
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 244
126 }
127 }
128
129 v[i][p1]=-1;v[i][p2]=-1;
130 f[cut]++;
131 }
132
133 for(i=0,maxi=0;i<=99;i++)
134 if(f[i]>maxi)
135 maxi=f[i];
136
137 if(cerinta==1)
138 fout<<maxi<<’\n’;
139 else
140 {
141 sortare_ptr_lipire();
142 afisare();
143 }
144
145 fin.close();
146 fout.close();
147 return 0;
148 }
50
51 return 0;
52 }
53
54 void det (long long &x, int &nr)
55 {
56 long long nmax=0,p=1,nou;
57 while (p*10<=x)
58 {
59 nou=x/(p*100)*p+x%p;
60 //cout<<nou<< " obtinut prin eliminarea lui "<< x/p%100<<’\n’;
61 if (nou>nmax)
62 {
63 nmax=nou;
64 nr=x/p%100;
65 }
66 p=p*10;
67 }
68 x=nmax;
69 }
70
71 int main()
72 {
73 int n,c,i,z,u,maxap,nr;
74 long long x;
75 f>>c>>n;
76
77 if (c==1)
78 {
79 int v[100]={0};
80 for (i=1; i<=n; i++)
81 {
82 f>>x;
83 det (x,nr);
84 //cout<<"am eliminat "<<nr<<" am obtinut "<<x<<’\n’;
85
86 z=nr/10;
87 u=nr%10;
88
89 if (z<u)
90 nr=u*10+z;
91
92 v[nr]++;
93 }
94
95 maxap=v[0];
96
97 for (i=10; i<=99; i++)
98 if (v[i]>maxap)
99 maxap=v[i];
100
101 g<<maxap<<’\n’;
102 }
103 else
104 {
105 for (i=1; i<=n; i++)
106 {
107 f>>x;
108 det (x,nr);
109 a[i]=x;
110 }
111
112 sort(a+1,a+n+1,compara);
113
114 for (i=1; i<=n; i++)
115 g<<a[i];
116
117 g<<’\n’;
118 }
119
120 return 0;
121 }
1 #include <fstream>
2 #include <cstring>
3
4 using namespace std;
5
6 ifstream fin("peste.in");
7 ofstream fout("peste.out");
8
9 long long gasit, m, c, n, nr[110], j;
10 char v[110][21], a[21], b[21];
11
12 void trans(long long m)
13 {
14 long long i, mare= 0, p = 100, val;
15 int k = 0;
16 while (m > p / 10)
17 {
18 val = m / p * (p / 100) + m % (p / 100);
19 if ( mare < val)
20 {
21 mare = val;
22 i = m / (p / 100) % 100;
23 }
24 p = p * 10;
25 }
26
27 p = p / 1000;
28
29 while (p > 1)
30 {
31 mare = mare % p;
32 v[j][k] = ’0’;
33 p = p / 10;
34 v[j][k] += mare / p;
35 k++;
36 }
37
38 nr[i]++;
39 p = i / 10 + 10 * (i % 10);
40
41 if (p != i)
42 nr[p]++;
43 }
44
45 int main()
46 {
47 int mare, i;
48 fin >> c >> n; //cerinta si cate numere
49
50 for (j = 1; j <= n; ++j) //citeste numerele si transforma-le
51 {
52 fin >> m;
53 trans (m);
54 }
55
56 if (c == 1) //cerinta 1
57 {
58 mare = 0;
59 for (i = 0; i < 100; ++i)
60 {
61 if (nr[i] > mare)
62 mare = nr[i];
63 }
64 fout << mare << ’\n’;
65 }
66 else //cerinta 2
67 {
68 gasit = 1;
69 while (gasit) //sortare
70 {
71 gasit = 0;
72 for (i = 1; i < n; ++i)
73 {
74 strcpy(a, v[i]);
75 strcpy(b, v[i+1]);
76 strcat(a, b); //"ab"
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 247
56 mare = 0;
57 for (i = 0; i < 100; ++i)
58 if (nr[i] > mare)
59 mare = nr[i];
60 fout << mare << ’\n’;
61 }
62 else //cerinta 2
63 {
64 for (i = 1; i < n; i++) //sortare selectie
65 for (j = i + 1; j <= n; j++)
66 {
67 strcpy(a, v[i]);
68 strcpy(b, v[j]);
69 strcat(a, v[j]); //"ab"
70 strcat(b, v[i]); //"ba"
71 if (strcmp(a, b) < 0)
72 swap(v[i], v[j]);
73 }
74
75 for(i = 1; i <= n; ++i) //afisez rezultatele concatenate
76 fout << v[i];
77 fout << ’\n’;
78 }
79
80 return 0;
81 }
47 while (i < j)
48 {
49 aux = s[i];
50 s[i] = s[j];
51 s[j] = aux;
52 i++;
53 j--;
54 }
55
56 i = 1;
57 while(r[i] == s[i] && i<=n)
58 i++;
59
60 if (r[i] > s[i])
61 return 1;
62 else
63 return 0;
64 }
65
66
67 int main ()
68 {
69 ifstream fin ("peste.in");
70 ofstream fout("peste.out");
71
72 fin>>t>>n;
73 for (i=1;i<=n;i++)
74 {
75 fin>>x;
76 p = 1;
77 maxim = 0;
78 while (x/p >= 10)
79 {
80 y = x/(p*100) * p + x % p;
81 cf = x/p % 100;
82 c1 = cf/10;
83 c2 = cf%10;
84
85 if (c1 > c2)
86 {
87 aux = c1;
88 c1 = c2;
89 c2 = aux;
90 }
91
92 cf = c1 * 10 + c2;
93 if (y > maxim)
94 {
95 maxim = y;
96 cod = cf;
97 }
98
99 p = p*10;
100 }
101
102 f[cod]++;
103
104 if (f[cod] > sol1)
105 sol1 = f[cod];
106
107 v[i] = maxim;
108 }
109
110 if (t == 1)
111 {
112 fout<<sol1<<’\n’;
113 return 0;
114 }
115
116 for (i=1;i<n;i++)
117 for (j=i+1;j<=n;j++)
118 if (!compare(v[j], v[i]))
119 {
120 aux = v[j];
121 v[j] = v[i];
122 v[i] = aux;
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 250
123 }
124
125 for (i=1;i<=n;i++)
126 fout<<v[i];
127
128 fout<<’\n’;
129
130 return 0;
131 }
64 b[k2]=y%10;
65 y=y/10;
66 }
67
68 //inversam
69 for(i=1;i<=k1/2;i++)
70 swap(a[i],a[k1+1-i]);
71
72 for(i=1;i<=k2/2;i++)
73 swap(b[i],b[k2+1-i]);
74
75 //xy
76 for(i=1;i<=k1;i++)
77 c[i]=a[i];
78
79 k3=k1;
80 for(i=1;i<=k2;i++)
81 {
82 k3++;
83 c[k3]=b[i];
84 }
85
86 //yx
87 for(i=1;i<=k2;i++)
88 d[i]=b[i];
89
90 k4=k2;
91 for(i=1;i<=k1;i++)
92 {
93 k4++;
94 d[k4]=a[i];
95 }
96
97 for(i=1;i<=k4;i++)
98 if (c[i]>d[i])
99 return 1;
100 else
101 if (c[i]<d[i])
102 return 0;
103 return 1;
104 }
105
106 void sortare()
107 {
108 int i,ok;
109 long long aux;
110 ok=1;
111 while (ok)
112 {
113 ok=0;
114 for(i=1;i<n;i++)
115 if (maimare(z[i], z[i+1])!=1)
116 {
117 ok=1;
118 aux=z[i];
119 z[i]=z[i+1];
120 z[i+1]=aux;
121 }
122 }
123 }
124
125 void citeste()
126 {
127 int i;
128
129 f>>c>>n;
130 for(i=1;i<=n;i++)
131 f>>a[i];
132 }
133
134 int main()
135 {
136 int i;
137 citeste();
138 elimina();
139 if( c==1)
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 252
140 g<<maxim;
141 else
142 {
143 sortare();
144 for (i=1;i<=n;i++)
145 g<<z[i];
146 }
147
148 return 0;
149 }
Cerinţe
Date de intrare
Fişierul de intrare soricel.in conţine pe prima linie numărul natural P reprezentând cerinţa
din problemă care trebuie rezolvată.
Pe a doua linie vor fi cele trei numere naturale nenule N , M şi K, separate prin câte un spaţiu,
cu semnificaţiile din enunţ.
Pe fiecare dintre următoarele N linii se află câte M numere naturale separate prin câte un
spaţiu, reprezentând numărul de cubuleţe de caşcaval Ci,j depozitate ı̂n camera de coordonate
i, j
Date de ieşire
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 253
Dacă valoarea lui P este 1, fişierul de ieşire soricel.out va conţine pe prima linie cele două
valori conform cerinţei 1, adică numărul de zile ı̂n care se va goli depozitul şi numărul de camere
golite de John ı̂n ziua K. Valorile vor fi afişate ı̂n ordinea cerută şi separate printr-un spaţiu.
Dacă valoarea lui P este 2, fişierul de ieşire soricel.out va conţine pe prima linie cele două
valori conform cerinţei 2, adică numărul maxim de camere consecutive golite de John ı̂ntr-o zi şi
numărul zilei ı̂n care se va ı̂ntâmpla acest lucru. Valorile vor fi afişate ı̂n ordinea cerută şi separate
printr-un spaţiu.
Exemple
Se folosesc două tablouri, matricea A pentru a reţine numărul de cuburi de caşcaval din fiecare
cameră şi un tablou B pentru a reţine câte cubuleţe trebuie să fie consumate pentru a ajunge la
un număr pătrat perfect. Atunci când construim tabloul B avem grijă la următoarele aspecte:
a dacă nu există niciun cubuleţ de caşcaval ı̂n cameră, şi ı̂n tabloul B va fi 0;
a dacă iniţial există doar un cubuleţ de caşcaval, acesta va fi mâncat ı̂n prima zi de către
primul şoricel, deci ı̂n tabloul B va fi 0;
a dacă numărul de cubuleţe de caşcaval e iniţial pătrat perfect, ı̂n B va fi reţinută diferenţa
până la numărul pătrat perfect cel mai apropiat, mai mic decât valoarea citită.
Pentru prima cerinţă trebuie să determinăm maximul dintre valorile reţinute ı̂n B şi numărul
de valori din B egale cu K; aceste valori pot fi determinate pe măsură ce se citeşte matricea A.
Pentru cea de-a doua cerinţă se parcurge tabloul B conform enunţului (liniile impare se parcurg
de la prima la ultima coloana, iar cele pare se parcurg de la ultima spre prima coloană) şi se caută
cea mai lungă secvenţă de elemente nenule egale, ı̂n acelaşi timp, calculându-se şi numărul total
de cubuleţe de caşcaval din camerele care fac parte din secvenţă, adică dacă elementul din B e ı̂n
secvenţă
suma = (suma + cel mai mare pătrat perfect strict mai mic decât Aij ).
Dacă se găsesc două secvenţe de lungimi egale se va reţine cea cu suma mai mare, iar dacă şi
sumele sunt egale se va reţine cea care este formată din elemente mai mari in tabloul B (acestea
reprezintă de fapt ziua ı̂n care camera va fi golită).
La final se afişează lungimea secvenţei găsite şi elementul din care este ea formată.
38 if (a[i][j]>1)
39 b[i][j]=a[i][j]-cauta_patrat(a[i][j]-1);
40 else
41 b[i][j]=0;
42
43 maxim=max(maxim,b[i][j]);
44 }
45 }
46
47 void calculeaza_1()
48 {
49 int i,j,t=0;
50
51 for (i=1;i<=m;i++)
52 for(j=1;j<=n;j++)
53 if (b[i][j]==k) t++;
54
55 if (s==0)
56 g<<"0 0";
57 else
58 if (maxim==0)
59 g<<"1 0";
60 else
61 g<<maxim<<" "<<t;
62 }
63
64 void calculeaza_2()
65 {
66 int l1,l2,c1,c2,nr,k,t,i,j;
67
68 l1=1;
69 c1=1;
70 l2=m;
71 c2=n;
72 k=0;
73 nr=0;
74
75 if (maxim==0)
76 {
77 g<<"0 1";
78 }
79 else
80 {
81 maxim=0;nrmaxim=0;val=b[1][1];li=1;ci=1;
82 for(i=1;i<=m;i++)
83 if (i%2==1)
84 for (j=1;j<=n;j++)
85 {
86 if (b[i][j]==val)
87 {
88 k++;
89 nr=nr+a[i][j]-b[i][j];
90 }
91 else
92 {
93 if (val)
94 if (maxim<k)
95 {
96 maxim=k;nrmaxim=nr;
97 t=b[li][ci];
98 }
99 else
100 if (maxim==k)
101 if (nr>nrmaxim)
102 {
103 nrmaxim=nr;
104 t=b[li][ci];
105 }
106 else
107 if(nrmaxim==nr)
108 if (t<val)
109 t=val;
110 k=1;
111 val=b[i][j];
112 li=i;
113 ci=j;
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 256
114 nr=a[i][j]-b[i][j];
115 }
116 }
117 else
118 for(j=n;j>=1;j--)
119 {
120 if (b[i][j]==val)
121 {
122 k++;
123 nr=nr+a[i][j]-b[i][j];
124 }
125 else
126 {
127 if (val)
128 if (maxim<k)
129 {
130 maxim=k;nrmaxim=nr;
131 t=b[li][ci];
132 }
133 else
134 if (maxim==k)
135 if (nr>nrmaxim)
136 {
137 nrmaxim=nr;
138 t=b[li][ci];
139 }
140 else
141 if(nrmaxim==nr)
142 if(t<val)
143 t=val;
144
145 k=1;
146 val=b[i][j];
147 li=i;
148 ci=j;
149 nr=a[i][j]-b[i][j];
150 }
151 }
152
153 if (val)
154 if (maxim<k)
155 {
156 maxim=k;nrmaxim=nr;
157 t=b[li][ci];
158 }
159 else
160 if (maxim==k)
161 if (nr>nrmaxim)
162 {
163 nrmaxim=nr;
164 t=b[li][ci];
165 }
166 else
167 if(nrmaxim==nr)
168 if(t<val)
169 t=val;
170
171 g<<maxim<<" "<<t;
172 }
173 }
174
175 int main()
176 {
177 citeste();
178 if (c==1)
179 calculeaza_1();
180 else
181 calculeaza_2();
182 return 0;
183 }
3 #include <cmath>
4
5 using namespace std;
6
7 ifstream f("soricel.in");
8 ofstream g("soricel.out");
9
10 int a[202][202],v[50001],dif[50001],
11 c,n,m,k,i,j,x,t,maxim,r, lungime, zi,nr,smax,s;
12
13 int main()
14 {
15 f>>c;
16 f>>n>>m>>k;
17
18 for(i=1; i<=n; i++)
19 for(j=1; j<=m; j++)
20 f>>a[i][j];
21
22 maxim=1;
23 for(i=1; i<=n; i++)
24 {
25 if(i%2==1)
26 for(j=1; j<=m; j++)
27 {
28 x++;
29 if(a[i][j]!=0)
30 {
31 if(a[i][j]==1)
32 {
33 dif[x]=0;
34 v[x]=0;
35 }
36 else
37 if(sqrt(a[i][j])==int(sqrt(a[i][j])))
38 {
39 dif[x]=a[i][j]-
40 (sqrt(a[i][j])-1)*(sqrt(a[i][j])-1);
41 v[x]=(sqrt(a[i][j])-1)*(sqrt(a[i][j])-1);
42 }
43 else
44 {
45 dif[x]=a[i][j]-
46 (int(sqrt(a[i][j])))*(int(sqrt(a[i][j])));
47 v[x]=(int(sqrt(a[i][j])))*(int(sqrt(a[i][j])));
48 }
49 }
50
51 if(dif[x]==k) t++;
52 if(dif[x]>maxim)
53 maxim=dif[x];
54 }
55 else
56 for(j=m; j>=1; j--)
57 {
58 x++;
59 if(a[i][j]!=0)
60 {
61 if(a[i][j]==1)
62 {
63 dif[x]=0;
64 v[x]=0;
65 }
66 else
67 if(sqrt(a[i][j])==int(sqrt(a[i][j])))
68 {
69 dif[x]=a[i][j]-
70 (sqrt(a[i][j])-1)*(sqrt(a[i][j])-1);
71 v[x]=(sqrt(a[i][j])-1)*(sqrt(a[i][j])-1);
72 }
73 else
74 {
75 dif[x]=a[i][j]-
76 (int(sqrt(a[i][j])))*(int(sqrt(a[i][j])));
77 v[x]=(int(sqrt(a[i][j])))*(int(sqrt(a[i][j])));
78 }
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 258
79 }
80
81 if(dif[x]==k) t++;
82 if(dif[x]>maxim)
83 maxim=dif[x];
84 }
85 }
86 nr=1;
87 smax=s=v[1];
88 zi=1;
89 for(i=1; i<=n*m; i++)
90 if(dif[i]==dif[i+1])
91 {
92 nr++;
93 s+=v[i+1];
94 }
95 else
96 {
97 if(dif[i]!=0)
98 if(nr>lungime)
99 {
100 lungime=nr;
101 zi=dif[i];
102 smax=s;
103 }
104 else
105 if(nr==lungime)
106 {
107 if(s>smax)
108 {
109 lungime=nr;
110 zi=dif[i];
111 smax=s;
112 }
113 else
114 if(s==smax && dif[i]>zi)
115 {
116 lungime=nr;
117 zi=dif[i];
118 smax=s;
119 }
120 }
121 nr=1;
122 s=v[i+1];
123 }
124
125 if(c==1)
126 g<<maxim<<" "<<t;
127 else
128 g<<lungime<<" "<<zi;
129
130 return 0;
131 }
20
21 int main()
22 {
23 int n,m, maxx=0,nr=0,i,j,x,rx,p,k,u;
24
25 f>>p >>n>>m>>k;
26
27 for (i=1; i<=n; i++)
28 for (j=1; j<=m; j++)
29 f>>a[i][j];
30
31 if (p==1)
32 {
33 for (i=1; i<=n; i++)
34 for (j=1; j<=m; j++)
35 {
36 x=nrzile(a[i][j]);
37 if (maxx<x) maxx=x;
38 if (k==1)
39 {
40 if (a[i][j]!=1 && x==1) nr++;
41 }
42 else
43 if (x==k) nr++;
44 }
45
46 g<<maxx<<’ ’<<nr<<’\n’;
47 }
48 else
49 {
50
51 k=0;
52 for (i=1; i<=n; i++)
53 if (i%2!=0)
54 for (j=1; j<=m; j++) v[++k]=a[i][j];
55 else
56 for (j=m; j>=1; j--) v[++k]=a[i][j];
57 k++;
58 v[k]=-1;
59
60 long long smax,s;
61 int l=1,lmax=0;
62
63 if (v[1]<2) l=0;
64 else l=1;
65
66 for (i=2; i<=k; i++)
67 if (v[i]>1 && nrzile(v[i])==nrzile(v[i-1])) l++;
68 else
69 {
70 if (l>lmax)
71 {
72 lmax=l;
73 u=i-1;
74 smax=0;
75 for (j=u-lmax+1; j<=u; j++)
76 smax=smax+v[j];
77 }
78 else
79 if (l==lmax)
80 {
81 s=0;
82 for (j=i-1-lmax+1; j<=i-1; j++)
83 s=s+v[j];
84
85 if (s>=smax)
86 {
87 u=i-1;
88 smax=s;
89 }
90 }
91
92 if (v[i]<2) l=0;
93 else l=1;
94 }
95
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 260
96 g<<lmax<<’ ’<<nrzile(v[u])<<’\n’;
97 }
98 }
146 zi=elem;
147 }
148 else
149 if(lung == lung_max && sum>sum_max)
150 {
151 sum_max=sum;
152 zi=elem;
153 }
154
155 g<<lung_max<<" "<<zi; // afisez lungimea maxima a unei secvente
156 // de camere golite si ziua in care
157 // aceasta s-a realizat
158 }
159
160 return 0;
161 }
57
58 a[i][j] --;
59 if (a[i][j] != 0)
60 {
61 // caut in p primul element <= a[i][j]
62 st = 1;
63 dr = r;
64 while (st <= dr)
65 {
66 int mid = (st + dr)/2;
67 if (p[mid]<=a[i][j])
68 st = mid+1;
69 else
70 dr = mid-1;
71 }
72
73 a[i][j] -= p[dr];
74
75 if (a[i][j] > max1)
76 max1 = a[i][j];
77
78 if (a[i][j] == k-1)
79 sol1++;
80 }
81 }
82
83 if (t == 1)
84 {
85 fout<<max1+1<<" "<<sol1<<"\n";
86 return 0;
87 }
88
89 if (n < m)
90 d = n;
91 else
92 d = m;
93
94 r = 0;
95 for (i=1;i<=n;i++)
96 {
97 if (i%2 == 1)
98 for (j=1;j<=m;j++)
99 v[++r] = a[i][j], w[r] = b[i][j] - a[i][j];
100 else
101 for (j=m;j>=1;j--)
102 v[++r] = a[i][j], w[r] = b[i][j] - a[i][j];
103 }
104
105 L = 1;
106 for (i=2;i<=r;i++)
107 {
108 if (v[i] == v[i-1])
109 {
110 L++;
111 suma += w[i];
112 }
113 else
114 {
115 L = 1;
116 suma = w[i];
117 }
118
119 if (v[i] != -1)
120 if (L > maxim2)
121 {
122 maxim2 = L;
123 numar2 = suma;
124 zi = v[i];
125 }
126 else
127 if (L == maxim2)
128 {
129 if (suma > numar2)
130 {
131 numar2 = suma;
132 zi = v[i];
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 264
133 }
134 else
135 {
136 if (suma == numar2 && v[i] > zi)
137 zi = v[i];
138 }
139 }
140 }
141
142 fout<<maxim2<<" "<<zi+1;
143 return 0;
144 }
ONI 2016
Cerinţe
Date de intrare
Fişierul de intrare cod.in conţine pe prima linie un număr natural P . Pentru toate testele de
intrare, numărul P poate avea doar valoarea 1, 2 sau 3. Pe a doua linie numărul natural N , iar
pe a treia linie, N numere naturale separate prin câte un caracter #.
Date de ieşire
Dacă valoarea lui P este 1, se va rezolva numai punctul 1) din cerinţe. În acest caz, fişierul de
ieşire cod.out va conţine pe prima linie un număr natural nenul reprezentând câte numere din
şir nu s-au folosit la construirea parolelor sau 0 dacă nu există astfel de numere.
Dacă valoarea lui P este 2, se va rezolva numai punctul 2) din cerinţe. În acest caz, fişierul
de ieşire cod.out va conţine pe prima linie un număr natural reprezentând parola construită de
Ionel.
Dacă valoarea lui P este 3, se va rezolva numai punctul 3) din cerinţe. În acest caz, fişierul
de ieşire cod.out va conţine pe prima linie un număr natural reprezentând parola construită de
Georgel.
a 0 $ N & 100000
a 2 & numărul de cifre ale unui număr & 100
a Se garantează că toate parolele pe care copiii le vor obţine sunt nenule
a În fişierul de intrare ultimul număr nu este urmat de caracterul #
a 16% din teste conţin doar numere formate din cel mult 9 cifre
a Pentru rezolvarea corectă a cerinţei 1 se obţin 20 de puncte, pentru rezolvarea corectă a
cerinţei 2 se obţin 40 de puncte iar pentru rezolvarea corectă a cerinţei 3 se obţin 40 de puncte
265
CAPITOLUL 20. ONI 2016 20.1. COD - ONI 2016 266
Exemple
cod.in cod.out Explicaţii
1 1 Doar numărul 23 nu este divizibil cu niciun număr din
6 mulţimea {2, 3, ..., 15}
10#20#12#34#15#23
2 9 Pentru parola lui Ionel trebuie sa verificăm divizibilitatea
5 cu numerele 2, 3, 4, 5, 6, 7, 8, 9.
16#61#12#385#31 Două numere sunt divizibile cu 2 (16 şi 12), un număr este
divizibil cu 3 (12), două numere sunt divizibile cu 4 (16
şi 12), un număr este divizibil cu 5 (385), un număr este
divizibil cu 6 (12), un număr este divizibil 7 (385), un număr
este divizibil cu 8 (16).
Parola este: 2+1+2+1+1+1+1=9
3 6 Pentru parola lui Georgel trebuie sa verificăm divizibilitatea
5 cu numerele 10, 11, 12, 13, 14, 15.
30#1100#11#85#121 Două numere sunt divizibile cu 10 (30 şi 1100), trei numere
sunt divizibile cu 11 (1100, 11 şi 121), si un număr este
divizibil cu 15 (30).
Parola este: 2+3+1=6
??? = ???
Se citesc cifrele pentru un număr şi sunt puse ı̂ntr-un tabel unidimensional.
Numărul memorat astfel este utilizat pentru a verifica dacă sunt ı̂ndeplinite criteriile de diviz-
ibilitate
a cu 2 (ultima cifra divizibilă cu 2),
a cu 3 (suma cifrelor divizibilă cu 3),
a cu 4 (numărul format din cifra zecilor şi unităţilor este divizibil cu 4),
a cu 5 (ultima cifră este 0 sau 5),
a cu 6 (se divide cu 2 şi 3, conform criteriilor precedente),
a cu 7 (pentru mai mult de 6 cifre, ı̂mpărţim de la dreapta la stânga numărul ı̂n grupe de
câte trei cifre, dacă diferenţa dintre suma numerelor exprimate prin grupe de rang par şi suma
grupelor de rang impar se divide cu 7),
a cu 8 (numărul format din ultimele 3 cifre este divizibil cu 8),
a cu 9 (suma cifrelor este divizibilă cu 9),
a cu 10 (se divide cu 2 şi 5, conform criteriilor precedente),
a cu 11 (diferenţa dintre suma cifrelor situate pe poziţii impare şi suma cifrelor situate pe
poziţii pare este divizibilă cu 11),
a cu 12 (se divide cu 3 şi 4, conform criteriilor precedente),
a cu 13 (similar cu 7, pentru mai mult de 6 cifre, ı̂mpărţim de la dreapta la stânga numărul ı̂n
grupe de câte trei cifre, dacă diferenţa dintre suma numerelor exprimate prin grupe de rang par
şi suma grupelor de rang impar se divide cu 13),
a cu 14 (se divide cu 2 şi 7, conform criteriilor precedente) şi
a cu 15 (se divide cu 3 şi 5, conform criteriilor precedente).
Numerele care nu sunt divizibile cu niciun număr din mulţimea {2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15} sunt contorizate ca numere care nu sunt utilizate ı̂n formarea parolelor.
Pentru fiecare copil se numără câte din numere citite fac parte din grupa corespunzătoare
pentru construirea codului(grupa {2, 3, 4, 5, 6, 7, 8, 9} sau grupa {10, 11, 12, 13, 14, 15}) şi prin
ı̂nsumare se obţin numerele pentru cele două parole.
CAPITOLUL 20. ONI 2016 20.1. COD - ONI 2016 267
71 if(v[m]==0)g[10]++;
72
73 //11
74 s1=0, s2=0;
75 for(i=1;i<=m;i++)
76 if(i%2) s1+=v[i]; else s2+=v[i];
77 if(s1>s2) s=s1-s2;else s=s2-s1;
78 if(s%11==0)g[11]++;
79
80 //12
81 if(g[4]&&g[3])g[12]++;
82
83 //13
84 if(s3%13==0)g[13]++;
85
86 //14
87 if(g[2]&&g[7])g[14]++;
88
89 //15
90 if(g[3]&&g[5])g[15]++;
91 return 0;
92 }
93
94 int main()
95 {
96 ifstream fin("cod.in");
97 ofstream fout("cod.out");
98
99 long nrp=0,nrc=0;
100 fin>>P;
101 fin>>N;
102
103 for(i=0;i<=15;i++){gr_i[i]=0; gr_g[i]=0;}
104
105 for(i=1;i<=N;i++)
106 {
107 n=0;
108 while(fin>>c && c!=’#’)
109 {
110 n++;
111 v[n]=c-’0’;
112 if(v[n])nrc++;
113 };
114
115 selectie(v,n,g);
116
117 long numar=0;
118 for(j=2;j<=15;j++) numar+=g[j];
119 if(numar==0) cate++;
120 for(j=2;j<=9;j++) gr_i[j]+=g[j];
121 for(j=10;j<=15;j++) gr_g[j]+=g[j];
122 }
123
124 fin.close();
125
126 long cod_i=0,cod_g=0;
127
128 for(i=2;i<=9;i++)
129 if(gr_i[i]!=0) cod_i+=gr_i[i];
130
131 for(i=10;i<=15;i++)
132 if(gr_g[i]!=0) cod_g+=gr_g[i];
133
134 if(P==1) fout<<cate<<endl;
135 if(P==2) fout<<cod_i<<endl;
136 if(P==3) fout<<cod_g<<endl;
137
138 fout.close();
139 return 0;
140 }
Cerinţe
Realizaţi un program care citeşte un şir de N numere naturale şi rezolvă următoarea cerinţă:
- determină o ı̂mpărţire a acestuia ı̂n secvenţe de permutări. Dacă există mai multe soluţii se
va afişa soluţia minim lexicografică.
Dacă şirul poate fi ı̂mpărţit ı̂n secvenţe de permutări, pentru fiecare număr din şir, ı̂n ordinea
v1 , .., vN , se va afişa numărul permutării din care face parte. Numerotarea permutărilor se va
face consecutiv ı̂ncepând cu numărul 1.
Date de intrare
Fişierul de intrare perm.in conţine pe prima linie numărul natural N , iar pe a doua linie, un
şir format din N numere naturale separate prin câte un spaţiu.
Date de ieşire
Fişierul de ieşire perm.out conţine pe prima linie mesajul N U dacă şirul nu se poate ı̂mpărţi ı̂n
secvenţe de permutări. Dacă ı̂mpărţirea se poate efectua atunci pe prima linie se va scrie numărul
secvenţelor de permutări obţinut, iar pe a doua linie un şir de numere reprezentând ı̂mpărţirea
minim lexicografică determinată. Numerele pe linia a doua vor fi separate prin câte un spaţiu.
Exemple
perm.in perm.out Explicaţii
10 2 1 3 4 1 1 1111233 Prima secvenţă care reprezintă o permutare e formată din
2345 333 primele 4 elemente, a doua din elementul de pe poziţia 5, iar
a treia din ultimele 5 elemente.
41223 NU
??? - ???
CAPITOLUL 20. ONI 2016 20.2. PERM - ONI 2016 270
Pentru detreminarea secvenţelor vom face tot un vector ı̂n care bi reprezintă de câte ori apare
i ı̂n cele n numere.
Avem o observaţie simplă: pentru a putea exista o soluţie trebuie să nu existe două numere
bi şi bi 1 cu proprietatea că bi $ bi 1.
Dacă nu apare a doua oară un element, caut ı̂n stânga o posibilă permutare până când ajung
la elementul care se repetă.
Pentru a verifica că este permutare facem suma elementelor şi o verificăm că este egală cu
suma lui Gauss.
59 d[nr]=poz;
60 poz=1;
61 break;
62 }
63 else
64 if (a[j]==a[i])
65 {
66 printf("NU\n");
67 return 0;
68 }
69 }
70 }
71 }
72 else
73 {
74 s+=a[i];
75 poz++;
76 }
77 }
78
79 nr++;
80 d[nr]=n;
81 printf("%d\n",nr);
82 j=1;
83 k=1;
84 for (i=1;i<=n;i++)
85 if (i<d[j])
86 printf("%d ",k);
87 else
88 if (i == d[j])
89 printf("%d ",k),k++,j++;
90
91 printf("\n");
92 return 0;
93 }
Cerinţe
Scrieţi un program care, cunoscând numărul R de linii şi coloane şi cele K căsuţe semnalizator,
determină:
1) Toate perechile blocante de pe tablă;
2) Numărul de paşi efectuaţi pe fiecare sens ı̂n parte: Nord, Est, Sud şi Vest
Date de intrare
Fişierul robotel.in conţine pe prima linie numărul natural P reprezentând cerinţa din prob-
lemă care trebuie rezolvată, pe a doua linie, separate printr-un spaţiu numărul natural R şi
numărul natural K, iar pe următoarele K linii, două numere naturale şi un caracter, separate prin
câte un spaţiu reprezentând, ı̂n ordine, linia, coloana şi litera unei căsuţe semnalizator.
Date de ieşire
Dacă valoarea lui P este 1, se va rezolva doar cerinţa 1). Fişierul de ieşire robotel.out va
conţine perechile blocante, pentru fiecare pereche de căsuţe afişându-se 4 numere naturale separate
printr-un spaţiu, reprezentând, ı̂n ordine, linia, coloana primei căsuţe semnalizator, respectiv linia
şi coloana celei de-a doua căsuţe semnalizator. Perechile de căsuţe vor fi afişate pe linii ordonat
după regula: o pereche L1 C1 L2 C2 va fi afişată ı̂naintea perechii L3 C3 L4 C4 dacă L1¡L3 sau
L1=L3 şi C1¡C3, adică se va afişa mai ı̂ntâi perechea cu prima căsuţă având linia mai mică decât
a primei căsuţe din cealaltă pereche sau la linii egale, va fi afişată perechea cu coloana mai mică.
Dacă nu există astfel de perechi de căsuţe, ı̂n fişierul de ieşire se va afişa valoarea 0.
Dacă valoarea lui P este 2, se va rezolva doar cerinţa 2). Fişierul de ieşire robotel.out va
conţine 4 numere naturale separate printr-un spaţiu, reprezentând, ı̂n ordine, numărul de paşi
parcurşi de roboţel ı̂n sensurile Nord, Est, Sud, şi Vest.
Exemple
??? - ???
ONI 2015
Cerinţe
Scrieţi un program care citeşte lungimile catetelor echerului, numărul de rânduri, respectiv
numărul de coloane ale foii de hârtie şi determină:
1. numărul minim de mutări K, prin care poate muta echerul din colţul din stânga sus al foii
de matematică, astfel ı̂ncât echerul să atingă colţul din dreapta jos al foii;
2. cele K mutări efectuate pentru a deplasa echerul din colţul din stânga sus al foii, până când
un colţ al echerului atinge colţul din dreapta jos al foii; dacă există mai multe soluţii, se va afişa
soluţia minimă ı̂n sens lexicografic.
Un şir de mutări X X1 , X2 , ..., XK este mai mic ı̂n sens lexicografic decât alt şir de mutări
Y Y1 , Y2 , ..., YK dacă ¿P (1 & P & K) a.ı̂. XI YI , ¾I " r1, 2, ..., P 1x şi XP $ YP . De
exemplu şirul de mutări 1 2 3 1 este mai mic ı̂n sens lexicografic decât şirul de mutări 1 2 4 1.
Date de intrare
Fişierul de intrare echer.in conţine pe prima linie una dintre valorile 1 sau 2, reprezentând
cerinţa 1 dacă se cere determinarea numărului minim de mutări prin care poate muta echerul din
colţul din stânga sus al foii de matematică astfel ı̂ncât să atingă colţul din dreapta jos al foii,
respectiv cerinţa 2, dacă se cere determinarea mutărilor efectuate pentru a deplasa echerul din
colţul din stânga sus al foii până când un colţ al echerului atinge colţul din dreapta jos al foii.
A doua linie a fişierului conţine patru numere naturale, separate prin câte un spaţiu,
reprezentând valorile L1, L2, M şi N , ı̂n această ordine.
Date de ieşire
276
CAPITOLUL 21. ONI 2015 21.1. ECHER - ONI 2015 277
Exemple
Figura 21.3:
echer
22389 12312314 Mutările sunt cele ilustrate ı̂n imaginea de mai
sus.
Tabelul 21.1: echer
71 k-=4;
72 }
73
74 if(k) g<<" 4\n";
75 }
76 else
77 if(y-x>1)
78 {
79 while(k>=4)
80 {
81 g<<" 2 7 5 1";
82 k-=4;
83 }
84
85 if(k)g<<" 2\n";
86 }
87 }
88
89 return 0;
90 }
53 x=m-n;
54 for(i=1;i<n;i++)
55 g<<" 2 3 1";
56 for(i=1;i<=x;i++)
57 if(i%2==0)
58 g<<" 7 5 1";
59 else
60 g<<" 2";
61 }
62
63 g<<’\n’;
64 }
65
66 return 0;
67 }
58 }
72 else
73 if(y-x>1)
74 {
75 while(k>=4)
76 {
77 g<<" 2 7 5 1";
78 k-=4;
79 }
80
81 if(k)
82 g<<" 2\n";
83 }
84 }
85
86 return 0;
87 }
57 {
58 g<<’\n’;
59 gata=1;
60 }
61 else
62 if(m/l1==n/l2+1)
63 {
64 g<<"4\n";
65 nr_mutari--;
66 gata=1;
67 }
68 else
69 if((m/l1+1)==n/l2)
70 {
71 g<<"2\n";
72 nr_mutari;
73 gata=1;
74 }
75 if(!gata)
76 {
77 if(m/l1>n/l2+1)
78 {
79 while(nr_mutari>=4)
80 {
81 g<<"4 6 3 1 ";
82 nr_mutari=nr_mutari-4;
83 }
84
85 if(nr_mutari>0)
86 g<<"4\n";}
87 else
88 if(n/l2>m/l1+1)
89 {
90 while(nr_mutari>=4)
91 {
92 g<<"2 7 5 1 ";
93 nr_mutari=nr_mutari-4;
94 }
95
96 if(nr_mutari>0)
97 g<<"2\n";
98 }
99 }
100
101 f.close();
102 g.close();
103 return 0;
104 }
25 if (caz==1)
26 {
27 if (n/l1==m/l2)
28 nr=3*(n/l1-1)+1;
29 else
30 {
31 nr=3*(minn-1)+1+(dif/2)*4;
32 if (dif%2==1)
33 nr++;
34 }
35
36 g<<nr<<endl;
37 }
38 else
39 {
40 g<<"1";
41 if (n/l1==m/l2)
42 for(i=1;i<=n/l1-1;i++)
43 g<<" 2 3 1";
44 else
45 {
46 for(i=1;i<minn;i++)
47 g<<" 2 3 1";
48
49 if (n/l1>m/l2)
50 for(i=1;i<=dif;i++)
51 if (i%2==0)
52 g<<" 6 3 1";
53 else
54 g<<" 4";
55 else
56 for(i=1;i<=dif;i++)
57 if (i%2==0)
58 g<<" 7 5 1";
59 else
60 g<<" 2";
61 }
62 }
63
64 f.close();
65 g.close();
66 return 0;
67 }
Cerinţe
CAPITOLUL 21. ONI 2015 21.2. LIGHTBOT - ONI 2015 285
Exemple
lightbot.in lightbot.out Explicaţii
1 3 Sunt trei participanţi, care au finalizat nivelele: 1 2 4 (primul),
10 2 4 (al doilea) şi 6 7 9 (al treilea).
12424679
2 4 Nivele 2 şi 4 au fost finalizate de câte doi participanţi, cel mai
10 greu fiind nivelul 4.
12424679
3 338 Primul participant a sărit nivelul 3, al doilea nivelul 3, iar al
10 treilea nivelul 8.
12424679
Timp maxim de executare/test: 0.4 secunde
Memorie: total 4 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 5 KB
11 int n;
12 int jucatori_nivel[NMAX];
13
14 void numara_jucatori()
15 {
16 int x, y, nr = 1;
17 bool nivel_sarit = false;
18 f >> x;
19
20 while(f >> y)
21 {
22 if (y == x + 2)
23 {
24 if (nivel_sarit == true)
25 {
26 nr++;
27 nivel_sarit = false;
28 }
29 else
30 nivel_sarit = true;
31 }
32 else
33 if (y != x + 1)
34 {
35 nr++;
36 nivel_sarit = false;
37 }
38
39 x = y;
40 }
41
42 g << nr << ’\n’;
43 }
44
45 void nivel_accesat()
46 {
47 int maxim = -1, nivel = -1;
48 int x;
49
50 while(f >> x)
51 {
52 jucatori_nivel[x]++;
53 if (jucatori_nivel[x] > maxim)
54 {
55 maxim = jucatori_nivel[x];
56 nivel = x;
57 }
58 else
59 if (jucatori_nivel[x] == maxim)
60 {
61 nivel = max(nivel, x);
62 }
63 }
64
65 g << nivel << ’\n’;
66 }
67
68 void nivele_sarite()
69 {
70 int x, y, z, nr = 1;
71 bool nivel_sarit = false;
72 f >> x;
73
74 while(f >> y)
75 {
76 if (y == x + 2)
77 {
78 if (nivel_sarit == true)
79 {
80 nr++;
81 nivel_sarit = false;
82 }
83 else
84 {
85 nivel_sarit = true;
86 g << y - 1 << ’ ’;
CAPITOLUL 21. ONI 2015 21.2. LIGHTBOT - ONI 2015 288
87 }
88 }
89 else
90 if (y != x + 1)
91 {
92 nivel_sarit = false;
93 }
94
95 x = y;
96 }
97 }
98
99 int main()
100 {
101 int tip;
102 f >> tip >> n;
103
104 if (tip == 1)
105 numara_jucatori();
106 else
107 if (tip == 2)
108 nivel_accesat();
109 else
110 nivele_sarite();
111
112 return 0;
113 }
46 }
47
48 f.close();
49 g.close();
50 return 0;
51 }
7
8 int t,n,a,b,i,poz,p,cnt[200010];
9
10 void solve1(),solve2(),solve3();
11
12 int main()
13 {
14 f>>t>>n>>a;
15 cnt[a]++;
16 if(t==1) solve1();
17 if(t==2) solve2();
18 if(t==3) solve3();
19 return 0;
20 }
21
22 void solve1()
23 {
24 for(;f>>b;)
25 {
26 cnt[b]++;
27 if(b==a+1){a++;continue;}
28 if(poz==0)
29 {
30 p++;
31 poz=1;
32 a=b;
33 continue;
34 }
35 poz=0;
36 a=b;
37 }
38 g<<p;
39 }
40
41 void solve2()
42 {
43 for(;f>>b;)
44 cnt[b]++;
45 a=n;
46 for(i=n-1;i>=1;i--)
47 if(cnt[i]>cnt[a])
48 a=i;
49 g<<a;
50 }
51
52 void solve3()
53 {
54 for(;f>>b;)
55 {
56 cnt[b]++;
57 if(b==a+1){a++;continue;}
58 if(poz==0)
59 {
60 g<<a+1<<’ ’;
61 poz=1;
62 a=b;
63 continue;
64 }
65 poz=0;
66 a=b;
67 }
68 }
11 void calcul()
12 {
13 int a,b,i,maxx;
14
15 f>>caz;
16 f>>n;
17 f>>a;
18
19 maxx=0;
20 nr=1;
21 k=0;t=0;
22 i=1;
23 x[a]=1;
24 maxx=1;
25 val=a;
26 while (f>>b)
27 {
28 x[b]++;
29 if (maxx<x[b])
30 {
31 maxx=x[b];
32 val=b;
33 }
34 else
35 if (maxx==x[b])
36 if (val<b)
37 val=b;
38
39 if (b!=a+1)
40 {
41 t++;
42 if (t!=1)
43 {
44 t=0;
45 nr++;
46 }
47 else
48 {
49 k++;
50 y[k]=a+1;
51 }
52 }
53
54 a=b;
55 }
56
57 }
58 int main()
59 {
60 int i;
61
62 calcul();
63
64 if (caz==1)
65 g<<nr<<endl;
66 else
67 if (caz==2)
68 g<<val<<endl;
69 else
70 for (i=1;i<=k;i++)
71 g<<y[i]<<" ";
72
73 f.close();
74 g.close();
75 return 0;
76 }
Cerinţe
Scrieţi un program care să citească numerele naturale N , M , T , R, C apoi cele T perechi
de coordonate X, Y şi Z, U precizate ı̂n acte (corespunzătoare suprafeţelor dreptunghiulare
revendicate) şi care să determine:
1. numărul fermierilor care revendică pătratul elementar identificat prin coordonatele R, C ;
2. numărul maxim de fermieri care revendică acelaşi pătrat elementar;
3. numărul maxim de pătrate elementare ce formează o suprafaţă pătratică nerevendicată de
niciun fermier.
Date de intrare
Fişierul teren.in conţine pe prima linie un număr natural P care poate avea doar valoarea 1,
valoarea 2 sau valoarea 3. Pe a doua linie a fişierului sunt scrise cinci numere naturale N , M , T ,
R, C, separate prin câte un spaţiu, cu semnificaţia din enunţ. Pe fiecare din următoarele T linii
ale fişierului sunt câte patru numere naturale nenule XK, Y K, ZK, U K, separate prin câte un
spaţiu, reprezentând perechile de coordonate XK , YK şi ZK , UK corespunzătoare terenurilor
revendicate de cei T fermieri (1 & K & T ).
Date de ieşire
Fişierul de ieşire teren.out va conţine pe prima linie un număr natural reprezentând numărul
fermierilor care revendică pătratul elementar identificat prin coordonatele R, C dacă cerinţa a
fost 1, un număr natural reprezentând numărul maxim de fermieri ce revendică acelaşi pătrat
elementar dacă cerinţa a fost 2, respectiv un număr natural reprezentând numărul maxim de
pătrate elementare ce formează o suprafaţă pătratică nerevendicată de niciun fermier dacă cerinţa
a fost 3.
a 3 & N, M & 180; 3 & T & 100; 1 & R & N ; 1 & C & M ;
a 1 & XK & ZK & N şi 1 & YK & UK & M pentru K 1, 2, 3, ..., T ;
a Pentru rezolvare corectă a cerinţei 1 se acordă 20% din punctaj, pentru rezolvarea corectă a
cerinţei 2 se acordă 20% din punctaj, iar pentru rezolvarea corectă a cerinţei 3 se acordă 60% din
punctaj.
Exemple
CAPITOLUL 21. ONI 2015 21.3. TEREN - ONI 2015 293
O soluţie se poate obţine utilizând un tablou bidimensional A cu N linii şi M coloane pentru
memorarea terenurilor revendicate de fermieri. Fiecare element al tabloului reprezintă câte un
pătrat elementar din teren.
Iniţial toate elementele matricei au valoarea 0. Un element din tablou cu valoarea 0 semnifică
faptul că pătratul elementar din teren, corespunzător elementului, nu este revendicat de niciun
fermier.
Se citesc succesiv coordonatele suprafeţelor revendicate de fermieri. Pentru fiecare astfel de
suprafaţă cu coordonatele X, Y , Z, U se incrementează elementele submatricei corespunzătoare
suprafeţei curente (primul element este cel din linia X şi coloana Y , iar ultimul element este situat
ı̂n linia Z şi coloana U ).
1. Valoarea elementului ARC reprezintă numărul de fermieri care revendică pătratul ele-
mentar corespunzător.
2. Valoarea maximă din matrice reprezintă numărul maxim de fermieri care revendică acelaşi
pătrat elementar (3 este valoarea maximă pentru exemplul dat) .
3. Pentru a determina o suprafaţă pătratică nerevendicată de niciun fermier, parcurgem ma-
tricea şi determinăm pentru fiecare element cu Aij 0 submatricea pătratică maximală care
are primul element ı̂n Aij . Submatricea se poate obţine bordând spre dreapta matricea curentă
cu câte o linie şi o coloană matricea curentă cât timp elementele adăugate au valoarea 0, ca ı̂n
2 2
desenul de mai jos. (Complexitate O N M ).
71 return 0;
72 }
71
72 g<<t*t<<’\n’;}
73 f.close();g.close();
74 return 0;
75 }
10
11 short int Teren[DIMMAX][DIMMAX], N, M, T, R, C,P;
12 short int X, Y, Z, U;
13 short int rasp2, rasp3, t, i, j;
14 short int TerenLiber[DIMMAX][DIMMAX];
15
16 int main()
17 {
18 fin >> P>> N >> M >> T >> R >> C; //citesc datele
19 for (t = 1; t <= T; ++t)
20 {
21 fin >> X >> Y >> Z >> U; //citesc si
22 for (i = X; i <= Z; ++i) //prelucrez inscrisul t
23 for (j = Y; j <= U; ++j)
24 {
25 Teren[i][j]++;
26 if (Teren[i][j]>rasp2) //determin si zona maxima
27 rasp2 = Teren[i][j]; //pe parcurs
28 }
29 }
30
31 if(P==1)fout << Teren[R][C] << ’\n’; //afisez raspuns la a)
32 else
33 if(P==2)fout << rasp2 << ’\n’; //afisez raspuns la b)
34 else {
35 for (i = 1; i <= N; ++i)
36 for (j = 1; j <= M; ++j)
37 if (Teren[i][j])
38 Teren[i][j] = -1; //marchez zone ocupate
39
40 //ideea: construiesc o matrice care retine coltul din dreapta jos
41 //a patratului liber posibil maxim in acest loc
42 //pot utiliza doar 2 linii, dar pentru cei mici si dimensiunile
43 //date, merge si cu construirea intregii matrici
44
45 for (j = 1; j <= M; ++j)
46 if (!Teren[1][j])
47 TerenLiber[1][j] = 1; //in linia 1 nu poate fi decat
48 // patrate de latura 1
49
50 for (i = 2; i <= N; ++i) //in celelalte linii se extind patratele
51 {
52 if (!Teren[i][1]) //in coloana 1 doar zona de 1x1
53 TerenLiber[i][1] = 1;
54 for (j = 2; j <= M; ++j) //pentru celelalte coloane
55 {
56 if (!Teren[i][j]) //eventual se extinde
57 TerenLiber[i][j] = 1 +
58 min(min(TerenLiber[i][j-1], TerenLiber[i-1][j]),
59 TerenLiber[i-1][j-1]);
60 if (TerenLiber[i][j]>rasp3) //daca s-a gasit un patrat mai mare
61 rasp3 = TerenLiber[i][j]; //se retine
62 }
63 }
64 fout << rasp3 * rasp3 << ’\n’;}
65 return 0;
66 }
16 {
17 f>>x>>y>>z>>u;
18 k=0;
19 for (i=x;i<=z;i++)
20 for (j=y;j<=u;j++)
21 {
22 a[i][j]++;
23 if (maxx<a[i][j])
24 maxx=a[i][j];
25 }
26 }
27
28 if (caz==1)
29 g<<a[r][c]<<endl;
30 else
31 if (caz==2)
32 g<<maxx<<endl;
33 else
34 {
35 maxx=0;
36 for (j=1;j<=m;j++)
37 if (a[1][j]==0)
38 b[1][j]=1;
39
40 for (i=1;i<=n;i++)
41 if (a[i][1]==0)
42 b[i][j]=1;
43
44 for(i=2;i<=n;i++)
45 {
46 if (a[i][1]==0)
47 b[i][1]=1;
48
49 for(j=2;j<=m;j++)
50 if (a[i][j]==0)
51 {
52 minn=b[i][j-1];
53 if (minn>b[i-1][j])
54 minn=b[i-1][j];
55
56 if (minn>b[i-1][j-1])
57 minn=b[i-1][j-1];
58
59 b[i][j]=1+minn;
60 if (maxx<b[i][j])
61 maxx=b[i][j];
62 }
63 }
64
65 g<<maxx*maxx;
66 }
67
68 f.close();
69 g.close();
70 return 0;
71 }
ONI 2014
Cerinţe
Scrieţi un program care evaluează astfel de expresii.
Date de intrare
Fişierul de intrare betisoare.in conţine pe prima linie o valoare naturală n, care indică
numărul de expresii care trebuie evaluate. Fiecare dintre următoarele n linii conţine un şir de
maximum 1000000 caractere care reprezintă expresia ce trebuie evaluată.
Date de ieşire
Fişierul de ieşire betisoare.out va conţine pe fiecare linie i dintre primele n linii câte un
număr ı̂ntreg care reprezintă rezultatul evaluării expresiei de pe linia i 1 din fişierul de intrare.
Restricţii şi precizări
a 1 & n & 10
a O expresie poate avea cel puţin 1 caracter şi cel mult 1000000 de caractere.
a Valorile calculate pe parcurs şi valoarea finală au maximum 18 cifre.
a Dintre teste, 26% conţin numai operaţii de adunare, 22% numai operaţii de ı̂nmulţire, iar
restul de 52% conţin ambele operaţii.
Exemple
betisoare.in betisoare.out Explicaţii
1 11
I+I*III+IIIIIII
2 42
IIII
I+I
3 9 1 17
I+I+I+I+I+I+I+I+I
I*I*I*I*I*I*I
IIII*IIII+I
299
CAPITOLUL 22. ONI 2014 22.1. BETISOARE - ONI 2014 300
11 ifstream fin("betisoare.in");
12 ofstream fout("betisoare.out");
13
14 int n, i;
15 long long suma, factor, valoare, termen;
16 char c, semn_urmator;
17
18 int main()
19 {
20 fin >> n;
21 fin.get(); //trec de ENTER
22 for (i = 1; i <= n; i++)
23 {
24 //calculeaza cea de-a i-a expresie
25 suma = 0; //initializez suma
26 termen = 1; //initializez termen
27 factor = 0; //iitializez factor
28 fin.get(c);
29 while (c != ’+’ && c != ’*’ && c != ’\n’)//primul termen/factor
30 {
31 factor++;
32 fin.get(c);
33 }
34 semn_urmator = c; //retin semnul urmator
35 while (c != ’\n’) //cat timp mai am termeni sau factori
36 {
37 if (semn_urmator == ’+’ || c == ’\n’)
38 { //adun termenul
39 termen *= factor;
40 suma += termen;
41 termen = 1;
42 }
43 else
44 termen *= factor; //inca e produs
45 factor = 0; //reinitializez factorul
46 fin.get(c);
47 while (c != ’+’ && c != ’*’ && c != ’\n’) //alt factor
48 {
49 factor++;
50 fin.get(c); //urmatorul semn
51 }
52 semn_urmator = c; //il retin
53 }
54 if (suma == 0)
55 suma = termen * factor;
56 else
57 suma += termen * factor;
58 fout << suma << ’\n’; //afisez rezultat
59 }
60 fout.close();
61 return 0;
62 }
21 S=S+numar[i-1];
22 }
23 }
24
25 void citire()
26 {
27 int i,N;
28 char c;
29 long long val_nr;
30
31 fin>>N;
32 for(i=1;i<=N+1;i++)
33 { S=0;nr_elem=0;
34 c=fin.get();
35 val_nr=1;
36 while(c!=’\n’)
37 { c=fin.get();
38 while(c==’I’)
39 {
40 val_nr++;
41 c=fin.get();
42 }
43 numar[nr_elem++] = val_nr;
44 val_nr = 0;
45 if(c==’+’)
46 numar[nr_elem++] = 0;
47 else
48 if(c==’*’)
49 numar[nr_elem++] = -2;
50 }
51 if(i>1)
52 {
53 numar[nr_elem++] = val_nr;
54 evaluare_linie();
55 fout << S << "\n";
56 }
57 }
58 fin.close();
59 fout.close();
60 }
61
62 int main()
63 {
64 citire();
65 return 0;
66 }
27 else nr++;
28 }
29 fo<<rez<<"\n";
30 }
31 return 0;
32 }
33 g<<rez<<’\n’;
34 }
35 return 0;
36 }
23 {
24 t=0;
25 x=0;
26 do
27 {
28 k=0;
29 t++;
30 while (f.get(ch) && ch!=’\n’ && ch!=’+’ && ch!=’*’)
31 k++;
32
33 if (ch==’+’ || ch==’\n’)
34 {
35 stiva[t]=k;
36 k=0;
37 }
38 else
39 {
40 stiva[t]=k;k=0;
41
42 do
43 {
44 while(f.get(ch) && ch!=’\n’ && ch!=’+’ && ch!=’*’)
45 k++;
46
47 x=stiva[t]*k;
48 stiva[t]=x;
49 k=0;
50 }
51 while(ch==’*’ && ch!=’\n’);
52
53 k=x;
54 }
55
56 } while (ch!=’\n’);
57
58 if (op==’+’)
59 stiva[t++]=k;
60
61 x=stiva[t];
62 t--;
63
64 for (j=t;j>=0;j--)
65 {
66 x=x+stiva[t];
67 t--;
68 }
69
70 g<<x<<’\n’;
71 }
72
73 return 0;
74 }
20 }
21
22 long long e()
23 {
24 long long r=t();
25 while(*p==’+’) p++,r+=t();
26 return r;
27 }
28
29 long long t()
30 {
31 long long r=f();
32 while(*p==’*’) p++,r*=f();
33 return r;
34 }
35
36 long long f()
37 {
38 long long r=0;
39 while(*p==’I’) r++,p++;
40 return r;
41 }
- a delimitat ı̂n grădină, de-a lungul acesteia, N parcele alăturate, numerotate de la stânga la
dreapta cu valori ı̂n ordine, de la 1 la N . Dintre acestea, a dat spre pază fraţilor şi verişorilor săi
M parcele, iar restul de N M parcele oştenilor din ı̂mpărăţie. Cele N M parcele date oştenilor
sunt identice şi au fiecare lăţimea L.
- a măsurat distanţa D la care se află pomul cu merele de aur faţă de marginea din stânga a
grădinii, pentru a ı̂ntări chiar el paza parcelei ı̂n care e situat acesta.
Cerinţe
a) Cunoscând lăţimea fiecărei parcele, determinaţi cel mai mare număr de parcele alăturate,
de lăţime L fiecare, date spre pază oştenilor;
b) Determinaţi numărul de ordine al parcelei ı̂n care se află pomul cu merele de aur.
Date de intrare
- pe prima linie trei numere naturale N , M şi L, ı̂n această ordine, despărţite prin câte un
spaţiu, având semnificaţia din enunţ;
- pe următoarele M linii, câte două numere naturale Pi şi Li , despărţite prin câte un spaţiu,
reprezentând numărul de ordine, respectiv lăţimea fiecărei parcele dintre cele M , dată spre pază
fraţilor şi verişorilor;
- pe următoarea linie un număr natural D, care reprezintă distanţa la care se află pomul cu
merele de aur faţă de marginea din stânga a grădinii.
Date de ieşire
Fişierul de ieşire praslea.out va conţine pe prima linie un singur număr natural determinat
conform cerinţei a), iar pe cea de-a doua linie a fişierului un singur număr natural determinat
conform cerinţei b).
Exemple
praslea.in praslea.out Explicaţii
832 3 Sunt 8 parcele: 3 dintre ele au fost ı̂mpărţite fraţilor şi
21 5 verişorilor. Parcelele rămase pentru oşteni au toate lăţimea 2.
54 Dintre cele 3 parcele: parcela 2 are lăţimea 1, parcela 5 are
11 lăţimea 4 şi parcela 1 are lăţimea 1. Pomul cu mere de aur se
7 află la distanţa 7 faţă de marginea din stânga a grădinii.
Sunt 3 parcele alăturate care au lăţimea egală cu 2 (parcelele
numerotate cu 6, 7 şi 8).
Pomul se află ı̂n parcela cu numărul de ordine 5.
a pentru fiecare parcelă din cele M , memorăm numărul de ordine şi dimensiunea acesteia;
a sortăm cele M parcele ı̂n funcţie de numărul lor de ordine;
a determinăm numărul maxim de parcele de lăţime L, printr-o parcurgere liniară, şi contorizăm
la fiecare pas parcelele de lăţime L, situate ı̂ntre două parcele vecine (ı̂n urma sortării) din cele
M , citite din fişierul de intrare;
a determinăm numărul de ordine al parcelei ı̂n care se află pomul cu merele de aur printr-o
parcurgere a celor M parcele şi actualizarea (prin diferenţă) la fiecare pas a distanţei D la care se
află pomul, având ı̂n vedere trei cazuri posibile:
a pomul este situat ı̂naintea parcelei curente;
a pomul este situat ı̂n interiorul parcelei curente;
a pomul este situat la dreapta parcelei curente.
59 {
60 Pom=C[i].indice;
61 ok=2;
62 }
63 else
64 P=P-C[i].latime; // pomul e situat la dreapta parcelei curente
65 }
66
67 indice_precedent=C[i].indice;
68 i++;
69 }
70
71 fout<<max_parcele<<’\n’;
72
73 if(ok==0) //pomul e situat la drapta ultimei parcele din cele M citite
74 Pom=C[M-1].indice+ceil((double)P/L);
75
76 fout<<Pom<<’\n’;
77 return 0;
78 }
53
54 fin>>N>>M>>L; //citirea datelor
55 for(i=0;i<M;++i)
56 fin>>indice[i]>>latime[i];
57
58 M++;
59 indice[M]=N+1;
60 latime[M]=0;
61 fin>>P;
62 fin.close();
63
64 //sortarea parcelelor crescator in functie de indice
65 quick(0,M-1);
66
67 max_parcele=N-indice[M-1];
68 i=0;
69 while(i<M)
70 {
71 alaturate=indice[i]-indice_precedent-1;
72 if (max_parcele<alaturate)
73 max_parcele=alaturate; //rezolvare cerinta a)
74
75 if(!ok && P<=(alaturate*L))
76 {
77 Pom=indice_precedent+ceil((double)P/L);
78 ok=1; //pomul e situat inaintea parcelei curente
79 }
80 else
81 {
82 if (alaturate>0) P=P-(alaturate)*L;
83 if(!ok && P<=latime[i]) // pomul e situat in parcela curenta
84 {
85 Pom=indice[i];
86 ok=2;
87 }
88 else
89 // pomul e situat mai la dreapta parcelei curente
90 P=P-latime[i];
91 }
92
93 indice_precedent=indice[i];
94 i++;
95 }
96
97 fout<<max_parcele<<’\n’;
98 if(ok==0)
99 //pomul e situat dupa ultima parcela din cele M citite
100 Pom=indice[M-1]+ceil((double)P/L);
101
102 fout<<Pom<<’\n’;
103
104 return 0;
105 }
20 if(C_indice[i]>C_indice[j])
21 {
22 aux=C_indice[i]; C_indice[i]=C_indice[j]; C_indice[j]=aux;
23 aux=C_latime[i]; C_latime[i]=C_latime[j]; C_latime[j]=aux;
24 }
25 }
26
27 int main()
28 {
29 int i,ok=0;
30 fin>>n>>k>>l;
31
32 float x;
33
34 //citirea datelor
35 for(i=0;i<k;++i)
36 fin>>C_indice[i]>>C_latime[i];
37
38 k++;
39 C_indice[k]=n+1;
40 C_latime[k]=0;
41
42 //sortarea celulelor in functie de indice
43 fin>>P;
44 sortare();
45
46 //rezolvare cerinta a)
47 max_parcele=n-C_indice[k-1];
48 i=0;
49 while(i<k)
50 {
51 alaturate=C_indice[i]-indice_precedent-1;
52 if (max_parcele<alaturate)
53 max_parcele=alaturate;//rezolvare cerinta a)
54
55 if(!ok && P<=(alaturate*l))
56 {
57 Pom=indice_precedent+ceil((double)P/l);
58 ok=1;
59 }
60 else
61 {
62 if (alaturate>0)
63 P=P-(alaturate)*l;
64
65 if(!ok && P<=C_latime[i])
66 {
67 Pom=C_indice[i];
68 ok=2;
69 }
70 else
71 P=P-C_latime[i];
72 }
73
74 indice_precedent=C_indice[i];
75 i++;
76 }
77
78 fout<<max_parcele<<’\n’;
79
80 if(ok==0)
81 Pom=C_indice[k-1]+ceil((double)P/l);
82
83 fout<<Pom<<’\n’;
84
85 return 0;
86 }
6
7 int N,M;
8 int sola,solb;
9 long long L,D,S;
10 long long P[500005];
11
12 int main()
13 {
14 int i,x,nr=0;
15 long long y;
16
17 freopen("praslea.in","r",stdin);
18 freopen("praslea.out","w",stdout);
19
20 scanf("%d%d%d",&N,&M,&L);
21 for(; M; --M)
22 {
23 scanf("%d%lld",&x,&y);
24 P[x]=y;
25 }
26 scanf("%lld",&D);
27
28 for(i=1; i<=N; i++)
29 {
30 if(!P[i]) S+=L;
31 else S+=P[i];
32 if(!solb && D<=S) solb=i;
33 if(!P[i]) nr++;
34 else
35 {
36 sola=max(sola,nr);
37 nr=0;
38 }
39 }
40
41 sola=max(sola,nr);
42 printf("%d\n%d\n",sola,solb);
43 return 0;
44 }
22 fi>>d;
23 y=z=0;
24 for (i=1;i<=n+1;i++)
25 if (p[i]==L)
26 y++;
27 else
28 {
29 if (y>z) z=y;
30 y=0;
31 }
32
33 fo<<z<<"\n";
34
35 z=0;
36 i=1;
37 while (z<=d-p[i])
38 z+=p[i++];
39 if (z>d)
40 i--;
41
42 fo<<i<<"\n";
43
44 return 0;
45 }
49 }
50
51 nextt=x[i+1].nr_parc-x[i].nr_parc-1;
52 nr_parcele=max(nr_parcele,nextt);
53
54 k=x[i].nr_parc-x[i-1].nr_parc-1;
55 if(gasit==0)
56 if(dist<=0)
57 {
58 dist+=k*l;
59 locatie=x[i-1].nr_parc+(dist/l)+1;
60 dist-=k*l;
61 gasit=1;
62 }
63 else
64 {
65 dist-=x[i].lat_parc;
66 if(dist<0)
67 {
68 locatie=x[i].nr_parc;
69 gasit=1;
70 }
71 else
72 if(dist==0)
73 locatie=x[i].nr_parc+1;
74 else
75 dist-=nextt*l;
76 }
77 }
78
79 maxim=max(maxim,coun);
80 if(dist==0)
81 locatie--;
82
83 g<<max(maxim,nr_parcele)<<"\n"<<locatie;
84
85 return 0;
86 }
35 }
36 else
37 {
38 if (max1<t)
39 max1=t;
40 t=0;
41 }
42
43 if (r==0)
44 {
45 if (d1+v[i]>=d)
46 r=i;
47 else
48 d1=d1+v[i];
49 }
50 }
51
52 if(n-max>max1)
53 max1=n-max;
54
55 g<<max1<<endl;
56
57 if (r==0)
58 {
59 r=max+(d-d1)/l+1;
60 if((d-d1)%l==0)
61 r=r-1;
62 }
63
64 g<<r;
65 return 0;
66 }
41 t=0;
42 }
43
44 if (r==0)
45 {
46 if (d1+v[i]>=d)
47 r=i;
48 else
49 d1=d1+v[i];
50 }
51 }
52
53 if(n-max>max1)
54 max1=n-max;
55
56 g<<max1<<endl;
57
58 if (r==0)
59 {
60 r=max+(d-d1)/l+1;
61 if((d-d1)%l==0)
62 r=r-1;
63 }
64
65 g<<r;
66 return 0;
67 }
46
47 aparitii[k]=nr--; // salvez nr de dubluri gasite
48 k++;
49 }
50
51 // sortez ca pe ultima pozitie sa fie ceea mai mare valoare
52 sort(aparitii,aparitii+i);
53 g<<aparitii[k-1]<<’\n’;
54 g<<v;
55
56 return 0;
57 }
Date de intrare
Fişierul de intrare tinta.in conţine pe prima linie numărul natural n, indicând numărul de
linii şi de coloane ale ţintei.
Date de ieşire
Fişierul de ieşire tinta.out va conţine pe primele n linii câte n numere naturale, separate
prin câte un spaţiu, reprezentând numerele de pe cele n linii ale ţintei. Pe linia n 1 se va afişa
un singur număr p reprezentând numărul de punctaje distincte. Pe linia n 2 se vor afişa p
numere naturale separate prin câte un spaţiu şi ordonate strict crescător, reprezentând punctajele
distincte.
Exemple
CAPITOLUL 22. ONI 2014 22.3. TINTA - ONI 2014 322
Daca (i+j)<=n+1
atunci
daca (i+j)%2=0
atunci k=(i+j-1)*(i+j-2)/2+j;
altfel k=(i+j-1)*(i+j-2)/2+i;
altfel
u=n+1-i;
v=n+1-j;
daca (i+j)%2==0
atunci k=n*n+1-(u+v-1)*(u+v-2)/2-v;
altfel k=n*n+1-(u+v-1)*(u+v-2)/2-u;
a Observăm că punctajele identice din interior se obţin pe semidiagonalele paralele cu diagonala
secundară.
Observăm că pe o semidiagonală toate elementele au aceeaşi valoare ı̂n cazul ı̂n care se ţinteşte
din poziţiile respective, deci vom avea 2 n 5 punctaje distincte.
a Pentru a afişa punctajele distincte e suficient să calculăm punctajele de pe linia a doua a
matricei până la diagonala secundară, inclusiv pentru elementul aflat pe diagonala secundară şi
CAPITOLUL 22. ONI 2014 22.3. TINTA - ONI 2014 323
punctajele de pe linia n 1 a ţintei, de sub diagonala secunadară. De aceea, vom memora primele
3 linii şi ultimile 3 coloane ı̂n 2 tablouri bidimensionale.
bij ai1j 1ai1j ai1j 1ai1j 1ai1j ai1j 1aij 1aij 1
46 printf("%d ",s-a[2][j]);}
47
48 for(i=3;i<n;i++)
49 {
50 s=0;
51 for(j=1;j<=3;j++)
52 for(k=i-1;k<=i+1;k++)
53 s+=b[k][j];
54
55 printf("%d ",s-b[i][2]);
56 }
57
58 return 0;
59 }
59 }
60 }
61 else //daca este par
62 {
63 do
64 {
65 if (j < n)
66 {
67 while (j > 1)
68 {
69 i++; j--; M[i][j] = x++;
70 }
71 i++; M[i][j] = x++;
72 while (i > 1)
73 {
74 i--; j++; M[i][j] = x++;
75 }
76 if (j < n)
77 {
78 j++; M[i][j] = x++;
79 }
80 }
81 } while (j != n);
82
83 //acum sub diagonala secundara
84 while (i != n || j != n)
85 {
86 i++; M[i][j] = x++;
87 while (i < n)
88 {
89 i++; j--; M[i][j] = x++;
90 }
91 if (j < n)
92 {
93 j++; M[i][j] = x++;
94 while (j < n)
95 {
96 i--; j++; M[i][j] = x++;
97 }
98 }
99 }
100 }
101
102 //afisare matrice
103 for (i = 1; i <= n; ++i)
104 {
105 for (j = 1; j <= n; ++j)
106 fout << M[i][j] << ’ ’;
107 fout << ’\n’;
108 }
109
110 //afisare punctaje distincte
111 fout << 2 * n - 5 << ’\n’;
112
113 //calcul punctaje distincte
114 k = 0;
115 for (i = 2; i < n; ++i)
116 for (j = 2; j < n; ++j)
117 {
118 X = 0;
119 for (dir = 1; dir <= 8; ++dir)
120 X += M[i+dx[dir]][j+dy[dir]];
121 p = 1; u = k;
122 gasit = false;
123 while (p <= u && !gasit)
124 {
125 m = (p + u) / 2;
126 if (X == S[m])
127 gasit = true;
128 else
129 if (X > S[m])
130 p = m + 1;
131 else
132 u = m - 1;
133 }
134 if (!gasit)
CAPITOLUL 22. ONI 2014 22.3. TINTA - ONI 2014 326
135 S[++k] = X;
136 }
137
138 // sort(S+1, S+k+1);
139 for (i = 1; i <= k; ++i)
140 fout << S[i] << ’ ’;
141 fout << ’\n’;
142 fout.close();
143
144 return 0;
145 }
62 do
63 {
64 if (j < n)
65 {
66 while (j > 1)
67 {
68 i++; j--; M[i][j] = x++;
69 }
70 i++; M[i][j] = x++;
71 while (i > 1)
72 {
73 i--; j++; M[i][j] = x++;
74 }
75 if (j < n)
76 {
77 j++; M[i][j] = x++;
78 }
79 }
80 } while (j != n);
81
82 //acum sub diagonala secundara
83 while (i != n || j != n)
84 {
85 i++; M[i][j] = x++;
86 while (i < n)
87 {
88 i++; j--; M[i][j] = x++;
89 }
90 if (j < n)
91 {
92 j++; M[i][j] = x++;
93 while (j < n)
94 {
95 i--; j++; M[i][j] = x++;
96 }
97 }
98 }
99 }
100
101 //afisare matrice
102 for (i = 1; i <= n; ++i)
103 {
104 for (j = 1; j <= n; ++j)
105 fout << M[i][j] << ’ ’;
106 fout << ’\n’;
107 }
108
109 //afisare punctaje distincte
110 fout << 2 * n - 5 << ’\n’;
111
112 //calcul punctaje distincte
113 k = 0;
114 for (i = 2; i < n; ++i)
115 for (j = 2; j < n; ++j)
116 {
117 S[++k] = 0;
118 for (dir = 1; dir <= 8; ++dir)
119 S[k] += M[i+dx[dir]][j+dy[dir]];
120 }
121
122 sort(S+1, S+k+1);
123
124 fout << S[1] << ’ ’;
125
126 i = 2;
127 j = 1;
128 while (i < k)
129 {
130 while (S[i] == S[j] && i < k) i++;
131 fout << S[i] << ’ ’;
132 j = i; i++;
133 }
134
135 fout << ’\n’;
136 fout.close();
137
CAPITOLUL 22. ONI 2014 22.3. TINTA - ONI 2014 328
138 return 0;
139 }
71
72 for(i=1;i<=n;i++)
73 {
74 for (j=1;j<=n;j++)
75 g<<a[i][j]<<" ";
76 g<<’\n’;
77 }
78
79 for(i=2;i<n;i++)
80 for(j=2;j<n;j++)
81 b[i][j]=a[i-1][j-1]+a[i-1][j]+a[i-1][j+1]+
82 a[i+1][j-1]+a[i+1][j]+a[i+1][j+1]+
83 a[i][j-1]+a[i][j+1];
84
85 g<<n-3+n-2<<’\n’;
86
87 for (j=2;j<=n-2;j++)
88 g<<b[2][j]<<" ";
89
90 for(j=2;j<=n-1;j++)
91 g<<b[n-1][j]<<" ";
92
93 return 0;
94 }
ONI 2013
Cerinţe
Având dat un număr natural cu N cifre şi un calculator care poate prelucra numere cu cel
mult K cifre, Mihai vă roagă să-l ajutaţi acum să afle răspunsuri la următoarele ı̂ntrebări:
a) pentru câte numere de cel mult K cifre va folosi calculatorul pentru a determina numărul
de divizori, urmând exact procedeul descris mai sus?
b) care este valoarea ce reprezintă numărul maxim de divizori obţinută ı̂n urma calculelor
efectuate de Mihai?
c) care este numărul cu cei mai mulţi divizori din şirul numerelor prelucrate de Mihai? Dacă
sunt mai multe numere cu acelaşi număr maxim de divizori, se va alege cel mai mic dintre ele.
Date de intrare
Prima linie a fişierului divizori.in conţine două numere naturale N şi K separate printr-un
singur spaţiu, reprezentând numărul de cifre al numărului natural iniţial, şi respectiv numărul de
cifre al afişajului calculatorului.
Linia a doua a fişierului divizori.in conţine numărul natural cu N cifre pe care ı̂l va prelucra
Mihai urmând exact procedeul descris mai sus.
Date de ieşire
330
CAPITOLUL 23. ONI 2013 23.2. REMI - ONI 2013 331
a 2&K&9
a 2 & N $ 1000000
a Pentru 40% din teste, N & 50000 şi K & 6;
a Dacă numărul afişat pe prima linie a fişierului de ieşire este corect se acordă 40% din punctajul
testului. Dacă numărul afişat pe a doua linie a fişierului de ieşire este corect se acordă 40% din
punctajul testului. Pentru afişarea corectă a valorii de pe linia a treia a fişierului de ieşire se
acordă 20% din punctajul testului.
Exemple
divizori.in divizori.out Explicaţii
43 5 16 Cele 16 numere prelucrate
5874392065432987667890567800123450889987543 48 sunt: 58743, 12920, 32654,
12012 83298, 87667, 48905, 46780,
12012, 48345, 16088, 89987,
6543, 6, 4, 3, 2. Dintre
acestea, cei mai mulţi divizori
(48) ı̂i are numărul 12012
Cerinţe
Cunoscând piesele extrase de Andrei, ajutaţi-l să construiască numărul astfel ı̂ncât să aibă cele
mai mari şanse ı̂n câştigarea jocului.
Date de intrare
CAPITOLUL 23. ONI 2013 23.3. TETRIS - ONI 2013 332
Cerinţe
Date de intrare
Fişierul tetris.in conţine pe prima linie două numere naturale N şi M reprezentând numărul
de linii, respectiv numărul de coloane ale zonei de joc. Următoarele linii conţin perechi de numere
naturale, fiecare descriind câte o piesă ı̂n ordinea intrării ei ı̂n joc. Primul număr din pereche
reprezintă lungimea laturii piesei, iar cel de al doilea reprezintă numărul de ordine al coloanei
pe care se ı̂ncearcă plasarea laturii stângi a piesei. Numerele de pe fiecare linie sunt separate
printr-un singur spaţiu.
Date de ieşire
În fişierul tetris.out se va scrie pe prima linie numărul maxim al liniei ocupate de o piesă, iar
pe a doua linie numărul maxim de coloane alăturate ocupate de piese, din cadrul acestei linii.
Exemple
tetris.in tetris.out Explicaţii
78 74 Exemplu din desen descrie ordinea ı̂n care au intrat piesele
11 ı̂n joc. Linia 7 este linia cu număr de ordine maxim ce este
22 acoperită cu piese. Piesele 8 şi 10 acoperă această linie, pe
27 o secvenţă de 4 coloane alăturate, iar piesa 9 acoperă doar o
16 coloană, deci secvenţa maximă este de lungime 4.
36 Piesa 11 nu a mai putut fi introdusă ı̂n joc.
33
18
25
18
23
33
ONI 2012
Cerinţe
Date de intrare
Fişierul cartier.in conţine pe prima linie un număr natural n (numărul de blocuri de construit)
şi pe a doua linie n numere naturale, separate prin câte un spaţiu, reprezentând numărul de cuburi
corespunzătoare fiecărui bloc.
Date de ieşire
Fişierul cartier.out conţine numerele x, y şi z, ı̂n această ordine, fiecare pe câte o linie.
334
CAPITOLUL 24. ONI 2012 24.1. CARTIER - ONI 2012 335
Exemple
cartier.in cartier.out Explicaţii
6 1
7 4 10 12 10 15 13
4
23 H[i]=d;
24 L=x/d;
25 }
26 else
27 {
28 H[i]=x/d;
29 L=d;
30 }
31
32 Ltotal=Ltotal+L;
33
34 if(H[i]>Hmax)
35 {
36 Hmax=H[i];
37 nrmax=1;
38 }
39 else
40 if(H[i]==Hmax)
41 nrmax++;
42 }
43
44 Max=1;
45 sf=1;
46 for(i=1;i<=n && Max<n;i++)
47 {
48 for(j=n;j>=i && Max<j-i+1;j--)
49 {
50 a=H[i];
51 b=H[j];
52
53 while(a!=b)
54 if(a>b)a=a-b;
55 else b=b-a;
56
57 if(a!=1)
58 {
59 sf=j;
60 break;
61 }
62 }
63
64 if(sf-i+1>Max)
65 Max=sf-i+1;
66 }
67
68 g<<nrmax<<’\n’<<Ltotal<<’\n’<<Max<<’\n’;
69 f.close();
70 g.close();
71 return 0;
72 }
Cerinţe
a) Ştiind că bijutierul completează n (n număr natural impar) rânduri cu cristale pe pla-
cheta de aur, determinaţi cea mai mare sumă a valorilor tuturor cristalelor situate pe un rând al
medalionului.
b) Determinaţi valoarea cristalului montat cu exact p rânduri deasupra primului cristal montat
ı̂n medalion şi plasat pe aceeaşi coloană cu acesta.
Date de intrare
Fişierul medalion.in conţine pe prima linie numerele naturale k, n, p (ı̂n această ordine), cu
semnificaţiile menţionate anterior. Valorile k, n, p sunt separate prin câte un spaţiu.
Date de ieşire
Fişierul medalion.out conţine pe prima linie un număr natural, ce reprezintă numărul de-
terminat conform cerinţei a), iar pe cea de-a doua linie un număr natural, determinat conform
cerinţei b).
Exemple
medalion.in medalion.out Explicaţii
534 12 a) După montarea a 3 rânduri de cristale se obţine configuraţia:
2 Sumele valorilor cristalelor de pe aceste
rânduri sunt:
2+3+4=9
1+1+2=4
5+4+3=12
Suma cea mai mare este 12.
b) Cristalul situat cu 4 rânduri dea-
supra centrului medalionului, marcat ı̂n
desenul alăturat, are valoarea 2.
Rezolvarea cerinţei a)
- se construieşte ı̂n memorie matricea pătratică de dimensiune n, respectând regula de
construcţie a acesteia prin aşezarea ı̂n spirală a secvenţei de numere 1, 2, 3, ..., k, 1, 2, 3, ..., k, 1, 2, 3...
- pentru fiecare linie a matricei se calculează suma elementelor sale
- se determină cea mai mare valoare dintre sumele calculate
Rezolvarea cerinţei b)
- pentru valori mici ale lui p, putem folosi matricea construită la pasul anterior
- respectând restricţiile problemei 1 & p & 500000 ne dăm seama că nu vom putea memora
ı̂ntr-o matrice suficiente elemente pentru a determina ı̂n acest fel elementul specificat
- pentru o rezolvare corectă care ţine cont de restricţiile specificate ı̂n problemă (1 & p & 500000)
putem observa uşor că pe fiecare ”spiră” generată, numărul elementelor sale este cu 8 mai mare
decât numărul de elemente al spirei generată anterior.
27 int main()
28 {
29 long long val,linie,spira,j;
30
31 fin>>k>>n>>p;
32 fin.close();
33
34 m=n/2+n%2;
35 a[m][m]=1;
36 linie=m;
37 val=2;
38 spira=1;
39
40 while(linie>=1)
41 {
42 for(j=1;j<=2*spira-1;j++)//dreapta
43 {
44 a[linie][linie+j]=val;
45 val=1+val%k;
46 }
47 for(j=1;j<=2*spira-1;j++)//jos
48 {
49 a[linie+j][m+spira]=val;
50 val=1+val%k;
51 }
52 for(j=m+spira-1;j>=m-spira;j--)//stanga
53 {
54 a[m+spira][j]=val;
55 val=1+val%k;
56 }
57 for(j=m+spira-1;j>=m-spira;j--)//sus
58 {
59 a[j][m-spira]=val;
60 val=1+val%k;
61 }
62 spira++;
63 linie--;
64 }
65 calcul();
66
67 //cerinta b
68 val=(1+4*p*p+3*p)%k;
69 if (val==0)
70 fout<<k<<endl;
71 else
72 fout<<val<<endl;
73
74 fout.close();
75 return 0;
76 }
1. Se porneşte de la cifra iniţială 2 (2 3 9 6) şi se numără două cifre spre dreapta, ajungând la
cifra finală 9: 2 3 9 6.
2. Se porneşte de la cifra iniţială 9 şi se numără nouă cifre spre dreapta, ajungând la cifra
finală 6: 2 3 9 6.
3. Se porneşte de la cifra iniţială 6 şi se numără şase cifre spre dreapta, ajungând la cifra finală
3: 2 3 9 6.
4. Se porneşte de la cifra iniţială 3 şi se numără trei cifre spre dreapta, ajungând la cifra finală
2: 2 3 9 6.
Astfel, se ajunge la prima cifră din număr, adică la cifra 2, după exact 4 aplicări ale algorit-
mului, iar fiecare dintre cifrele numărului este exact o dată cifră iniţială.
Cerinţe
Scrieţi un program care citeşte numărul natural nenul n, apoi numerele naturale x1 , x2 , ...,
xn , şi determină:
a) cel mai mare număr din şir ı̂n care există cel puţin o cifră care apare de minimum două ori,
iar ı̂n cazul ı̂n care ı̂n şir nu există un astfel de număr, se va afişa cel mai mare număr din şir;
b) un şir a1 , a2 , ..., an de n numere naturale pentru care un element ai (1 & i & n)se calculează
astfel:
- este egal cu xi , dacă xi este număr circular;
- este numărul cel mai apropiat de xi (număr mai mare sau mai mic decât xi ), cu proprietatea
că este număr circular; dacă pentru un număr din şir se identifică un număr circular y, y % xi şi
un număr circular z, z $ xi , pentru care y xi xi z, atunci se va alege numărul y.
Date de intrare
Fişierul numar.in conţine pe prima linie numărul n, iar pe următoarele n linii numerele
naturale x1 , x2 , ..., xn .
Date de ieşire
Fişierul numar.out va conţine pe prima linie un număr natural determinat conform cerinţei
a), iar pe următoarele n linii şirul de numere determinat conform cerinţei de la punctul b), fiecare
număr pe câte un rând.
a 0 $ n $ 100
a 9 $ xi $ 999589, 1 & i & n
a pentru rezolvarea corectă a cerinţei a) se obţine 30% din punctaj, iar pentru rezolvarea
corectă a cerinţei b) se obţine 70% din punctaj.
Exemple
numar.in numar.out Explicaţii
5 515 a) 515 este cel mai mare număr dintre cele cinci numere citite,
15 15 număr ce conţine o cifră care apare de minimum două ori.
123 117 b) Pentru 15 : de la cifra iniţială 1, se numără o cifră şi se ajunge la
1972 1959 cifra finală 5, apoi ı̂ncepând de la cifra 5 ca cifră iniţială, se numără
222 222 cinci cifre şi se ajunge la cifra finală 1. Astfel cifrele 1, 5 sunt o
515 522 singură dată cifre iniţiale şi după două aplicări ale algoritmului de
deplasare se ajunge la prima cifră, deci 15 este număr circular.
Pentru 123: de la cifra iniţială 1, se numără o cifră şi se ajunge la
cifra finală 2, apoi ı̂ncepând de la cifra 2 ca cifră iniţială, se numără
două cifre şi se ajunge la cifra finală 1. Astfel, se ajunge din nou la
prima cifră, ı̂nsă algoritmul de deplasare s-a aplicat doar de două
ori şi nu trei ori, iar cifra 3 nu a fost cifră iniţială. Ca urmare, 123
nu este număr circular. Se determină cele două numere circulare,
y=141 şi z=117, cel mai apropiat de 123 dintre ele fiind 117.
Cu celelalte numere se procedează ı̂n acelaşi mod.
a) Se calculează cel mai mare număr şi cel mai mare număr care are ı̂n componenţă cifre care
se repetă. Dacă nu a existat niciun număr care conţine cifre care se repetă, se va afişa cel mai
mare număr, ı̂n caz contrar cel mai mare număr care are ı̂n componenţă cifre care se repetă.
b) Se identifică cifrele numărului şi se păstrează ı̂ntr-un vector.
Se verifică proprietatea de număr circular.
Dacă cel puţin o cifră are valoare 0, atunci număarul nu e circular.
Dacă numărul nu conţine nicio cifră 0, se ı̂ncepe numărătoarea spre dreapta de la prima cifră.
Se calculează următoarea cifră la care se ajunge, ţinând cont de faptul că atunci când se termină
cifrele de parcurs, se ı̂ncepe iarăşi cu prima cifră. Se continuă ı̂n acelaşi mod până când se ajunge
la o cifră care a mai fost atinsă anterior, sau se ajunge la prima cifră, după ce s-au atins toate
celelalte cifre.
Dacă numărul nu a fost circular, se caută unul mai mare decât el care are proprietatea de
număr circular. Fie acesta x. Se caută şi un număr mai mic decât el care are proprietatea de
număr circular. Fie acesta y. Se alege apoi dintre z şi x cel mai apropiat număr. Dacă ambele
sunt la fel de apropiate, se alege x.
44 max1=0;
45 max2=0;
46 for(i=0;i<n;i++)
47 {
48 if (cifre_repetate(a[i]))
49 if (max2<a[i])
50 max2=a[i];
51
52 if (max1<a[i])
53 max1=a[i];
54 }
55
56 if (max2==0)
57 return max1;
58 else
59 return max2;
60 }
61
62 int este (long x)
63 {
64 int i=1,a[100],b[100],k=0,t,z=0,j,ok;
65
66 while (x!=0)
67 {
68 a[i]=x%10;
69 if (a[i]==0)
70 return 0;
71 x/=10;
72 b[i++]=1;
73 }
74
75 i--;
76 for(j=0;j<=i/2;j++)
77 {
78 z=a[j];
79 a[j]=a[i+1-j];
80 a[i+1-j]=z;
81 }
82
83 z=0;
84 t=a[1];
85 k=1;
86 ok=1;
87 for(j=1;j<=i && ok;j++)
88 {
89 if(k+t<=i)
90 k=k+t;
91 else
92 k=(t-(i-k+1))%i+1;
93
94 if (b[k]!=0)
95 {
96 z++;
97 b[k]=0;
98 }
99 else
100 ok=0;
101
102 t=a[k];
103 }
104
105 if (ok)
106 return 1;
107 else
108 return 0;
109 }
110
111 int main()
112 {
113 int p=-1,i,z=0;
114 long t,x,y;
115
116 date();
117
118 g<<max()<<endl;
119
CAPITOLUL 24. ONI 2012 24.3. NUMAR - ONI 2012 343
120 z=0;
121 for(i=0;i<n;i++)
122 if (este(a[i]))
123 g<<a[i]<<endl;
124 else
125 {
126 p=0;
127 x=a[i];
128 while (!p)
129 if (este(x))
130 p=1;
131 else
132 x++;
133
134 p=0;
135 y=a[i];
136 while (!p)
137 if (este(y))
138 p=1;
139 else
140 y--;
141
142 if((x-a[i])>(a[i]-y))
143 g<<y<<endl;
144 else
145 g<<x<<endl;
146 }
147
148 g<<endl;
149 g.close();
150 return 0;
151 }
ONI 2011
Cerinţe
Scrieţi un program care să citească cele trei numere naturale nenule n, x şi y, şi apoi să
determine:
a) numărul t al sectoarelor de pe pistă prin care nu trece niciunul dintre cei doi copii ı̂n urma
săriturilor executate până la terminarea jocului;
b) numărul s de sărituri executate de fiecare copil până la terminarea jocului;
c) etichetele b şi r ale sectoarelor ı̂n care ajung cei doi copii la terminarea jocului (Bogdan
ajunge la finalul jocului ı̂n sectorul cu eticheta b, iar Rareş ı̂n cel cu eticheta r).
Date de intrare
Fişierul de intrare joc.in conţine pe prima linie trei numere naturale n, x şi y, separate prin
câte un spaţiu, cu semnificaţia din enunţ.
Date de ieşire
Fişierul de ieşire joc.out va conţine pe prima linie cele patru numere naturale determinate de
program: t, s, b şi r, separate prin câte un spaţiu, ı̂n această ordine, cu semnificaţia din enunţ.
344
CAPITOLUL 25. ONI 2011 25.1. JOC - ONI 2011 345
Exemple
joc.in joc.out Explicaţii
16 2 3 4819 Cei doi copii, executând simultan sărituri, trec până la terminarea jocu-
lui, prin sectoarele:
Bogdan 1 3 5 7 9 11 13 15 1
Rares 1 14 11 8 5 2 15 12 9
Jocul se termină după s 8 sărituri deoarece Bodgan ajunge din nou ı̂n
sectorul cu eticheta b 1. La finalul jocului Rareş se află ı̂n sectorul cu
eticheta r 9. Cei doi copii nu au trecut prin t 4 sectoare ale căror
etichete sunt: 4, 6, 10, 16.
16 6 2 12 2 13 13 Cei doi copii, executând simultan sărituri, trec până la terminarea jocu-
lui, prin sectoarele:
Bogdan 1 7 13
Rares 1 15 13
Jocul se termină după s 2 sărituri deoarece Bodgan şi Rareş ajung
amândoi ı̂n sectorul cu eticheta b r 13. Cei doi copii nu au trecut
prin t 12 sectoare ale căror etichete sunt: 2, 3, 4, 5, 6, 8, 9, 10, 11, 12,
14, 16.
O soluţie a problemei se poate obţine prin utilizarea unui vector v cu maxim 40000 de compo-
nente, cu indicii de la 1, de tip caracter. Iniţial, toate cele n componente, n & 40000, au valoarea
zero, exceptând componenta 1: v 1 11. Cifra zecilor, respectiv unităţilor, codului caracterului
memorat ı̂ntr-o componentă a vectorului este 1 dacă Bogdan, respectiv Rareş, a trecut prin acest
sector marcând ı̂n acest mod trecerea.
Simulăm parcurgerea circulară a vectorului, simultan ı̂n cele două direcţii corespunzător fiecărei
sărituri din timpul deplasării celor doi copii folosind două variabile b şi r (iniţial cu valoarea 1),
marcând totodată sectoarele prin care trec. La trecerea prin sectorul cu eticheta b, respectiv r,
marcarea trecerii se realizează prin incrementarea cifrei unităţilor lui v b dacă Bogdan a ajuns
ı̂n acest sector, respectiv prin incrementarea cifrei unităţilor lui v r dacă Rareş a ajuns ı̂n acest
sector.
După fiecare salt, se verifică, ı̂n această ordine, dacă etichetele sectoarelor ı̂n care au ajuns cei
doi copii sunt identice, adică b r, caz ı̂n care se termină jocul. Altfel se verifică dacă v b 11
sau v r 11, adică dacă Bogdan sau Rareş au trecut de două ori prin acelaşi sector, caz ı̂n care
se termină din nou jocul. Altfel, se continuă dubla parcurgere circulară a vectorului pănă când
este adevărată una din condiţiile de mai sus, ı̂n ordinea ı̂n care au fost specificate.
O implementare a soluţiei propuse ı̂n limbajul C/C++ este următoarea:
CAPITOLUL 25. ONI 2011 25.1. JOC - ONI 2011 346
10 p1=p2=0;
11 a[p1]=1;
12 //a[p2]=2;
13
14 s=0;
15 while(!g)
16 {
17 p1=(p1+x)%n;
18 p2=(n+p2-y)%n;
19 if(!(p1==p2 || p1*p2==0 || (a[p1]-1)*(a[p2]-2)==0))
20 {
21 a[p1]=1;
22 s++;
23 a[p2]=2;
24 }
25 else
26 {
27 a[p1]=1;
28 s++;
29 a[p2]=2;
30 g=1;
31 }
32 }
33
34 x=0;
35 for(i=0;i<n;i++)
36 x=x+(a[i]+1)/2;
37 t=n-(x);
38 }
39
40 int main()
41 {
42 freopen("joc.in","r",stdin);
43 freopen("joc.out","w",stdout);
44
45 scanf("%d%d%d",&n,&x,&y);
46
47 joc();
48
49 printf("%ld %ld %ld %ld",t,s,p1+1,p2+1);
50 return 0;
51 }
Cerinţe
Date de intrare
Fişierul talent.in conţine pe prima linie numărul n de participanţi, iar pe fiecare dintre
următoarele n linii câte un număr natural reprezentând numărul de concurs al unui participant.
Date de ieşire
Fişierul talent.out va conţine pe prima linie cele două valori x şi y, separate printr-un singur
spaţiu, ı̂n această ordine. Dacă nu există participanţi admişi direct ı̂n semifinală, atunci prima
linie a fişierului va conţine două valori nule, separate printr-un singur spaţiu: 0 0.
a 0 $ n & 15000
a numerele de concurs sunt distincte două câte două şi sunt mai mici sau egale cu 2 000 000
000
a un număr palindrom este un număr natural care este egal cu numărul natural obţinut prin
scrierea ı̂n ordine inversă a cifrelor lui (de exemplu, numărul 12021 este un număr palindrom)
a pentru rezolvarea corectă a primei cerinţe se acordă 50% din punctaj, iar pentru rezolvarea
corectă a celei de a doua cerinţe se acordă 50% din punctaj.
Exemple
talent.in talent.out Explicaţii
8 3 46476 Sunt 3 participanţi calificaţi direct ı̂n semifinală. Numerele lor
17864 de concurs sunt numere ale căror cifre pot fi aranjate astfel
9900 ı̂ncât să formeze un palindrom : 9900 (format din 2 cifre dis-
90321 tincte), 83181 (format din 3 cifre distincte) şi 46476 (format
4704 din 3 cifre distincte). Dintre acestea, cel mai mic număr format
351 dintr-un număr maxim de cifre distincte este 46476 reprezentând
83181 numărul de concurs al participantului VIP.
46476
7432
prof. Septimiu Sorin Groza, Colegiul Naţional ”Titu Maiorescu”, Aiud, Alba
Parcurgând secvenţial şirul de numere, se verifică pentru fiecare număr dacă prin aranjarea
cifrelor lui se obţine un număr palindrom. Pentru aceasta se construieşte vectorul de apariţii ale
cifrelor ı̂n număr.
La un palindrom cu număr par de cifre, fiecare cifră apare de un număr par de ori.
La unul cu număr impar de cifre, doar o cifră poate să apară de un număr impar de ori şi ı̂n
rest toate de un număr par de ori.
Totodată se determină şi numărul de cifre distincte din număr.
Dacă este palindrom se contorizează şi se păstrează dacă are un număr mai mare de cifre
distincte decât cel mai bun găsit până atunci sau dacă are acelaşi număr de cifre distincte ca el şi
este mai mic.
O implementare a soluţiei ı̂n limbajul Pascal este următoarea:
CAPITOLUL 25. ONI 2011 25.2. TALENT - ONI 2011 350
33 {
34 f>>x;
35 if(pali(x))
36 {
37 p++;
38 if(!vip || maxd<d || maxd==d && x<vip)
39 vip=x, maxd=d;
40 }
41 }
42
43 g<<p<<’ ’<<vip<<’\n’;
44
45 f.close();
46 g.close();
47 return 0;
48 }
Cerinţe
Scrieţi un program care citeşte trei numere naturale n, m, k şi un şir de k mutări pe care cei
doi fraţi doresc să le efectueze, alternativ, ı̂n ordinea dată şi apoi determină:
a numărul maxim a de pătrate completate ı̂n timpului unei mutări;
a numărul b de pătrate rămase libere după ı̂ncheierea jocului;
CAPITOLUL 25. ONI 2011 25.3. XY - ONI 2011 352
Date de intrare
Fişierul de intrare xy.in conţine pe prima linie trei numere naturale n, m şi k, separate prin
câte un spaţiu, cu semnificaţia din enunţ. Următoarele k linii conţin fiecare câte două numere
naturale i şi j, separate prin câte un spaţiu, reprezentând linia i şi coloana j unde este poziţionat
pătratul ales drept centru pentru a se efectua mutarea propusă.
Date de ieşire
Fişierul de ieşire xy.out va conţine pe prima linie cele trei numere determinate de program:
a, b şi c, separate prin câte un spaţiu, ı̂n această ordine, cu semnificaţia din enunţ.
Exemple
xy.in xy.out Explicaţii
655 5 17 9 La prima mutare, primul jucător trasează un X, cu centrul ı̂n linia 3 şi
32 coloana 2, prin completarea a 5 pătrate cu caracterul x.
44 La a doua mutare, al doilea jucător trasează un Y cu centrul ı̂n linia 4
34 şi coloana 4, prin completarea a 4 pătrate cu caracterul y.
24 La a treia mutare, primul jucător trasează un X, cu centrul ı̂n linia 3 şi
54 coloana 4, prin completarea doar a 3 pătrate cu caracterul x deoarece
foloseşte 2 pătrate completate la prima mutare.
La a patra mutare, al doilea jucător reuşeşte să completeze cu caracterul
y doar pătratul ales ca centru, situat ı̂n linia 2 şi coloana 4, şi jocul se
ı̂ncheie deoarece nu se poate realiza trasarea lui Y .
Pentru determinarea numărului maxim a de pătrate completate ı̂n timpului unei mutări este
suficient să contorizăm la fiecare mutare efectuată numărul de pătrate completate şi să actualizăm
valoarea a.
Pentru trasarea unui semn (X sau Y ) putem actualiza, plecând din centrul pătratului ales,
liniile şi coloanele care ı̂ncadrează pătratul ce ı̂ncadrează semnul.
Figura 25.3: xy
Determinarea numărului b de pătrate rămase libere după ı̂ncheierea jocului se poate face cal-
culând diferenţa n m - numărul de pătrate completate ı̂n timpul tuturor mutărilor efectuate.
Determinarea numărului maxim c de pătrate completate care formează o suprafaţă dreptunghi-
ulară pe tabla de joc la finalul jocului, se poate face modificând valorile din matricea ce memorează
suprafaţa de joc, astfel ı̂ncât fiecare element sij , situat pe o linie i şi o coloană j să memoreze
numărul pătratelor completate situate pe coloana j şi pe linii consecutive ce includ şi linia i.
Suprafaţa maximă este actualizată la fiecare pas de valoarea
maxrsij j2 j1 1©1 & j1 & j & j2 & m, sij & sik, k " j1, j2x
31 a[xs][ys]=a[xs][yd]=a[xj][y]=2;
32 xs--,xj++,ys--,yd++;
33 }
34 }
35
36 return c;
37 }
38
39 void arie()
40 { int i,j,j1,j2;
41 for(i=1;i<=n;i++)
42 {for(j=1;j<=m;j++)
43 if(a[i][j]!=0) a[i][j]=a[i-1][j]+1;
44 for(j=1;j<=m;j++)
45 if(a[i][j]!=0)
46 { j1=j;j2=j;
47 while(j1 && a[i][j1]>=a[i][j])j1--;
48 while(j2<=m && a[i][j2]>=a[i][j])j2++;
49 j1++;j2--;
50 if((j2-j1+1)*a[i][j]>M) M= (j2-j1+1)*a[i][j];
51 }
52 }
53 }
54
55 int main()
56 {f>>n>>m>>k;
57 do
58 {f>>x>>y;
59 r=marcheaza(jucator,x,y);
60 if(r>maxx)maxx=r;
61 s=s+r;
62 jucator=!jucator;
63 k--;
64 }while(k && r>1);
65
66 arie();
67 g<<maxx<<’ ’<<n*m-s<<’ ’<<M<<’\n’;
68 f.close();g.close();
69 return 0;
70 }
33 a[u][v]=2;
34 noi=0;
35 k=1,gata=0;
36
37 do
38 {if(u-k<1 ||u+k>n || v-k<1 || v+k>m) gata=1;
39 else
40 if(a[u-k][v-k]==1||a[u-k][v+k]==1||a[u+k][v]==1) gata=1;
41 else {noi=noi+6-a[u-k][v-k]-a[u-k][v+k]-a[u+k][v];
42 a[u-k][v-k]=a[u-k][v+k]=a[u+k][v]=2;
43 k++;
44 }
45
46 }while(!gata);
47
48 noi=noi/2+1;
49 total+=noi;
50 }
51
52 int dreptunghi()
53 {int i,j,i1,j1,max1=0,dif;
54 for(i=1;i<=n;i++)
55 for(j=1;j<=m;j++)
56 {if(a[i][j]==2)a[i][j]=1;
57 a[i][j]=a[i][j]+a[i][j-1]+a[i-1][j]-a[i-1][j-1];
58 }
59
60 for(i=1;i<=n;i++)
61 for(j=1;j<=m;j++)
62 for(i1=i;i1<=n;i1++)
63 for(j1=j;j1<=m;j1++)
64 { dif=a[i1][j1]-a[i1][j-1]-a[i-1][j1]+a[i-1][j-1];
65 if(dif==(i1-i+1)*(j1-j+1))
66 if(dif>max1)
67 { p1=i,q1=j,p2=i1,q2=j1;
68 max1=dif;
69 }
70 }
71
72 return max1;
73 }
74
75 void citire()
76 {int i,u,v;
77 f>>n>>m>>k;
78 for(i=1;i<=k;i++)
79 {f>>u>>v;
80 if(a[u][v])return;
81 else
82 {if (i%2)pune1(u,v);
83 else pune2(u,v);
84 if(maxim<noi) maxim=noi;
85 if(noi==1) return;
86
87 }
88 }
89 }
90
91 int main()
92 { citire();
93 g<<maxim<<" "<<m*n-total<<" "<<dreptunghi();
94
95 return 0;
96 }
9
10 void pune1(int u,int v)
11 {int k,gata;
12 a[u][v]=1;
13 noi=1;
14 k=1,gata=0;
15 do
16 {if(u-k<1 ||u+k>n || v-k<1 ||v+k>m) gata=1;
17 else
18 if(a[u-k][v-k]==2||a[u-k][v+k]==2||a[u+k][v-k]==2||a[u+k][v+k]==2)
19 gata=1;
20 else {noi=noi+4-a[u-k][v-k]-a[u-k][v+k]-a[u+k][v-k]-a[u+k][v+k];
21 a[u-k][v-k]=a[u-k][v+k]=a[u+k][v-k]=a[u+k][v+k]=1;
22 k++;
23 }
24
25 }while(!gata);
26 total+=noi;
27 }
28
29 void pune2(int u,int v)
30 {int k,gata;
31 a[u][v]=2;
32 noi=0;
33 k=1,gata=0;
34
35 do
36 {if(u-k<1 ||u+k>n || v-k<1 || v+k>m) gata=1;
37 else
38 if(a[u-k][v-k]==1||a[u-k][v+k]==1||a[u+k][v]==1) gata=1;
39 else {noi=noi+6-a[u-k][v-k]-a[u-k][v+k]-a[u+k][v];
40 a[u-k][v-k]=a[u-k][v+k]=a[u+k][v]=2;
41 k++;
42 }
43
44 }while(!gata);
45
46 noi=noi/2+1;
47 total+=noi;
48 }
49
50 int dreptunghi()
51 {int i,j,i1,j1,max1=0,dif;
52 for(i=1;i<=n;i++)
53 for(j=1;j<=m;j++)
54 {if(a[i][j]==2)a[i][j]=1;
55 a[i][j]=a[i][j]+a[i][j-1]+a[i-1][j]-a[i-1][j-1];
56 }
57 for(i=1;i<=n;i++)
58 for(j=1;j<=m;j++)
59 for(i1=i;i1<=n;i1++)
60 for(j1=j;j1<=m;j1++)
61 { dif=a[i1][j1]-a[i1][j-1]-a[i-1][j1]+a[i-1][j-1];
62 if(dif==(i1-i+1)*(j1-j+1))
63 if(dif>max1)
64 { p1=i,q1=j,p2=i1,q2=j1;
65 max1=dif;
66 }
67 }
68 return max1;
69 }
70
71 void citire()
72 {int i,u,v;
73 scanf("%d%d%d",&n,&m,&k);
74 for(i=1;i<=k;i++)
75 {scanf("%d%d",&u,&v);
76 if(a[u][v])return;
77 else
78 {if (i%2)pune1(u,v);
79 else pune2(u,v);
80 if(maxim<noi) maxim=noi;
81 if(noi==1) return;
82
83 }
84 }
CAPITOLUL 25. ONI 2011 25.3. XY - ONI 2011 357
85 }
86
87 int main()
88 { freopen("xy.in","r",stdin);
89 freopen("xy.out","w",stdout);
90 citire();
91
92 printf("%d %d %d",maxim,m*n-total,dreptunghi());
93
94 return 0;
95 }
ONI 2010
Cerinţe
Fiind date două numere naturale a şi b, precum şi o cifră c, să se determine câte numere
cuprinse ı̂ntre a şi b, inclusiv a şi b, au cifra de control egală cu c.
Date de intrare
Fişierul de intrare control.in conţine pe prima linie valorile a b c separate prin câte un spaţiu.
Date de ieşire
Fişierul de ieşire control.out va conţine o singură linie pe care va fi scris un număr natural k
care reprezintă numărul de valori cuprinse ı̂ntre a şi b (inclusiv) care au cifra de control egală cu
c.
Exemple
control.in control.out Explicaţii
10056 10105 7 6 Cele 6 numere care au cifra de control 7 cuprinse ı̂ntre 10056
şi 10111 sunt:
10060: 1+0+0+6+0 = 7
10069: 1+0+0+6+9 = 16; 1+6 = 7
10078: 1+0+0+7+8 = 16; 1+6 = 7
10087: 1+0+0+8+7 = 16; 1+6 = 7
10096: 1+0+0+9+6 = 16; 1+6 = 7
10105: 1+0+1+0+5 = 7
358
CAPITOLUL 26. ONI 2010 26.1. CONTROL - ONI 2010 359
Cerinţe
Date de intrare
Fişierul de intrare figura.in conţine pe prima linie numărul natural D. Pe cea de a doua
linie se află numărul natural N . Pe următoarele N linii sunt descrise coordonatele pătrăţelelor
decupate (linia şi coloana pe care se află pătrăţelul, separate prin spaţiu), câte un pătrat pe o
linie.
Date de ieşire
Fişierul de ieşire figura.out va conţine o singură linie pe care va fi scris un singur număr
natural reprezentând perimetrul figurii decupate.
a 1 & D & 20
a 1&N &DD
a Liniile sunt numerotate de sus ı̂n jos de la 1 la D; coloanele sunt numerotate de la stânga la
dreapta de la 1 la D.
a Lungimea laturii unui pătrăţel este 1 cm.
Exemple
figura.in figura.out Explicaţii
6 6
3 Foaia de matematică are 36 de pătrăţele aranjate
11 ı̂n 6 linii şi 6 coloane. Figura decupată este mar-
12 cată cu negru.
21
Se observă faptul că dacă se marchează ı̂ntr-o matrice cu 0 zonele libere şi cu 1 cele ocupate de
figură, atunci pentru un observator aflat ı̂n una dintre zonele libere vecine figurii acel 1 semnifică
exact numărul de laturi care ı̂l desparte de observator.
Ceea ce ı̂nseamnă că este suficient să ne plimbăm prin matrice şi pentru zonele aflate ı̂n afara
figurii numărăm vecinii egali cu 1 (de fapt pur şi simplu adunăm valorile vecine, deoarece dacă nu
face parte din figura unul din vecini, el are valoarea 0).
Desigur, pentru a surprinde şi cazurile când figura se află la marginea/marginile matricei,
trebuie să avem grijă ca ”foaia” să fie cu două linii şi două coloane mai mare decât dimensiunea
matricei.
Ultima dată, bunicul i-a cerut lui Andrei să aşeze jetoanele ı̂n şir, unul lângă altul, pe culori,
ı̂n ordine de la culoarea din care avea cele mai multe jetoane până la culoarea din care avea cele
mai puţine jetoane.
Pentru că şirul format era prea lung şi nu ı̂ncăpea pe covor, bunicul l-a rugat pe Andrei să
formeze un pătrat de latură maximă, luând jetoanele ı̂n ordinea ı̂n care erau dispuse şi punându-le
unul lângă altul (ı̂n număr egal) pe liniile pătratului. Completarea pătratului se va face de sus
ı̂n jos, ı̂n ordinea crescătoare a liniilor, iar pe fiecare linie de la stânga la dreapta, ı̂n ordinea
crescătoare a coloanelor.
Cerinţe
Cunoscând culorile jetoanelor din cutie, scrieţi un program care să determine numărul de culori
existente ı̂n joc, latura maximă a pătratului pe care-l poate construi Andrei, precum şi modalitatea
de aranjare a jetoanelor ı̂n pătrat.
Date de intrare
Fişierul de intrare joc.in conţine pe prima linie numărul natural N , reprezentând numărul de
jetoane din joc. Pe următoarele N linii sunt descrise culorile celor N jetoane din joc, câte un jeton
pe o linie. Culorile sunt identificate prin cifre cuprinse ı̂ntre 1 şi 9.
Date de ieşire
Fişierul de ieşire joc.out va conţine pe prima linie un număr natural C, reprezentând numărul
de culori folosite pentru jetoanele din joc. Pe cea de-a doua linie se va scrie un număr natural
M AX reprezentând latura maximă a pătratului format. Pe următoarele M AX linii se vor scrie
câte M AX cifre cuprinse ı̂ntre 1 şi 9, reprezentând culorile jetoanele aşezate ı̂n pătrat, conform
restricţiilor din enunţ.
Exemple
joc.in joc.out Explicaţii
13 4 ı̂n joc sunt jetoane de 4 culori (culorile 4, 5, 8, 9).
8 3 ı̂n ordinea specificată ı̂n enunţ, jetoanele ar putea fi aranjate ı̂n
5 888 linie astfel:
8 888 8888888555994
8 855 Cu aceste jetoane se poate construi un pătrat cu latura
8 maximă 3, considerând jetoanele ı̂n ordinea specificată, ı̂n modul
5 următor:
8 888
8 888
5 855
9 Observaţi că rămân 4 jetoane neutilizate (un jeton de culoare 5,
8 două jetoane de culoare 9 şi un jeton de culoare 4).
4
9
La citirea jetoanelor din fişieul de intrare com construi un vector uz, cu 9 elemente (de la 1 la
9), uz i = numărul de jetoane având culoarea i.
Pentru a determina numărul de culori, este suficient să parcurgem vectorul uz şi să determinăm
numărul de elemente nenule. Ô
Latura maximă a pătratului va fi egală cu partea ı̂ntreagă a lui n.
Pentru a construi pătratul, trebuie să ordonăm culorile descrescător după numărul lor de
apariţii.
Parcurgem apoi culorile ı̂n această ordine, afişându-le direct ı̂n fişier (nu este necesar să con-
struim matricea).
2 #include <fstream>
3 #include <math.h>
4
5 using namespace std;
6
7 char culori[60001];
8
9 int main()
10 {
11 ifstream f("joc.in");
12 ofstream g("joc.out");
13
14 long k[10], MAX, N;
15 long int C,i,j,s=0,ss,x,p,indici[10];
16 char v[60001];
17
18 for (i=1; i<=9; i++)
19 {
20 k[i]=0;
21 indici[i]=i;
22 }
23
24 f>>N; //g<<N<<endl;
25 for (i=1; i<=N; i++)
26 {
27 f>>culori[i]; culori[i]-=’0’;
28 k[culori[i]]++;
29 }
30 f.close();
31
32 // for (i=1; i<=N; i++) g<<(int)culori[i]; g<<endl;
33 // for (i=1; i<=9; i++) g<<k[i]; g<<endl;
34
35 C=0;
36 for (i=1; i<=9; i++)
37 if (k[i])
38 C++;
39 g<<C<<endl;
40
41 MAX=floor(sqrt(N));
42 g<<MAX<<endl;
43
44 for (i=1; i<9; i++)
45 for (j=i+1; j<=9; j++)
46 if (k[i]<k[j])
47 {
48 x=k[i];
49 k[i]=k[j];
50 k[j]=x;
51 x=indici[i];
52 indici[i]=indici[j];
53 indici[j]=x;
54 }
55 p=1;
56 for (i=1; i<=9; i++)
57 for (j=1; j<=k[i]; j++)
58 {
59 v[p]=indici[i]; p++;
60 }
61 // for (i=1; i<=N; i++) g<<(int)v[i]; g<<endl;
62
63
64 i=1;
65 while (i<=MAX*MAX)
66 {
67 g<<(int)v[i];
68 if (i%MAX==0)
69 g<<endl;
70 i++;
71 }
72
73 g.close();
74 return 0;
75 }
CAPITOLUL 26. ONI 2010 26.3. JOC - ONI 2010 365
”Instalare” C++
Instalarea este foarte uşoară (este de tipul ”next -> next -> ... -> next”) iar pe in-
ternet sunt multe site-uri de ajutor. De exemplu:
https://www.pbinfo.ro/?pagina=intrebari-afisare&id=26
https://www.youtube.com/watch?v=CLkWRvAwLO8
https://infoas.ro/lectie/112/tutorial-instalare-codeblocks-usor-introducere-in-in
https://www.competentedigitale.ro/c/oji2019/Kit_OJI_2017.rar
367
APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 368
A.1.1 Code::Blocks
Pentru versiuni mai noi, de Code::Blocks şi compilatoare, se poate accesa site-ul
http://www.codeblocks.org/downloads/binaries
de unde se poate descărca, de exemplu, codeblocks-20.03mingw-setup.exe.
Versiuni mai vechi, dar foarte bune, se pot descărca de la adresa
26
Code::Blocks este un IDE (integrated development environment) pentru C/C++, un fel de Notepad ... mai
sofisticat, cu multe butoane care lansează ı̂n execuţie diverse programe, de exeplu g++.exe
27
g++.exe este compilatorul de C++, programul care va verifica dacă instrucţiunile noastre sunt ok sau nu ...
şi care ne va supăra mereu cu erorile pe care ni le arată ... ... Este “o mică artă” să ı̂nţelegem mesajele de
eroare pe care le vedem pe ecran şi să fim ı̂n stare să “depanăm” programele noastre!
APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 369
http://www.codeblocks.org/downloads/source/5
Mai precis:
https://sourceforge.net/projects/codeblocks/files/Binaries/20.03/
http://sourceforge.net/projects/codeblocks/files/Binaries/17.12
http://sourceforge.net/projects/codeblocks/files/Binaries/16.01
De preferat este să avem cel puţin două partiţii: C:¯, D:¯, ... şi să “lăsăm ı̂n pace” partiţia C:¯
pentru sistemul de operare şi programele instalate!
În figura de mai sus se poate observa că pe D:¯ există un folder de lucru pentru programele ı̂n
C++, folder care se numeşte Programe C++. Aici vom salva toate programele C++ pe care
le vom scrie, eventual organizate pe mai multe subfoldere.
Click-dreapta cu mouse-ul şi selectăm “New -¿ Text document” ca ı̂n figura următoare.
APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 370
Dacă vom executa două click-uri pe numele fşierului p01.cpp sau un click pentru a marca
fişierul şi apoi un ¡Enter¿, se va declanşa Code::Blocks cu p01.cpp ı̂n fereastra de editare şi, ce
este şi mai important, cu Programe C++ ca folder curent de lucru pentru Code::Blocks.
Adică, aici vor apărea toate fişiere generate de Code::Blocks pentru p01.cpp.
Figura A.9: Pregătit pentru a scrie cod de program C++ ı̂n Code::Blocks
APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 372
Dacă avem fişierele p01.cpp, ..., p05.cpp, ı̂n folderul nostru de lucru, şi facem dublu-click pe
fiecare ... vor apărea toate ...
A.2 winlibs
A.2.1 GCC şi MinGW-w64 pentru Windows
Se descarcă de la
http://winlibs.com/#download-release
unul dintre fişierele:
winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r
3.7z dimensiune fişier = 148 MB
winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r
3.zip dimensiune fişier = 324 MB
winlibs-x86_64-posix-seh-gcc-10.2.0-mingw-w64-8.0.0-r3.7z dimensiune
fişier = 52.1 MB
winlibs-x86_64-posix-seh-gcc-10.2.0-mingw-w64-8.0.0-r3.zip dimensi-
une fişier = 141 MB
A.2.2 PATH
Trebuie pusă ı̂n PATH calea pentru D:\mingw64\bin\. În “Type here to search” scrieţi: path
şi apoi click pe “Edit the system environment variables”, ca ı̂n figura următoare:
APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 378
Se selecteaza “Path” şi click pe “Edit”. Apare fereastra “Edit Environment Variables”
C:¯path
Dacă totul este OK atunci se trece la instalarea IDE-ului preferat (Integrated Development
28
Environment ), de exemplu Code::Blocks 20.03 (sau Eclipse, Visual Studio Code, Dev C++,
NetBeans, şi altele).
A.2.3 CodeBlocks
CodeBlocks se poate descărca de la http://www.codeblocks.org/downloads/26. Sunt
mai multe variante dar eu am descărcat numai codeblocks-20.03-setup.exe care are 35.7 MB.
La instalare am lăsat totul implicit, deci ... Next, Next, ..., Next până la sfârşit!
La prima lansare ı̂n execuţie este necesară setarea locaţiei compilatorului de C++ (gcc-ul pe
care tocmai l-am instalat!).
28
https://en.wikipedia.org/wiki/Integrated_development_environment
https://ro.wikipedia.org/wiki/Mediu_de_dezvoltare
APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 381
Exponenţiere rapidă
În figura B.1 este considerat numărul nr 234 care ı̂n baza 2 se scrie sub forma 11101010 (celula
C10).
Pe R3 (rândul 3) este arătat ce se ı̂ntâmplă cu nr atunci când se fac ı̂mpărţiri succesive prin
baza 10: se ”şterge” ulima cifră (care este egală cu nr%10 adică ultima cifră este de fapt restul
ı̂mpărţirii lui nr la baza 10).
Pe R10 (rândul 10) este arătat ce se ı̂ntâmplă cu nr atunci când se fac ı̂mpărţiri succesive prin
baza 2: se ”şterge” ulima cifră (care este egală cu nr%2 adică ultima cifră este de fapt restul
ı̂mpărţirii lui nr la baza 2, la fel cum se ı̂ntâmplă ı̂n baza 10).
Observaţia 1. Cifrele se obţin ı̂n ordine inversă. Prima cifră obţinută ca rest este de fapt ultima
cifră din număr (vezi R4 şi R11).
Pe R6 şi R16 sunt precizate puterile bazei.
Valoarea numărului nr este suma produselor dintre cifre şi puterile corespunzătoare:
ı̂n baza 10: 4*1 + 3*10 + 2*100 = 234 (R3 şi R6)
ı̂n baza 2: 0*1 + 1*2 + 0*4 + 1*8 + 0*16 + 1*32 + 1*64 + 1*128 = 234 (R13 şi R16)
390
APPENDIX B. EXPONENŢIERE RAPIDĂ B.2. NOTAŢII, RELAŢII ŞI FORMULE 391
2 2 2 4 2 8 2 16
a0 a a1 a0 a a2 a1 a a3 a2 a a4 a3 a
2 32 2 64 2 128
a5 a4 a a6 a5 a a7 a6 a
Dacă notăm ek ”exponentul (puterea)” la care apare ak ı̂n produs, atunci putem observa
uşor că şirul e0 , e1 , e2 , e3 , ... se obţine prin ı̂mpărţiri succesive ale lui n prin 2 şi preluı̂nd restul
rezultatului. Pentru a folmaliza acest lucru vom considera şirul n0 , n1 , n2 , n3 , ... definit astfel:
n0 n,
w
nk nk1 ©2 (câtul ı̂mpărţirii!) k '1
Folosind aceste notaţii, putem scrie:
~
n0 n;
a0 a;
e n0 %2 " r0, 1x;
0
1 a0 , dacă e0 1;
p0
e
a00 sau, altfel scris: p0 w
1, dacă e0 0;
(B.2.1)
nk nk1 ©2 k ' 1; nk1 j 0 desigur ! ... dar şi nk1 j 1
ak1 , k ' 1;
2
ak
ek nk %2 " r0, 1x, k ' 0;
pk1 ak , k ' 0, dacă ek 1; ak ak modifică produsul pk1
1
p w
k k ' 0, dacă ek 0; ak 1 nu modifică produsul pk1
0
pk1 ,
B.4 Codul
Codul pentru relaţiile (B.2.1) devine:
Observaţia 2. În acest cod actualizarea lui p se face după actualizările pentru a şi n.
Observaţia 3. În codul următor actualizarea lui p se face ı̂naintea actualizărilor pentru a şi n,
corespunzător relaţiilor (B.4.2).
APPENDIX B. EXPONENŢIERE RAPIDĂ B.4. CODUL 393
~
iniţializări:
p1 1;
n1 n;
a1 a;
calcul pentru k ' 0:
e
k nk1 %2 " r0, 1x; k ' 0 (B.4.2)
pk1 ak1 , k ' 0, dacă ek 1; ak1
1
ak1 modifică produsul pk1
k w
p
k ' 0, dacă ek 0; ak1
0
pk1 , 1 nu modifică produsul pk1
actualizări k ' 0:
a ak1 , k ' 0;
2
k
nk nk1 ©2 k ' 0; şi nk1 j 0 desigur !
APPENDIX B. EXPONENŢIERE RAPIDĂ B.4. CODUL 394
Observaţia 4. Instrucţiunile care sunt ”ı̂n plus” se pot elimina. Codul următor arată acest lucru:
Observaţia 5. Produsul poate deveni foarte mare şi din cauza asta se cere rezultatul modulo un
număr prim. Codul următor arată acest lucru:
14 a = (a * a)%MOD;
15 n = n / 2;
16 nropr=nropr+6; // n%2, p*a, a*a, (a * a)%MOD si n/2
17 }
18 return p;
19 }
20
21 int main()
22 {
23 int a=1234;
24 int n=1e+9; // 10ˆ9
25 int rezn; // rezultat exponentiere naiva
26
27 rezn=exponentiere_rapida(a,n);
28
29 cout<<"rezr = "<<rezn<<" nropr = "<<nropr<<"\n";
30
31 return 0;
32 }
33 /*
34 rezr = 376 nropr = 180
35
36 Process returned 0 (0x0) execution time : 0.021 s
37 Press any key to continue.
38 */
Numărul de operaţii:
cu metoda naivă acest număr este 2 000 000 000
cu metoda rapidă este 180.
Iar ca număr de operaţii ... una este să faci 2 miliarde de operaţii şi alta este să faci
numai 180 de operaţii de acelaşi tip (de fapt sunt numai 30 de paşi dar la fiecare pas se fac 5
sau 6 operaţii aritmetice)!
29
şi nu mai trebuie ”atâtea formule matematice”!
29
Este o glumă!
Index
18
10 , 197 k ¡¡ 1LL, 12
log2 , 3
++V[M], ++i;, 17 lexicografic, 269, 276
Şmenul lui Mars, 195 Liceul Militar Dimitrie Cantemir, vi
şiruri de caractere, 300 long long, 64, 196
1LL, 12
my max, 17
a, 191 ((a ¿ b) ? a : b);, 17
algoritm de tip succesor, 191
algoritmul lui Euclid, 3 nrD, 23
assert, 11, 27 nrDiv, 28, 29
număr palindrom, 349
backtracking, 191 numărul de divizori, 22, 214
biblioteca cstring, 300
biblioteca cmath, 197 pair, 25
bordare matrice, 223, 293, 361 permutare, 269
pregenerare, 206
căutare binară, 8, 12, 185, 197 pregenerare numere prime, 22
cbrt, 197
CINOR, vi relaţie de ordine, 235
ciur(), 23, 25
ciurul lui Eratostene, 22, 197, 205 second, 25
codul ASCII, 200 secvenţă, 269
concatenare, 195 short, 27
criteriile de divizibilitate, 266 sort, 30
cu 11, 266 sortare, 235, 310
cu 13, 266 sqrt, 11, 197
cu 2, 266 strtok, 300
cu 3, 266 struct, 26, 27, 34, 40
cu 4, 266 sumă parţială, 183
cu 5, 266 suma lui Gauss, 270
cu 7, 266 suma pătratelor, 11
cu 8, 266 sume parţiale, 191
cu 9, 266 sume parţiale 2D, 183
descompunere ı̂n factori, 196 tablou bidimensional, 293
descompunere ı̂n factori primi, 214 timp logaritmic, 8
tipul caracter, 345
Eratostene(), 28, 29
tipul int, 220
factorizare, 3 tipul long, 220
first, 25 tipul long long, 35, 220
funcţii standard, 300 token, 300
trage cu tunul, iv
getline, 300
Universitatea Ovidius, vi
i
=1, 16 vector, 3
I.d.k.: vector de frecvenţă, 22, 187, 200, 235, 273,
I don’t know who the author is., v 285
398
Bibliografie
[1] Aho, A., Hopcroft, J., Ullman, J.D.; Data strutures and algorithms, Addison Wesley, 1983
[2] Andreica M.I.; Elemente de algoritmică - probleme şi soluţii, Cibernetica MC, 2011
[3] Andonie R., Gârbacea I.; Algoritmi fundamentali, o perspectivă C++, Ed. Libris, 1995
[4] Atanasiu, A.; Concursuri de informatică. Editura Petrion, 1995
[5] Bell D., Perr M.; Java for Students, Second Edition, Prentice Hall, 1999
[21] Knuth, D.E.; The art of computer programming, vol. 4A: Combinatorial algorithms, Part 1,
Addison Wesley, 2011.
[22] Lambert,K. A., Osborne,M.; Java. A Framework for Programming and Problem Solving,
PWS Publishing, 1999
[23] Laaksonen A.; Guide to competitive programming, Springer, 2017
[24] Livovschi, L.; Georgescu H.; Analiza şi sinteza algoritmilor. Ed. Enciclopedică, Bucureşti,
1986.
[25] Niemeyer, P., Peck J.; Exploring Java, O’Reilly, 1997.
399
BIBLIOGRAFIE BIBLIOGRAFIE 400
[26] Odăgescu, I., Smeureanu, I., Ştefănescu, I.; Programarea avansată a calculatoarelor personale,
Ed. Militară, Bucureşti 1993
[27] Odăgescu, I.; Metode şi tehnici de programare, Ed. Computer Lobris Agora, Cluj, 1998
[28] Popescu Anastasiu, D.; Puncte de articulaţie şi punţi ı̂n grafuri, Gazeta de Informatică nr.
5/1993
[29] Răbâea, A.; https://math.univ-ovidius.ro/Doc/Admitere/CentruPregatire
/2007/Info/Lista_probleme_2000-2007.pdf
[30] Răbâea, A.; https://math.univ-ovidius.ro/Doc/Admitere/CentruPregatire
/2007/Info/Rezolvari_C09.pdf
402
What’s the next?
ORNL’s Frontier First to Break the Exaflop Ceiling
Over time
the following steps
will lead you to the value
you seek for yourself
now!