Sunteți pe pagina 1din 425

Informatică

Olimpiada - cls6

2022-12
PROBLEME DE INFORMATICĂ

date la olimpiade

OJI + ONI
ı̂n

**** **** 2022 2021 2020


2019 2018 2017 2016 2015
2014 2013 2012 2011 2010

... draft (ciornă) ...


*** Nobody is perfect ***

Adrian Răbâea, Ph.D.

*** https://en.wikipedia.org/wiki/Saint_Stephen#Eastern_Christianity ***

2022-12-27
Dedication

I would like to dedicate this book ...

a ”to myself” ...


1
2
in a time when ...
3
I will not be able ... ”to be”
That is because ...
4
”When I Die Nobody Will Remember Me”

a to people impacted by the book


a to my nephew Adam.

( 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

... restricţiile de memorie, din enunţurile problemelor, par ’ciudate’ acum!).


În perioada 2017-2020 cele mai puternice calculatoare din lume au fost: ı̂n noiembrie 2017
10
ı̂n China, ı̂n noiembrie 2019 ı̂n SUA şi ı̂n iunie 2020 ı̂n Japonia. În iunie 2022 ”Frontier”
5
Se poate observa din ”Coduri sursă” că orice problemă are numeroase soluţii, atât ca algoritmi de rezolvare
cât şi ca stil de programare! Studiind aceste coduri ... avem ce ı̂nvăţa ... deşi uneori pare că ’se trage cu tunul’ ...
6
IOI2019 şi IOI2020 au a permis utilizarea limbajelor de programare C++ şi Java
7
IOI2015 a permis utilizarea limbajelor de programare C++, Java, Pascal, Python şi Rubi (...)
8
Vezi cele 5 secunde pentru Timp maxim de executare/test din problema ”avârcolaci” - ONI2014 clasa a 11-a
9
https://en.wikipedia.org/wiki/Computer
10
https://www.top500.org/lists/top500/2022/06/

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

Bistriţa, 27th December 2022 Adrian Răbâea


11
https://en.wikipedia.org/wiki/Metric_prefix/
12
https://en.wikipedia.org/wiki/Computer_performance_by_orders_of_magnitude
13
https://ejoi.org/about/
14
https://stats.ioinformatics.org/olympiads/
15
https://en.wikipedia.org/wiki/International_Mathematical_Olympiad
16
https://www.facebook.com/johnwayne/photos/a.156450431041410/2645523435467418/?type=3
”Acknowledgements”

17
”I want to thank God most of all because without God I wouldn’t be able to do any of this.”

Bistriţa, 27th December 2022

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 - ...

telefon: +40 728 zz ll aa +40 363 xx 25 xx


email: adrian1803@gmail.com
Lector universitar - Universitatea Tehnică din Cluj Napoca - Centrul Universitar Nord din Baia
Mare, Facultatea de Ştiinţe, Str. Victoriei, nr. 76, Baia Mare, România, (pensionat: 01.10.2018)
https://stiinte.utcluj.ro/departamente.html
Discipline predate (1992-2018):
Algoritmi şi structuri de date, Algoritmi ı̂n teoria opţiunilor financiare, Bazele matematice
ale calculatoarelor, Bazele tehnologiei informaţiei, Birotică, Capitole speciale de inteligenţă
artificială, Capitole speciale de teoria algoritmilor, Calcul paralel, Informatică economică,
Instruire asistată de calculator, Limbaje de programare; Programare orientată pe obiecte,
Programare procedurală, Structuri de date.
Studii doctorale ı̂n informatică economică - Diplomă de doctor (1997-2002):
Instituţia: Academia de Studii Economice, Bucureşti;
19
Titlul tezei: Algoritmi paraleli şi aplicaţii pe maşini virtual paralele
20
Conducător ştiinţific: Prof. dr. ing. Gheorghe Dodescu
Teme studiate: utilizarea algoritmilor paraleli ı̂n teoria opţiunilor financiare
Studii de specializare ı̂n informatică - Certificat anul V - ’master’ (1978-1979):
Instituţia: Facultatea de matematică şi informatică, Bucureşti;
Titlul tezei: Probleme la limită pentru procese cu creşteri independente şi aplicaţii ı̂n teoria
aşteptării
21
Conducător ştiinţific: Prof. dr. Constantin Tudor
Studii universitare de licenţă ı̂n informatică - Diplomă de licenţă (1974-1978):
Instituţia: Facultatea de matematică şi informatică, Bucureşti;
Titlul tezei: Metode de comparaţie multiplă ı̂n analiza dispersională
22
Conducător ştiinţific: Prof. dr. Ion Văduva
Locuri de muncă: (1979-2018):
- (2018-2009) Universitatea Tehnică din Cluj-Napoca, Centrul Universitar Nord din Baia-
Mare, Facultatea de Ştiinţe, Departamentul de Matematică-Informatică
- (2009-1992) Universitatea ”Ovidius” din Constanţa, Facultatea de Matematică şi Infor-
23
matică, Departamentul de Informatică
24
- (1992-1979) Centrul de Informatică şi organizare CINOR, Bucureşti
25
Olimpiade: (fiind elev la Liceul Militar ”Dimitrie Cantemir” - Breaza, PH)
- 1971: Olimpiada Naţională de matematică: participare (fără rezultat notabil)
- 1970: Olimpiada Naţională de matematică: participare (fără rezultat notabil)
https://scholar.google.com/citations?user=-sSE_1wAAAAJ&hl=en
https://www.scopus.com/authid/detail.uri?origin=resultslist&authorId=56122389200&zone=
http://www.facebook.com/adrian.rabaea
18
https://dmi.cunbm.utcluj.ro/?page_id=2
19
http://opac.biblioteca.ase.ro/opac/bibliographic_view/149021
20
http://www.ionivan.ro/2015-PERSONALITATI/Dodescu.htm
21
http://old.fmi.unibuc.ro/ro/prezentare/promotii/promotia1978informatica_10ani/
22
https://ro.wikipedia.org/wiki/Ion_V%C4%83duva
23
https://fmi.univ-ovidius.ro/
24
http://c3.cniv.ro/?q=2021/cinor/
25
https://www.cantemircml.ro/

vi
Cuprins

Prefaţă iii

Cuprins vii

Lista figurilor xiii

Lista tabelelor xvi

Lista programelor xvii

I OJI - Olimpiada judeţeană de informatică 1


1 OJI 2022 2
1.1 Cmmdc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Vecine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 OJI 2021 - OSEPI 7


2.1 Formula1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2 Seism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

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

7 OJI 2016 104


7.1 cifre - OJI 2016 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
7.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
7.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
7.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
7.2 litere - OJI 2016 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
7.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
7.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
7.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

8 OJI 2015 109


8.1 covor - OJI 2015 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
8.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
8.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
8.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
8.2 ordine - OJI 2015 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
8.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
8.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
8.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123

9 OJI 2014 124


9.1 imprimanta - OJI 2014 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
9.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
9.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
9.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
9.2 munte - OJI 2014 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
9.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
9.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
9.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

10 OJI 2013 142


10.1 cladiri - OJI 2013 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
10.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
10.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
10.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
10.2 galbeni - OJI 2013 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
10.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
10.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
10.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154

11 OJI 2012 155


11.1 cifru - OJI 2012 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
11.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
11.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
11.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
11.2 flori - OJI 2012 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
11.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
11.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
11.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

12 OJI 2011 161


12.1 carte - OJI 2011 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
12.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
12.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
12.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
12.2 grad - OJI 2011 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
12.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
12.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
12.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

13 OJI 2010 174


13.1 loto - OJI 2010 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
13.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
13.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
13.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
13.2 submit - OJI 2010 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
13.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
13.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
13.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178

II ONI - Olimpiada naţională de informatică 179


14 ONI 2022 180
14.1 iluminat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
14.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
14.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
14.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
14.2 inundatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
14.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
14.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
14.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
14.3 siruri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
14.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
14.3.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
14.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188

15 ONI 2021 189


15.1 Butoi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
15.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
15.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
15.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
15.2 Păsări . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
15.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
15.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
15.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
15.3 Puternic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
15.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
15.3.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
15.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197

16 ONI 2020 - suspendat !!! 198

17 ONI 2019 199


17.1 maya - ONI 2019 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
17.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
17.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
17.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
17.2 optime - ONI 2019 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
17.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
17.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
17.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
17.3 roata - ONI 2019 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
17.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
17.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
17.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213

18 ONI 2018 214


18.1 descmult - ONI 2018 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
18.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
18.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
18.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
18.2 gazon - ONI 2018 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
18.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
18.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
18.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
18.3 pietre - ONI 2018 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
18.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
18.3.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
18.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223

19 ONI 2017 224


19.1 faleza - ONI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
19.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
19.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
19.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
19.2 peste - ONI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
19.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
19.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
19.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
19.3 soricel - ONI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
19.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
19.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
19.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264

20 ONI 2016 265


20.1 cod - ONI 2016 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
20.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
20.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
20.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
20.2 perm - ONI 2016 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
20.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
20.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
20.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
20.3 robotel - ONI 2016 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
20.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
20.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
20.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
21 ONI 2015 276
21.1 echer - ONI 2015 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
21.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
21.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
21.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
21.2 lightbot - ONI 2015 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
21.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
21.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
21.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
21.3 teren - ONI 2015 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
21.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
21.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
21.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298

22 ONI 2014 299


22.1 betisoare - ONI 2014 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
22.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
22.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
22.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
22.2 praslea - ONI 2014 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
22.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
22.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
22.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
22.3 tinta - ONI 2014 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
22.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
22.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
22.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329

23 ONI 2013 330


23.1 divizori - ONI 2013 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
23.1.1 *Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
23.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
23.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
23.2 remi - ONI 2013 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
23.2.1 *Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
23.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
23.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
23.3 tetris - ONI 2013 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
23.3.1 *Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
23.3.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
23.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333

24 ONI 2012 334


24.1 cartier - ONI 2012 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
24.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
24.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
24.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
24.2 medalion - ONI 2012 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
24.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
24.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
24.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
24.3 numar - ONI 2012 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
24.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
24.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
24.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
25 ONI 2011 344
25.1 joc - ONI 2011 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
25.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
25.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
25.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
25.2 talent - ONI 2011 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
25.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
25.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
25.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
25.3 xy - ONI 2011 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
25.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
25.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
25.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357

26 ONI 2010 358


26.1 control - ONI 2010 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
26.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
26.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
26.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
26.2 figura - ONI 2010 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
26.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
26.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
26.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
26.3 joc - ONI 2010 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
26.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
26.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
26.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365

Appendix A ”Instalare” C++ 367


A.1 Kit OJI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
A.1.1 Code::Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
A.1.2 Folder de lucru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
A.1.3 Utilizare Code::Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
A.1.4 Setări Code::Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
A.1.5 Multe surse ı̂n Code Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
A.2 winlibs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
A.2.1 GCC şi MinGW-w64 pentru Windows . . . . . . . . . . . . . . . . . . . . . 377
A.2.2 PATH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
A.2.3 CodeBlocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380

Appendix B Exponenţiere rapidă 390


B.1 Analogie baza 2 cu baza 10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
B.2 Notaţii, relaţii şi formule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
B.3 Pregătire pentru scrierea codului! . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
B.4 Codul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
B.5 Chiar este rapidă? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
B.6 Rezumat intuitiv! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396

Index 398

Bibliografie 399

Lista autorilor 402


Lista figurilor

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

7.1 Litere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106

8.1 Covor1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109


8.2 Covor2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
8.3 Ordine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
8.4 Covor1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

9.1 Imprimanta1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124


9.2 Imprimanta2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
9.3 ImprimantaIR2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
9.4 ImprimantaIR2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

10.1 Imprimanta2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

14.1 *** . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

17.1 Maya . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199


17.2 MayaIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
17.3 Optime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
17.4 RoataIR1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
17.5 RoataIR2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

18.1 descmult . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215


18.2 gazon1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
18.3 gazon2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
18.4 piatra1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
18.5 piatra2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223

19.1 peste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234


19.2 soricel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252

20.1 robotel1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271


20.2 robotel2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272

21.1 echer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276


21.2 echer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
21.3 echer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
21.4 lightbot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
21.5 teren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
21.6 teren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293

xiii
22.1 betisoare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
22.2 praslea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
22.3 praslea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
22.4 tinta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
22.5 tinta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322

23.1 remi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331


23.2 tetris . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332

24.1 cartier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334


24.2 medalion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336

25.1 joc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344


25.2 xy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
25.3 xy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353

A.1 Fişierele din Kit OJI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367


A.2 CodeBlocks & C++ Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
A.3 Ce conţine C:¯ OJI ¯ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
A.4 Folder de lucru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
A.5 New -¿ Text document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
A.6 Schimbare nume fişier şi nume extensie fişier . . . . . . . . . . . . . . . . . . . . . . 370
A.7 Confirmare schimbare extensie ı̂n .cpp . . . . . . . . . . . . . . . . . . . . . . . . . 371
A.8 Pregătit pentru Code::Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
A.9 Pregătit pentru a scrie cod de program C++ ı̂n Code::Blocks . . . . . . . . . . . . 371
A.10 Primul cod de program C++ ı̂n Code::Blocks . . . . . . . . . . . . . . . . . . . . . 372
A.11 Build - compilare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
A.12 0 error(s), 0 warning(s) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
A.13 Run - execuţie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
A.14 Executat corect: a făcut “nimic” . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
A.15 Settings  % Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
A.16 Toolchain executables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
A.17 Unde sunt acele programe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
A.18 Multe surse ı̂n Code Blocks - setări . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
A.19 Multe surse in Code Blocks - exemple . . . . . . . . . . . . . . . . . . . . . . . . . 376
A.20 mingw64 pe D: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
A.21 search path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
A.22 System properties –¿ Advanced . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
A.23 Environment Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
A.24 Edit Environment Variables –¿ New . . . . . . . . . . . . . . . . . . . . . . . . . . 379
A.25 Calea şi versiunea pentru gcc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
A.26 Settings –¿ Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
A.27 Toolchain executables –¿ Auto-detect . . . . . . . . . . . . . . . . . . . . . . . . . . 381
A.28 New –¿ Text Document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
A.29 New text Document.txt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
A.30 Schimbare nume şi extensie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
A.31 Moore apps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
A.32 Look for another app . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
A.33 Cale pentru codeblocks.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
A.34 Selectare codeblocks.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
A.35 Editare test01.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
A.36 Compilare test01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
A.37 Mesaje după compilare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
A.38 Execuţie test01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
A.39 Rezultat execuţie test01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
A.40 Fişiere apărute după compilare! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
A.41 Creare test02.cpp gol! + ¡dublu click¿ sau ¡Enter¿ . . . . . . . . . . . . . . . . . . 387
A.42 Lista programelor de utilizat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
A.43 Selectare Code::Blocks IDE pentru fişierele .cpp . . . . . . . . . . . . . . . . . . 388
A.44 Editare+Compilare+Execuţie pentru test02 . . . . . . . . . . . . . . . . . . . . . 388
A.45 Selectare tab ce conţine test01.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 389
B.1 Analogie B2 cu B10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
Lista tabelelor

18.1 descmult . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215

21.1 echer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277

xvi
Lista programelor

2.1.1 formula1 arisanu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9


2.1.2 formula1 muntean.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.3 formula1 lica.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2.1 seism iordaiche.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.2 seism lica.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2.3 seism timplaru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.4 seism chichirim.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.1.1 f marinel ciur c.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.1.2 Cris forta.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.1.3 f marinel ciur.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.1.4 f marinel ciur assert.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.1.5 forta ciur.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.1.6 forta ciur sort 5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.1.7 putere RT.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.2.1 marinel furnica c.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.2.2 furnica cpp RT.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.2.3 furnica sol.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.2.4 furnica sol assert.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.2.5 furnicaRC.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.2.6 marinel furnica.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.1.1 album Flavius.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.1.2 album Roxana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.1.3 album VG.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
4.1.4 album2 VG.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.1.5 albumAdyN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
4.1.6 albumPLV.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
4.2.1 maximFB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
4.2.2 maximFBB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
4.2.3 maximPLV.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
4.2.4 maximPLV01cerinta1sort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
4.2.5 maximPLV02sort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
4.2.6 maximPR.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.2.7 maximR1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
4.2.8 maximR2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
5.1.1 numere cpp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
5.1.2 numere1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
5.1.3 numere2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
5.1.4 numere3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
5.2.1 turnuri.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
5.2.2 turnuri1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
5.2.3 turnuri2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
5.2.4 turnuri3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
5.2.5 turnuri4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
5.2.6 turnuri5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
5.2.7 turnuri6.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
5.2.8 turnuri7.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.2.9 turnuri8.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
6.1.1 accesibil1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
6.1.2 accesibil2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

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

OJI - Olimpiada judeţeană de


informatică

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

Să se determine răspunsul pentru una din următoarele cerinţe:


1. Cel mai mare divizor comun al celor n numere.
2. Cel mai mare divizor comun care se poate obţine alegând exact n - 1 elemente din şir.
3. Cel mai mare divizor comun care se poate obţine alegând exact n - 2 elemente din şir.

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

În fişierul cmmdc.out se va afişa răspunsul pentru cerinţa cerută.

Restricţii şi precizări

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:

cmmdc.in cmmdc.out Explicaţii


1 4 T = 1, deci se cere determinarea celui mai mare divizor comun
5 al celor cinci numere: 48, 40, 20, 16 şi 80.
48 Răspunsul este 4.
40
20
16
80

2
CAPITOLUL 1. OJI 2022 1.1. CMMDC 3

2 8 T = 2, deci se rezolvă cerinţa 2.


5 Eliminând numărul 20, rămân n - 1 = 4 numere, iar cmmdc(16,
48 48, 40, 80) = 8, care este şi maximul posibil.
40
20
16
80
3 20 T = 3, deci se rezolvă cerinţa 3. Eliminând numerele 16 şi 48
5 rămân n - 2 = 3 numere, iar cmmdc(40, 20, 80) = 20, care este
48 şi maximul posibil.
40
20
16
80

1.1.1 Indicaţii de rezolvare

Propusă de: prof. Dan Pracsiu Liceul Teoretic ”Emil Racoviţă”


Deoarece sunt folositori ı̂n rezolvarea celor trei cerinţe, construim de la ı̂nceput doi vectori de
lungime n, st şi dr cu semnificaţia următoare:
ˆ sti va reţine cel mai mare divizor comun al numerelor a1 , a2 , ..., ai
ˆ dri va reţine cel mai mare divizor comun al numerelor ai , ai1 , ..., an .
Vectorul st se va construi de la stânga la dreapta, iar vectorul dr de la dreapta la stânga, după
relaţiile:
ˆ st1 a1
ˆ sti cmmdc sti1 , ai , pentru 2 & i & n
ˆ drn an
ˆ dri cmmdc dri1 , ai , pentru 1 & i & n  1
Cerinţa 1.
Soluţie brută. Se calculează cmmdc-ul prin factorizare, sau se caută manual cmmdc-ul şi se
verifică dacă acesta este divizor pentru fiecare element din şir şi se păstrează maximul găsit dintre
toţi candidaţii.
Pentru această rezolvare brută a primei cerinţe, se pot obţine 16 puncte.
Soluţie optimă. Dacă se foloseş te algoritmul lui Euclid pentru calcularea soluţiei, răspunsul
este stn (sau dr1 ).
Complexitatea temporală este O n log2 max.
Pentru rezolvarea corectă a primei cerinţe, se pot obţine 36 de puncte.
Cerinţa 2.
Soluţie brută. Se calculează pentru fiecare 1 & i & n, care este cmmdc-ul dacă eliminăm
elementul ai şi se păstrează rezultatul maxim.
2
Complexitatea temporală este O n log2 max.
Pentru rezolvarea brută a celei de-a doua cerinţe, se pot obţine 20 de puncte.
Soluţie optimă. Trebuie să aflăm cmmdc-ul maxim dacă se elimină exact un număr din şir.
Pentru a realiza acest lucru, parcurgem şirul şi pentru fiecare poziţie i:
ˆ dacă se elimină a1 , atunci cel mai mare divizor comun este dr2
ˆ dacă se elimină an , atunci cel mai mare divizor comun este stn1
ˆ dacă se elimină ai , pentru 2 & i & n  1, atunci cel mai mare divizor comun al numerelor
rămase este cmmdc sti1 , dri1 
Dintre toate aceste valori determinate aflăm maximul.
Complexitatea temporală este O n log2 max.
Pentru rezolvarea corectă a celei de-a doua cerinţe, se pot obţine 42 de puncte.
Cerinţa 3.
Soluţie brută. Se calculează pentru fiecare pereche ordonată 1 & i $ j & n, care este
cmmdc-ul dacă eliminăm elementul ai şi aj şi se păstrează rezultatul maxim.
CAPITOLUL 1. OJI 2022 1.2. VECINE 4

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 :

M max cmmdc a1 , a2 , ..., ai1 , cmmdc ai1 , ..., aj 1 , cmmdc aj 1 , ..., an 


2
Complexitatea temporală este O n log2 max.
Pentru rezolvarea corectă a primei cerinţe, se pot obţine 22 de puncte.

1.1.2 *Cod sursă

1.1.3 *Rezolvare detaliată

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

Cunoscându-se şirul de cifre iniţial, să se obţină următoarele rezultate:


1. Presupunând că nu se face nici o lipire de cifre, fiecare cifră devenind un număr ı̂n şir, adică
ai ci , să se determine câte perechi de numere vecine consecutive există ı̂n şir;
2. Să se determine o modalitate de lipire a cifrelor astfel ı̂ncât să se obţină cele mai mari două
numere vecine consecutive şi să se afişeze primul dintre aceste numere.

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.

Restricţii şi precizări

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.

1.2.1 Indicaţii de rezolvare

Propusă de: prof. Rodica Pintea - Liceul Teoretic ”Radu Vlădescu”


Cerinţa 1. Două cifre alăturate din şir, ci şi ci1 , sunt consecutive dacă ci  1 ci1 , pentru
orice 1 & i & n  1. Se parcurgeşirul de cifre şi se contorizează aceste perechi.
Complexitatea temporală este O n.
Pentru rezolvarea corectă a primei cerinţe, se pot obţine 20 de puncte.
Cerinţ a 2. Două numere sunt vecine dacă sunt consecutive şi dacă primul număr este cu
exact 1 mai mare decât cel de-al doilea.
O observaţie ce trebuie făcută este că două numere consecutive au fie acelaşi număr de cifre, fie
diferă prin 1. Cazurile când numărul cifrelor diferă sunt când primul număr este de forma 99...9 ,
ÍÒÒ Ò Ò Ò ÒÑ Ò Ò Ò Ò Ò Ï
de k ori
iar cel de-al doilea este de forma 1 0...0 .
ÍÒÒ Ò ÒÑ Ò Ò Ò Ï
de k ori
Astfel, problema se poate rezolva cu următorul algoritm:
(1) Pentru fiecare 1 & k & 10 fixăm lungimea primului număr la k.
(2) Pentru fiecare poziţie posibilă 1 & i & n  2k  1, se verifică dacă X  1 Y , unde
X ci ci1 ci2 ...cik1 şi Y cik cik1 cik2 ...ci2k1 , dacă X şi Y au acceaşi lungime
(3) Pentru fiecare poziţie posibilă 1 & i & n  2k, se verifică dacă X  1 Y , unde X =
ci ci1 ci2 ...cik1 şi Y cik cik1 cik2 ...ci2k , dacă Y are cu o cifră mai mult decât X.
(4) dacă unul dintre cazurile de mai sus sunt adevărate se actualizează maximul găsit cu X,
dacă este cazul.
Complexitatea temporală a acestui algoritm este O n kmax, unde kmax 10, reprezintă
lungimea maximă posibilă a unui număr.
CAPITOLUL 1. OJI 2022 1.2. VECINE 6

1.2.2 *Cod sursă

1.2.3 *Rezolvare detaliată


Capitolul 2

OJI 2021 - OSEPI

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.

Figura 2.1: formula1

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

Restricţii şi precizări

a 1 & K & 100 000


a 1 & N & 500 000
a Pentru rezolvarea corectă a primei cerinţe se obţin 20 de puncte, iar pentru rezolvarea corectă
a celei de a doua cerinţe se obţin 80 de puncte.

Exemple:

formula1.in formula1.out Explicaţii


1 25 Se rezolva prima cerinţă şi se va folosi doar valoarea K.
34 Steguleţul celei de a treia maşini are 25 de pătrăţele albe şi negre
ı̂n total.
2 81 Se rezolvă a doua cerinţă şi se va folosi doar valoarea N .
34 Pe steguleţele primelor 4 maşini apar, ı̂n total, 0+4+12+24=40
pătrăţele albe. Cel mai mare steguleţ care conţine cel mult 40
de pătrăţele albe aparţine maşinii cu numărul 5 care are ı̂n total
81 de pătrăţele.

Timp maxim de executare/test: 1.0 secunde


Memorie: total 16 MB din care pentru stivă 8 MB
Dimensiune maximă a sursei: 10 KB

2.1.1 Indicaţii de rezolvare


Propunător: Prof. Ana-Maria Arişanu, Colegiul Naţional ”Mircea cel Bătrân”, Rm. Vâlcea
2
1. Steguleţul maşinii cu numărul k are 2k  1 pătrăţele
2. Numărul de pătrăţele albe de pe steguleţul maşinii cu numărul k este:
2
2k  1  1 2
k 2k  2 2k  2k (2.1.1)
2
Prin urmare:

2 2 2 2
A 2˜1  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)

Valoarea lui A se poate determina ı̂n 2 moduri:


a iterativ (un for de la 1 la N )
N N 1˜ 2N 1 N N 1 N N 1˜ 2N 1
a cu formula A 2˜ 2˜  N N  1
6 2 3
Ambele modalităţi de calcul iau 100 de puncte.
Presupunem că cel mai mare steguleţ care are cel mult A pătrăţele albe aparţine maşinii cu
2 2
numărul x. Astfel, acest steguleţ va avea 2x  1 pătrăţele ı̂n total, dintre care2x  2x albe.
Prin urmare, x se determină ca fiind cel mai mare număr impar cu proprietatea că 2x¶ 2x & A.
2

Determinarea lui x se poate face ı̂n următoarele moduri:


ˆ Pornim iterativ cu x de la 1 pană la cel mai mare x care ı̂ncă respectă 2x
2
 2x & A. (
scor obţinut: 70-80 de puncte)

ˆ 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

2.1.2 Cod sursă

Obs: https://ebooks.infobits.ro/culegere_OJI_2021.pdf

Listing 2.1.1: formula1 arisanu.cpp


1 /*
2 2.1. Autor Prof. Miana Arisanu
3 algoritm liniar, 70-80 puncte
4 */
5 #include <fstream>
6 using namespace std;
7
8 ifstream f("formula1.in");
9 ofstream g("formula1.out");
10
11 int main()
12 {
13 unsigned long long N, P, k, A,x;
14 f>>P>>k>>N;
15
16 if (P==1)
17 g<<(2*k-1)*(2*k-1);
18 else
19 {
20 A=N*(N+1)*(2*N+1)/3- N*(N+1);
21 // x = numarul masinii care are A stegulete albe
22 x=1;
23 while (2*x*x-2*x<=A)x++;
24 x--;
25 // pentru eficienta x se determina direct cu formula sau se cauta binar
26 g<<(2*x-1)*(2*x-1)<<’\n’;
27 }
28 }
29 \index{unsigned}
30 \index{unsigned!long long}
31
32
33
34 \begin{lstlisting}[language=C++,commentstyle=\color{purple}, caption={concurs\_timplaru.
cpp}]
35 /*
36 2.2. Autor Roxana Timplaru
37 */
38 #include <fstream>
39 #include <cmath>
40
41 using namespace std;
42
43 ifstream fin("formula1.in");
44 ofstream fout("formula1.out");
45
46 int k,n;
47
48 void cerinta_1()
49 {
50 long long s=1;
51 s=s+2*(k-1);
52 fout<<s*s;
53 }
54
55 void cerinta_2()
56 {
57 long long s,a,i,x;
58 s=0;a=1;
59 for(i=1;i<=n;i++)
60 {
61 x=a*a/2;
62 s=s+x;
63 a=a+2;
64 }
65 a=1;
66 x=0;
67 while (a*a/2<=s)
68 {
CAPITOLUL 2. OJI 2021 - OSEPI 2.1. FORMULA1 10

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 }

Listing 2.1.2: formula1 muntean.cpp


1 /**
2 * 2.3 Autor sursa: Radu Muntean
3 * Complexitate: O(1)
4 * Scor: 100 puncte
5 *
6 */
7 #include <fstream>
8 #include <assert.h>
9 #include <cmath>
10
11 using namespace std;
12
13 int main()
14 {
15 ifstream in ("formula1.in");
16 ofstream out ("formula1.out");
17
18 int mode;
19 long long n, k;
20
21 in >> mode >> k >> n;
22 assert(mode > 0);
23 assert(mode <= 2);
24
25 if (mode == 1)
26 {
27 out << (2*k - 1) * (2*k - 1) << "\n";
28 return 0;
29 }
30
31 // A =(1ˆ2-1)/2 + (3ˆ2-1)/2 + ... ((2n-1)ˆ2-1)/2
32 // A =(1ˆ2-1 + 3ˆ2-1 + ... (2n-1)ˆ2-1)/2
33 // A = (1ˆ2 + 3ˆ2 + ... (2n-1)ˆ2
34 // -n)/2
35 // A = (1ˆ2 + 2ˆ2 + 3ˆ2 + ... + (2n-1)ˆ2 - adunam nr pare si impare
36 // 2ˆ2 + 4ˆ2 + ... + (2n - 2)ˆ2 scadem numerele pare
37 // -n) / 2
CAPITOLUL 2. OJI 2021 - OSEPI 2.1. FORMULA1 11

38 // 1ˆ2 + 2ˆ2 + ... + kˆ2 = k * (k+1) * (2k + 1) / 6


39
40 long long A = (1LL * (2*n - 1) * (2*n) * (4*n - 1) / 6 -
41 // suma pentru toate patratele de la 1 la (2n-1)ˆ2
42 4 * (n - 1) * n * (2*n - 1) / 6 - n ) / 2;
43 // suma pentru toate patratele de nr pare
44 // cumul de n ori "-1"
45 long long x = sqrt(A * 2 + 1);
46 // A reprezinta numarul maxim de patratele albe.
47 if (x % 2 == 0)
48 {
49 x --;
50 }
51 out << x*x << "\n";
52 return 0;
53 }

Listing 2.1.3: formula1 lica.cpp


1 /*
2 2.4. Autor Prof. Daniela Lica
3 Solutie de 100 de puncte folosind cautarea b i n a r la c e r i n a 2
4 */
5 #include <fstream>
6
7 using namespace std;
8
9 ifstream f("formula1.in");
10 ofstream g("formula1.out");
11
12 int P, N, K;
13
14 void Read()
15 {
16 f >> P >> K >> N;
17 return;
18 }
19
20 long long cnt (int k)
21 {
22 return (1LL * (1LL * (k << 1LL) - 1LL) * 1LL * ((k << 1LL) - 1LL));
23 }
24
25 void Task_1 ()
26 {
27 g << cnt(K) << ’\n’;
28 return;
29 }
30
31 ///cautare b i n a r a rezultatului
32 void Task_2 ()
33 {
34 long long total = 0;
35 for(int k = 1; k <= N; ++k)
36 total += 1LL * (cnt(k) >> 1LL);
37
38 long long Keep = 0;
39 int Left = 1, Right = 1e8;
40 while(Left <= Right)
41 {
42 int Mid = ((Left + Right) >> 1);
43 if((cnt(Mid) >> 1LL) <= total)
44 Keep = cnt(Mid), Left = Mid + 1;
45 else
46 Right = Mid - 1;
47 }
48 g << Keep << ’\n’;
49 return;
50 }
51
52 void Solve ()
53 {
54 if(P == 1)
55 Task_1();
56 else
CAPITOLUL 2. OJI 2021 - OSEPI 2.2. SEISM 12

57 Task_2();
58 return;
59 }
60
61 int main()
62 {
63 Read();
64 Solve();
65 return 0;
66 }

2.1.3 *Rezolvare detaliată

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.

Restricţii şi precizări

ˆ 5&N & 100 000


ˆ 1 secundă & durata unui seism & N  4 secunde
ˆ Pentru cerinţele 1 şi 2 se garantează că seismograful a detectat cel puţin un seism.
CAPITOLUL 2. OJI 2021 - OSEPI 2.2. SEISM 13

ˆ 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:

seism.in seism.out Explicaţii


1 4 Durata maximă a unui seism este de 4
21 secunde.
0011110000010100110
01
2 3 Seismograful a ı̂nregistrat 3 seisme.
21 Primul seism are durata de 4 secunde,
0011110010010100110 al doilea are durata de 1 secundă şi ul-
01 timul are durata de 2 secunde.
3 4 Elementul din şir de pe poziţia 5 se
8 schimbă ı̂n 1 şi se obţine un seism de
00110100 durată 4 secunde.
3 5 Se schimbă ı̂n 1 semnalele asociate se-
14 cundelor 6, 7, 8, 9 şi 10 şi se obţine un
01100000000010 seism de durată 5 secunde.

Timp maxim de executare/test: 1.0 secunde


Memorie: total 16 MB din care pentru stivă 8 MB
Dimensiune maximă a sursei: 10 KB

2.2.1 Indicaţii de rezolvare


Propunător: Prof. Cristina Iordaiche, Liceul Teoretic ”Grigore Moisil”, Timişoara
Cerinţele 1 şi 2 Notăm vectorul de valori transmise cu v.
O soluţie ar fi să parcurgem şirul celor N semnale şi să ne oprim la fiecare poziţie i unde
v i 1, v i  1 0 şi v i  2 0. În continuare trebuie analizat dacă acest i poate fi capătul
din stânga al unui seims. Putem găsi exact porţiunea formată din valori alăturate de 1 prin
iterarea la dreapta a unui j ce porneşte din i şi avansează atâta timp cât v j  1. Apoi, dacă
v j  1 0 şi v j  2 0, atunci secvenţa i; j  este un seims valid.
Cu această abordare putem trece prin absolut toate seismele şi calcula care este cel de durată
maximă (cerinţa 1). În cazul cerinţei 2 trebuie doar să contorizăm numărul de seisme găsite.
Soluţia descrisă are complexitate O n şi obţine punctajul maxim pe primele 2 cerinţe.
Motivaţia complexităţii liniare este că j-ul ı̂ncepe mişcarea la dreapta doar după ce am fixat
capătul stânga al unei secvenţe de 1, iar secvenţele de 1 nu se pot suprapune.
Cerinţa 3 Pentru corectarea erorilor transmise de seismograf, analizăm fiecare secvenţa din
şir ce este formată doar din zerouri. Notăm capetele secvenţei analizate: i1 şi i2 . Identificăm 4
cazuri de modalităţi de corectare:
a Cazul 1 ı̂nlocuim toate zerourile din secvenţa găsită cu valori de 1. Figura 2.2 prezintă cum
ne putem deplasa la stânga până la j1 şi la dreapta până la j2 atâta timp cât trecem numai prin
valori de 1. Verificăm apoi dacă secvenţa cu capetele ı̂n j1 şi j2 are ı̂n stânga şi ı̂n dreapta sa cel
puţin două elemente de 0. În caz afirmativ am identificat un seism şi ı̂i calculăm durata.

Figura 2.2: Cazul 1, transformare a tuturor elmentelor din i1 ; i2  ı̂n 1


CAPITOLUL 2. OJI 2021 - OSEPI 2.2. SEISM 14

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.

Figura 2.3: Cazul 2, transformare a zerourilor din i1  2; i2  2 ı̂n 1

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.

Figura 2.4: Cazul 3, transformare a zerourilor din i1 ; i2  2 ı̂n 1

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

Figura 2.5: Cazul 4, transformare a zerourilor din i1  2; i2  ı̂n 1

Complexitatea finală de evaluare a tuturor celor 4 cazuri este O n.

2.2.2 Cod sursă

Obs: https://ebooks.infobits.ro/culegere_OJI_2021.pdf

Listing 2.2.1: seism iordaiche.cpp


1 /*
2 3.1 Autor Iordaiche Cristina
3 */
4 #include <fstream>
5
6 using namespace std;
7
8 ifstream fin("seism.in");
9 ofstream fout("seism.out");
10
11 bool v[100001];
12 int N, C, s;
13 int durata_seism, cate_seisme, durata_max;
14
15 int main()
16 {
17 int i,incep_seism,sf_seism,j;
18 fin>>C>>N;
19 for(i=1; i<=N; i++)
CAPITOLUL 2. OJI 2021 - OSEPI 2.2. SEISM 15

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 }

Listing 2.2.2: seism lica.cpp


1 /*
2 3.2 Autor Daniela Lica
3 */
4 #include <fstream>
5 #include <cassert>
6
7 using namespace std;
8
9 ifstream f("seism.in");
10 ofstream g("seism.out");
11
12 const int NMAX = 1e5 + 1;
13 int P, N;
14 bool A[NMAX];
15 int M, V[NMAX];
16 int ans_1, ans_2, ans_3;
17
18 void Read ()
19 {
20 f >> P >> N;
21 for(int i = 1; i <= N; ++i)
22 f >> A[i];
23 return;
24 }
25
26 int my_abs (int x)
27 {
28 if(x < 0)
29 return -x;
30 return x;
31 }
32
33 ///secv en ele de 0 sunt memorate n vectorul V cu valori negative,
34 /// n valoare a b s o l u t egale cu lungimea lor
35 ///secv en ele de 1 sunt memorate n vectorul V cu valori pozitive,
36 ///egale cu lungimea lor
37 void Load ()
38 {
39 M = 0;
40 for(int i = 1; i <= N; ++i)
41 if(A[i] == 0)
42 {
43 V[++M] = 0;
44 while(i <= N && A[i] == 0)
45 ++V[M], ++i;
46 V[M] = -V[M];
47 --i;
48 }
49 else
50 {
51 V[++M] = 0;
52 while(i <= N && A[i] == 1)
53 ++V[M], ++i;
54 --i;
55 }
56 return;
57 }
58
59 int my_max (int a, int b)
60 {
61 return ((a > b) ? a : b);
62 }
63
64 void Task_1 ()
65 {
66 ans_1 = 0;
67 for(int i = 2; i < M; ++i)
CAPITOLUL 2. OJI 2021 - OSEPI 2.2. SEISM 17

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 }

Listing 2.2.3: seism timplaru.cpp


1 /*
2 3.3 Autor Roxana Timplaru
3 */
CAPITOLUL 2. OJI 2021 - OSEPI 2.2. SEISM 18

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

80 maxi1 = max(maxi1, nrz2-4);


81 nrz1 = nrz2;
82 }
83 if (c == 1)
84 fout << maxi;
85 else
86 if (c == 2)
87 fout << k;
88 else
89 fout << maxi1;
90 }
91
92 int main()
93 {
94 fin >> c;
95 cerinte();
96 return 0;
97 }

Listing 2.2.4: seism chichirim.cpp


1 /*
2 3.4. Autor Stelian Chichirim
3 */
4 #include <bits/stdc++.h>
5
6 using namespace std;
7
8 const int Nmax = 1e5;
9 int v[Nmax + 10];
10
11 int main()
12 {
13 freopen("seism.in", "r", stdin);
14 freopen("seism.out", "w", stdout);
15
16 int c, n, ans1 = 0, ans2 = 0, ans3 = 0;
17 scanf("%d", &c);
18 scanf("%d", &n);
19 assert(1 <= n && n <= Nmax);
20 assert(1 <= c && c <= 3);
21 for (int i = 1; i <= n; ++i)
22 {
23 scanf("%d", &v[i]);
24 assert(0 <= v[i] && v[i] <= 1);
25 }
26 int last1 = 1, pos1 = 0, last2 = 1, pos2 = 0, nrZero = 0;
27 v[n + 1] = 1;
28 v[0] = 1;
29 for (int i = 1; i <= n; ++i)
30 {
31 if (v[i])
32 {
33 nrZero = 0;
34 if (!v[i-1] or i == 1)
35 {
36 pos2 = pos1;
37 last2 = last1;
38 pos1 = i;
39 last1 = 1;
40 }
41 else
42 last1++;
43 if (!v[pos1 - 1] && !v[pos1 - 2] && !v[i + 1] && !v[i + 2])
44 {
45 ans1 = max(ans1, last1);
46 ans2++;
47 }
48 }
49 else
50 nrZero++;
51 if (nrZero > 4) ans3 = max(ans3, nrZero - 4);
52 if (!v[i] && !v[i - 1] && pos1 > 0)
53 {
54 if (!v[pos1 - 1] && !v[pos1 - 2])
CAPITOLUL 2. OJI 2021 - OSEPI 2.2. SEISM 20

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 }

2.2.3 *Rezolvare detaliată


Capitolul 3

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.

Restricţii şi precizări

a 1 & n & 100 000


a 1 & numerele din şir & 2 000 000 000
a O secvenţă este constituită dintr-un singur număr sau mai multe numere aflate pe poziţii
consecutive ı̂n şir. Lungimea unei secvenţe este egală cu numărul de valori care o compun.
a Pentru prima cerinţă se acordă 50 de puncte, iar pentru cea de a doua cerinţă se acordă 40
de puncte.
a Pentru teste valorând 30 de puncte 1 & n & 10 000

Exemple:

forta.in forta.out Explicaţii

21
CAPITOLUL 3. OJI 2020 3.1. FORTA 22

1 32 Cerinţa este 1. D17={1,17}, D243={1,3,9,27,81,243},


6 D10={1,2,5,10}, D32={1,2,4,8,16,32}, D25={1,5,25},
17 243 10 32 25 13 D13={1,13} Deci cea mai mare forţă este 6, iar numărul
minim cu această forţă este 32.
2 5 Cerinţa este 2. O rearanjare a şirului ar putea fi
8 10 14 15 121 25 49 9 25
121 10 14 25 49 9 25 15 astfel ı̂ncât putem obţine o secvenţă de lungime 3 de
numere de forţă 4 şi o secvenţă de lungime 5 de numere
de forţă 3.

Timp maxim de executare/test: 1.0 secunde


Memorie: total 16 MB din care pentru stivă 8 MB
Dimensiune maximă a sursei: 10 KB

3.1.1 Indicaţii de rezolvare


prof. Raluca Costineanu - Colegiul Naţional ”ştefan cel Mare”, Suceava

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:

1. Identificând şi numărând divizorii ı̂ntr-o parcurgere a tuturor valorilor de la 1 la X


2. Căutând divizorii ”ı̂n pereche”
3. Din factorizarea numărului X, folosind rezultatul nrDiv X  p1  1 ˜ p2  1 ˜ ... ˜ pk  1
p p p
pentru X d11 ˜ d22 ˜ ... ˜ dkk
4. Aplicând rezultatul de la 3, dar folosind pentru factorizare doar numerele prime pregenerate
(folosind eventual ciurul lui Eratostene).

Î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ţă.

3.1.2 Cod sursă

Listing 3.1.1: f marinel ciur c.c


1 //marinel februarie 2020
2 #include <stdio.h>
3
4 FILE *fin, *fout;
5
6 #define dim 100001
7
8 struct elem
9 {
10 int X;
11 short int nrdiv;
12 } divi[dim];
13
14 int X, x, cx, d, cerinta, n, nrd_citit, i, imax, mic, m;
15 int Pmax, nr_max, p, u, cate, cate_max, pmax, umax, Fmax;
16 int F[dim], P[45001];
17 char C[45001];
18
19 int nrD(int n)
CAPITOLUL 3. OJI 2020 3.1. FORTA 23

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 }

Listing 3.1.2: Cris forta.cpp


1 //Cristina Iordaiche
2 #include <fstream>
3 #include <climits>
4
5 using namespace std;
6
7 ifstream fin("forta.in");
CAPITOLUL 3. OJI 2020 3.1. FORTA 24

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 }

Listing 3.1.3: f marinel ciur.cpp


1 //marinel februarie 2020
2 #include <fstream>
3 #include <cstring>
4
5 using namespace std;
6
7 ifstream fin("forta.in");
8 ofstream fout("forta.out");
9
10 #define dim 100001
11
12 struct elem
13 {
14 int X;
15 short int nrdiv;
16 } divi[dim];
17
18 int X, x, cx, d, cerinta, n, nrd_citit, i, imax, mic, m;
19 int Pmax, nr_max, p, u, cate, cate_max, pmax, umax, Fmax;
20 int F[dim], P[45001];
21 char C[45001];
22
23 int nrD(int n)
24 {
25 int k = 1, p, d = 1; //folosesc formula d = (p1+1)(p2+1)...(pk+1)
26 while (P[k] * P[k] <= n) //unde p1 p2...pk sunt puterile factorilor primi
27 { //din descompunere
28 p = 0; //initializez puterea
29 while (n % P[k] == 0) //cat timp se divide cu numarul prim P[k]
30 {
31 n /= P[k]; //imparte
32 p++; //numara
33 }
34 d = d * (p + 1); //formula
35 k++; //trec la alt numar prim
36 }
37 if(n > 1) //daca a mai ramas ceva din n => este numar prim
38 d = d * 2; //deci d se inmulteste cu (1+1) = 2
39 return d; //returnez numarul de divizori
40 }
41
42 void ciur()
43 {
44 int i, j; //pentru determinarea numarului de divizori
45 C[0] = C[1] = 1; //voi folosi DOAR numere prime impare
46 for (i = 2; i < 45001; i ++) //suficient 45001 deoarece
47 if (C[i] == 0) //45000 * 45000 = 2025000000 > 2000000000
48 { //am un numar prim
49 m++; //il numar si
50 P[m] = i; //il salvez apoi elimin multipli
51 for (j = i * i; j < 45001; j += i)
52 C[j] = 1;
53 }
54 }
55
56 int main()
57 {
58 fin >> cerinta; //citire cerinta si
59 fin >> n; //numarul de numere
60 ciur(); //construiesc sirul numerelor prime
61 for (i = 1; i <= n; i++) //iau pe rand cele n numere
62 {
63 fin >> X; //citesc numarul
64 divi[i].nrdiv = nrD(X); //calculez si retin numarul de divizori
65 divi[i].X = X; //retin si numarul
66 F[divi[i].nrdiv]++; //contorizez nr de aparitii a nr de divizori
67 if (F[divi[i].nrdiv] > Fmax) //determin numarul maxim de aparitii
68 Fmax = F[divi[i].nrdiv];
69 if (divi[i].nrdiv > Pmax) //determin si numarul maxim de divizori
70 {
71 Pmax = divi[i].nrdiv; //retin
CAPITOLUL 3. OJI 2020 3.1. FORTA 26

72 nr_max = X; //retin si pentru cine este acesta


73 }
74 else
75 if (divi[i].nrdiv == Pmax) //in caz de egalitate
76 {
77 if (X < nr_max) //caut numarul mai mic
78 nr_max = X;
79 }
80 }
81 if (cerinta == 1)
82 fout << nr_max << ’\n’; //afisez cerinta 1
83 else
84 fout << Fmax << ’\n’; //afisez cerinta 2
85 return 0;
86 }

Listing 3.1.4: f marinel ciur assert.cpp


1 //marinel februarie 2020
2 #include <fstream>
3 #include <cstring>
4 #include <cassert>
5
6 using namespace std;
7
8 ifstream fin("forta.in");
9 ofstream fout("forta.out");
10
11 #define dim 100001
12
13 struct elem
14 {
15 int X;
16 short int nrdiv;
17 } divi[dim];
18
19 int X, x, cx, d, cerinta, n, nrd_citit, i, imax, mic, m;
20 int Pmax, nr_max, p, u, cate, cate_max, pmax, umax, Fmax;
21 int F[dim], P[45001];
22 char C[45001];
23
24 int nrD(int n)
25 {
26 int k = 1, p, d = 1; //folosesc formula d = (p1+1)(p2+1)...(pk+1)
27 while (P[k] * P[k] <= n) //unde p1 p2...pk sunt puterile factorilor primi
28 { //din descompunere
29 p = 0; //initializez puterea
30 while (n % P[k] == 0) //cat timp se divide cu numarul prim P[k]
31 {
32 n /= P[k]; //imparte
33 p++; //numara
34 }
35 d = d * (p + 1); //formula
36 k++; //trec la alt numar prim
37 }
38 if(n > 1) //daca a mai ramas ceva din n => este numar prim
39 d = d * 2; //deci d se inmulteste cu (1+1) = 2
40 return d; //returnez numarul de divizori
41 }
42
43 void ciur()
44 {
45 int i, j; //pentru determinarea numarului de divizori
46 C[0] = C[1] = 1; //voi folosi DOAR numere prime impare
47 for (i = 2; i < 45001; i ++) //suficient 45001 deoarece
48 if (C[i] == 0) //45000 * 45000 = 2025000000 > 2000000000
49 { //am un numar prim
50 m++; //il numar si
51 P[m] = i; //il salvez apoi elimin multipli
52 for (j = i * i; j < 45001; j += i)
53 C[j] = 1;
54 }
55 }
56
57 int main()
CAPITOLUL 3. OJI 2020 3.1. FORTA 27

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 }

Listing 3.1.5: forta ciur.cpp


1 //Raluca Costineanu
2 #include <bits/stdc++.h>
3
4 using namespace std;
5
6 ifstream f("forta.in");
7 ofstream g("forta.out");
8
9 bool ciur[45000];
10 int prime[5000], cate;
11
12 void Eratostene()
13 {
14 for(int i=3; i<=212; i+=2)
15 if(ciur[i]==0)
16 for(int j=i*i; j<45000; j+=i)
17 ciur[j]=1;
18 cate=1;
19 prime[1]=2;
20 for(int i=3; i<45000; i+=2)
21 if(!ciur[i])prime[++cate]=i;
22 }
23
24 int nrDiv(int x)
25 {
26 int k=1,p=0,i=1;
27 while(i<=cate && prime[i]*prime[i]<=x)
28 {
29 while(x%prime[i]==0) x/=prime[i], p++;
30 k*=p+1, i++, p=0;
31 }
32 if(x>1) k*=2;
33 return k;
34 }
35
36 int main()
37 {
38 Eratostene();
39 int C;
CAPITOLUL 3. OJI 2020 3.1. FORTA 28

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 }

Listing 3.1.6: forta ciur sort 5.cpp


1 //Raluca Costineanu
2 #include <bits/stdc++.h>
3
4 using namespace std;
5
6 #define nMax 100010
7
8 ifstream f("forta.in");
9 ofstream g("forta.out");
10
11 bool ciur[45000];
12 int prime[5000], cate;
13
14 void Eratostene()
15 {
16 for(int i=3; i<=212; i+=2)
17 if(ciur[i]==0)
18 for(int j=i*i; j<45000; j+=i)
19 ciur[j]=1;
20 cate=1;
21 prime[1]=2;
22 for(int i=3; i<45000; i+=2)
23 if(!ciur[i])prime[++cate]=i;
24 }
25
26 int nrDiv(int x)
27 {
28 int k=1,p=0,i=1;
29 while(i<=cate && prime[i]*prime[i]<=x)
30 {
31 while(x%prime[i]==0) x/=prime[i], p++;
32 k*=p+1, i++, p=0;
33 }
34 if(x>1) k*=2;
35 return k;
36 }
37
38 int a[nMax], n;
39 int main()
40 {
41 Eratostene();
CAPITOLUL 3. OJI 2020 3.1. FORTA 29

42 int C, pMax=0, nrMin=0, x;


43 f>>C>>n;
44 for(int i=1; i<=n; i++)
45 {
46 f>>x;
47 a[i]=nrDiv(x);
48 if(a[i]>pMax)pMax=a[i], nrMin=x;
49 else if(a[i]==pMax && x<nrMin)nrMin=x;
50 }
51 if(C==1)
52 g<<nrMin<<’\n’;
53 else
54 {
55 sort(a+1, a+n+1);
56 int lg=1, maxim=0;
57 for(int i=2; i<=n; i++)
58 if(a[i]==a[i-1])lg++;
59 else
60 {
61 if(lg>maxim)maxim=lg;
62 lg=1;
63 }
64 if(lg>maxim)maxim=lg;
65 g<<maxim<<’\n’;
66 }
67 return 0;
68 }

Listing 3.1.7: putere RT.cpp


1 //Roxana Timplaru
2 #include <iostream>
3 #include <algorithm>
4 #include<fstream>
5
6 using namespace std;
7
8 ifstream fin("forta.in");
9 ofstream fout("forta.out");
10
11 int p[45001],k,x[100001],y[100001],n;
12
13 void ciur()
14 {
15 int i,j;
16 for(i=3;i<=212;i=i+2)
17 if (p[i]==0)
18 for(j=i*i;j<=45000;j=j+i)
19 p[j]=1;
20 x[1]=2;k=1;
21 for(i=3;i<=45000;i=i+2)
22 if (p[i]==0)
23 {
24 k++;
25 x[k]=i;
26 }
27 }
28
29 int numara_div(int a)
30 {
31 int t,nr=1,i=1;
32 if (a==2)
33 return 2;
34 while ( x[i]*x[i]<=a)
35 { t=0;
36 while (a%x[i]==0)
37 {
38 a=a/x[i];
39 t++;
40 }
41 if (t)
42 nr=nr*(t+1);
43 i++;
44 }
45 if (a!=1) nr=nr*2; // e nr prim
CAPITOLUL 3. OJI 2020 3.1. FORTA 30

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.1.3 *Rezolvare detaliată


CAPITOLUL 3. OJI 2020 3.2. FURNICA 31

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

Scrieţi un program care să rezolve următoarele cerinţe:


1. determină timpul (exprimat ı̂n secunde) necesar furnicii pentru a parcurge tot traseul
menţionat;
2. determină lungimea maximă (exprimată ı̂n centimetri) a unei porţiuni de traseu ı̂n care
furnica NU coboară deloc;
3. determină ce număr de ordine are foaia pe care se află furnica după T secunde.

Date de intrare

Fişierul de intrare furnica.in conţine:


- pe prima linie un număr natural C care reprezintă numărul cerinţei şi poate avea valorile 1,
2 sau 3.
- pe cea de-a doua linie un număr natural N ce reprezintă numărul foilor galbene dacă cerinţa
este 1 sau 2, respectiv două numere naturale N şi T , dacă cerinţa este 3.

- 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.

Restricţii şi precizări

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

furnica.in furnica.out Explicaţii


1 151 În primul exemplu, cerinţa este 1. Sunt 5 foi galbene iar traseul
5 parcurs de furnică este pe modelul din imaginea de mai sus.
39 Traseul are o lungime de 45 de centimetri şi furnica ı̂l va termina
59 ı̂n 151 de secunde.
26
2 13
14
2 17 În al doilea exemplu cerinţa este 2. Cea mai lungă porţiune de
5 traseu, ı̂n care furnica nu coboară are 9+3+5=17 cm.
39
59
26
2 13
14
3 4 În al treilea exemplu cerinţa este 3. După 100 de secunde furnica
5 100 se va afla pe foaia 4.
39
59
26
2 13
14

Timp maxim de executare/test: 0.1 secunde


Memorie: total 16 MB din care pentru stivă 8 MB
Dimensiune maximă a sursei: 10 KB

3.2.1 Indicaţii de rezolvare


prof. Cristina Iordaiche - Liceul Teoretic ”Grigore Moisil”, Timişoara

Pentru rezolvarea problemei identificăm pe traseul furnicii


ˆ porţiunile ı̂n care furnica urcă cu câte un centimetru ı̂n fiecare 5 secunde;

ˆ porţiunile de pe traseu ı̂n care coboară câte un centimetru la fiecare 2 secunde;

ˆ porţiunile de pe traseu ı̂n care se deplasează pe orizontală cu câte un centimetru la fiecare


3 secunde.
Furnica urcă pe latura verticală a primei foi, apoi parcurge conform traseului specificat, fiecare
foaie. Pentru a identifica tipul porţiunii (urcare, coborâre, deplasare pe orizontală) comparăm
laturile foii curente K, cu laturile foii anterioare K  1.
Cerinţa 1 - calculăm timpul necesar furnicii pentru fiecare porţiune din traseul său, cu ajutorul
unei variabile sumative
Timp=5*(porţiune urcare)+2*(porţiune coborâre)+3*(porţiune orizontală)
Cerinţa 2 - identificăm doar porţiunile de pe traseul furnicii ı̂n care aceasta se deplasează
doar pe orizontală sau pe verticală (ı̂n urcare) şi calculăm cea mai mare lungime (exprimată ı̂n
centimetri) a unei porţiuni continue de pe traseul furnicii ce respectă condiţiile din cerinţă (furnica
NU coboară)
Cerinţa 3 - contorizăm pas cu pas timpul necesar deplasării furnicii pe traseul determinat
de marginile libere ale foilor galbene, până ı̂n momentul ı̂n care am ajuns la valoarea T. Afişăm
numărul de ordine al foii galbene pe care se află furnica ı̂n acest moment.

3.2.2 Cod sursă


CAPITOLUL 3. OJI 2020 3.2. FURNICA 33

Listing 3.2.1: marinel furnica c.c


1 //Marinel Serban - 2020
2 #include <stdio.h>
3
4 FILE *fin, *fout;
5
6 struct foaie
7 {
8 long long l, h;
9 } F[10005];
10
11 long long cerinta, N, i, p, u;
12 long long timp, lg, lg_max, T;
13
14 int main()
15 {
16 fin = fopen("furnica.in", "r");
17 fout = fopen("furnica.out", "w");
18
19 fscanf(fin, "%lld", &cerinta);
20 if (cerinta < 3)
21 {
22 //citire cerinta 1 sau 2
23 fscanf(fin, "%lld", &N);
24 for (i = 1; i <= N; i++)
25 fscanf(fin, "%lld %lld", &F[i].l, &F[i].h);
26 }
27 else
28 {
29 //citire cerinta 3
30 fscanf(fin, "%lld %lld", &N, &T);
31 for (i = 1; i <= N; i++)
32 fscanf(fin, "%lld %lld", &F[i].l, &F[i].h);
33 }
34 if (cerinta == 1)
35 {
36 //rezolv cerinta 1
37 timp = F[1].h * 5; //urc
38 for (i = 1; i < N; i++)
39 {
40 timp += F[i].l * 3; //orizontal pe i
41 if (F[i].h < F[i+1].h)
42 timp += (F[i+1].h - F[i].h) * 5; //urc pe i+1
43 else
44 timp += (F[i].h - F[i+1].h) * 2; //cobor pe i
45 }
46 timp += F[N].l * 3; //orizont al pe N
47 timp += F[N].h * 2; //cobor pe N
48 fprintf(fout, "%lld\n", timp);
49 }
50 if (cerinta == 2)
51 {
52 //rezolv cerinta 2
53 p = 1; //plec de la 1
54 u = 1;
55 lg = F[1].h; //urc
56 while (p <= N) // cat timp mai am unde
57 {
58 lg += F[p].l; //merg pe orizontal
59 u++; //trec la urmatoarea
60 if (F[u].h >= F[p].h) //daca e mai inalta sau egala
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 fprintf(fout, "%lld\n", lg_max);
74 }
CAPITOLUL 3. OJI 2020 3.2. FURNICA 34

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 }

Listing 3.2.2: furnica cpp RT.cpp


1 //Roxana Timplaru
2 #include <fstream>
3 #include <iostream>
4
5 using namespace std;
6
7 ifstream fin("furnica.in");
8 ofstream fout("furnica.out");
9
10 int cerinta;
11 int t_u=5,t_c=2,t_o=3,n,i;
12 long long s,x1,y1,x2,y2,t,l,maxi;
13
14 void timp()
15 {
16 fin>>n>>x1>>y1;
17 s=y1*t_u+x1*t_o;
18 l=y1+x1;
19 y2=y1;
20 maxi=l;
21 for(i=2;i<=n;i++)
22 {
23 fin>>x2>>y2;
24 if (y2>=y1)
25 {
26 s=s+(y2-y1)*t_u;
27 l=l+y2-y1;
28 }
29 else
30 {
31 s=s+(y1-y2)*t_c;
CAPITOLUL 3. OJI 2020 3.2. FURNICA 35

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 }

Listing 3.2.3: furnica sol.cpp


1 /**
2 Cristina Iordaiche
3 */
CAPITOLUL 3. OJI 2020 3.2. FURNICA 36

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 }

Listing 3.2.4: furnica sol assert.cpp


1 /**
2 Cristina Iordaiche
3 */
4 #include <fstream>
5 #include <cassert>
6
7 using namespace std;
8
9 ifstream f("furnica.in");
10 ofstream g("furnica.out");
11
12 long long dist_coborare,dist_urcare,dist_oriz,lungime,maxi,TIMP;
13
14 int main()
15 {
16 int H,L,H1,L1,n,i,cerinta,t_oriz,t_urcare,t_coborare,cladire;
17 t_urcare=5;t_oriz=3;t_coborare=2;
18
19 f>>cerinta>>n;
20 assert(1 <= cerinta && cerinta <= 3);
21 assert(n >= 1 && n <= 10000);
22 if (cerinta==3)
23 {
24 f>>TIMP;
25 assert(1 <= TIMP && TIMP <= 10000);
26 }
27 f>>L1>>H1;
28 assert(L1 >= 1 && L1 < 1000000000);
29 assert(H1 >= 1 && H1 < 1000000000);
30 H=H1;
31 dist_urcare=H1;dist_oriz=L1;dist_coborare=0;
32 lungime=H1+L1;
33 maxi=lungime;
34 i=1;
35 TIMP=TIMP-(dist_urcare*t_urcare+dist_oriz*t_oriz);
36 if (TIMP<=0)
37 cladire=1;
38 for(i=2; i<=n; i++)
39 {
40 f>>L>>H;
41 assert(L >= 1 && L < 1000000000);
42 assert(H >= 1 && H < 1000000000);
43 dist_oriz=dist_oriz+L;
44 if(H>=H1) // URCARE
45 {
46 lungime=lungime+H-H1+L;
47 dist_urcare=dist_urcare+H-H1;
48 if (TIMP>0)
49 {
50 TIMP=TIMP-(H-H1)*t_urcare;
51 if(TIMP<=0)
52 cladire=i;
53 }
54 }
55 else // COBORARE
56 {
57 dist_coborare=dist_coborare+H1-H;
58 lungime=L;
59 if (TIMP>0)
60 {
61 TIMP=TIMP-(H1-H)*t_coborare;
62 if(TIMP<=0)
63 cladire=i-1;
64 }
65 }
66 if (TIMP>0)
67 {
68 TIMP=TIMP-L*t_oriz;
69 if (TIMP<=0)
70 cladire=i;
71 }
CAPITOLUL 3. OJI 2020 3.2. FURNICA 38

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 }

Listing 3.2.5: furnicaRC.cpp


1 //Raluca Costineanu
2 #include <bits/stdc++.h>
3
4 using namespace std;
5
6 ifstream f("furnica.in");
7 ofstream g("furnica.out");
8
9 int c, n, unde;
10 long long timp, nuCoboara, mx, T, l, L, ll, LL;
11
12 int main()
13 {
14 int i;
15 f>>c;
16 if(c<3)
17 {
18 f>>n>>l>>L;
19 timp=L*5+l*3;
20 mx=nuCoboara=l+L;
21 for(i=2; i<=n; i++)
22 {
23 f>>ll>>LL;
24 long long dif=LL-L;
25 if(dif>=0)
26 timp+=dif*5+ll*3, nuCoboara+=dif+ll, mx=max(mx, nuCoboara);
27 else timp+=-dif*2+ll*3, nuCoboara=ll;
28 l=ll;
29 L=LL;
30 }
31 timp+=L*2;
32 if(c==1)g<<timp<<’\n’;
33 else g<<mx<<’\n’;
34 }
35 else
36 {
37 f>>n>>T>>l>>L;
38 timp=L*5+l*3; unde=1;
39 if(timp<T)
40 for(i=2; i<=n; i++)
41 {
42 f>>ll>>LL;
43 long long dif=LL-L;
44 if(dif>=0)
45 timp+=dif*5;
46 else { timp+=-dif*2;
47 if(timp>=T)
48 {
49 unde=i-1;
50 break;
51 }
52 }
53 timp+=ll*3;
CAPITOLUL 3. OJI 2020 3.2. FURNICA 39

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 }

Listing 3.2.6: marinel furnica.cpp


1 //Marinel Serban - 2020
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream fin("furnica.in");
7 ofstream fout("furnica.out");
8
9 struct foaie
10 {
11 long long l, h;
12 } F[10005];
13
14 long long cerinta, N, i, p, u;
15 long long timp, lg, lg_max, T;
16
17 int main()
18 {
19 fin >> cerinta;
20 if (cerinta < 3)
21 {
22 //citire cerinta 1 sau 2
23 fin >> N;
24 for (i = 1; i <= N; i++)
25 fin >> F[i].l >> F[i].h;
26 }
27 else
28 {
29 //citire cerinta 3
30 fin >> N >> T;
31 for (i = 1; i <= N; i++)
32 fin >> F[i].l >> F[i].h;
33 }
34 if (cerinta == 1)
35 {
36 //rezolv cerinta 1
37 timp = F[1].h * 5; //urc
38 for (i = 1; i < N; i++)
39 {
40 timp += F[i].l * 3; //orizontal pe i
41 if (F[i].h < F[i+1].h)
42 timp += (F[i+1].h - F[i].h) * 5; //urc pe i+1
43 else
44 timp += (F[i].h - F[i+1].h) * 2; //cobor pe i
45 }
46 timp += F[N].l * 3; //orizont al pe N
47 timp += F[N].h * 2; //cobor pe N
48 fout << timp << ’\n’;
49 }
50 if (cerinta == 2)
51 {
52 //rezolv cerinta 2
53 p = 1; //plec de la 1
54 u = 1;
55 lg = F[1].h; //urc
56 while (p <= N) // cat timp mai am unde
57 {
58 lg += F[p].l; //merg pe orizontal
59 u++; //trec la urmatoarea
60 if (F[u].h >= F[p].h) //daca e mai inalta sau egala
CAPITOLUL 3. OJI 2020 3.2. FURNICA 40

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 }

3.2.3 *Rezolvare detaliată


Capitolul 4

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.

Restricţii şi precizări

a n este număr natural, 3 & n & 800000.


a Pentru rezolvarea cerinţei 1 se obţin 40 de puncte, iar pentru cerinţa 2, 50 de puncte.
a Pentru cerinţa 2, se garantează că, pentru 50% dintre teste, n & 100.
a Numerele de pe stickere sunt numere naturale cuprinse ı̂ntre 10 şi 999999.

Exemple

41
CAPITOLUL 4. OJI 2019 4.1. ALBUM 42

album.in album.out Explicaţii


1 12 Cerinţa este 1. Pe ultimul sticker de pe masă
7 este scris numărul 121, care are cele mai mari
291 11 992 456 71 13 121 două cifre 1 şi 2.
2 V Cerinţa este 2. Victor ı̂ncepe concursul şi ia
7 4 stickerele 234 (cu 3 şi 4 cele mai mari două
234 122 334 199 463 221 231 cifre), 334 şi 463. Pa masă rămân stickerele 122
199 221 231. Continuă Radu, care ia stickerele
cu numerele 122 (cu cele mai mari două cifre 2
şi 2) şi 221. Rămân stickerele 199 şi 231. Victor
mai ia stickerul cu numărul 199, apoi Radu ia
stickerul cu numărul 231. Victor câştigă cu 4
stickere, Radu având doar trei.

Timp maxim de executare/test: 0.5 secunde


Memorie: total 16 MB din care pentru stivă 8 MB
Dimensiune maximă a sursei: 10 KB
Sursa: album.cpp, album.c sau album.pas va fi salvată ı̂n folderul care are drept nume
ID-ul tău.

4.1.1 Indicaţii de rezolvare

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.

4.1.2 Cod sursă

Listing 4.1.1: album Flavius.cpp


1 #include <iostream>
2 #include <fstream>
3 #include <algorithm> // sort, reverse
4
5 using namespace std;
6
7 ifstream f("album.in");
8 ofstream g("album.out");
9
10 int C,i,j,k,n,v[11],ap[101],u,maxim1,a,numar,maxim2,x,vi,
11 ra,t,p,ok,y,nr,minim,poz;
12
13 int main()
14 {
15 f>>C;
16
17 if(C==1)
18 {
19 f>>n;
20 for(i=1; i<=n; i++)
21 f>>x;
22
23 maxim1=0;
CAPITOLUL 4. OJI 2019 4.1. ALBUM 43

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 }

Listing 4.1.2: album Roxana.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("album.in");
7 ofstream g("album.out");
8
9 int c,n,i,x[1000001],y[1000001],v[10],k,max1,max2;
10
11 void maxime(int x, int &max1, int &max2)
12 {
13 while(x)
14 {
15 v[x%10]++;
16 x=x/10;
17 }
18
19 k=0;
20 for(i=9;i>=0;i--)
21 {
22 if (!v[i])
23 {
24 if(k!=1)
25 max1=i; v[i]--;k++;
26 if (k==2) break;
27 }
28 if (!v[i])
29 {
30 max2=i;k++;
31 if (k==2) break;
32 }
33 }
34 }
35
36 void maxime1(int x, int &max1, int &max2)
37 {
38 max1=0;
39 max2=0;
40 while (x)
41 {
42 if (x%10>max1)
43 {
44 max2=max1;
45 max1=x%10;
46 }
47 else
48 if (x%10>max2)
49 max2=x%10;
50 x=x/10;
51 }
52 }
53
54 int exista(int x, int max1, int max2)
55 {
56 int k1,k2,v1[10],c;
CAPITOLUL 4. OJI 2019 4.1. ALBUM 45

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 }

Listing 4.1.3: album VG.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 int ap[100],n,x,y,v,r,c,ci[7];
6
7 int main()
8 {
9 ifstream f("album.in");
10 ofstream g("album.out");
11 int i,j,k, ok,c1,c2,ct1,ct2,al=0,nrc;
12
13 f>>c;
14 if(c==1)
15 {
16 f>>n;
17 for(i=1;i<=n;i++) f>>x;
18 c1=-1; c2=-1;
19
20 while(x!=0)
21 {
22 if(x%10>=c1) {c2=c1; c1=x%10;}
23 else if(x%10>c2) c2=x%10;
24
25 x=x/10;
26 }
27
28 g<<c2<<’ ’<<c1;
29 }
30
31 else
32 // C=2
33 { f>>n;
34 for(i=1;i<=n;i++)
35 {
36 f>>x;
37 y=x;
38
39 nrc=0;
40 while (y!=0)
41 {
42 nrc++;
43 ci[nrc]=y%10;
44 y=y/10;
45 }
46
CAPITOLUL 4. OJI 2019 4.1. ALBUM 47

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 }

Listing 4.1.4: album2 VG.cpp


1 #include <fstream>
2
3 using namespace std;
4 int ap[1000001],n,x,y,v,r,c;
5
6 int main()
7 {
8 ifstream f("album.in");
9 ofstream g("album.out");
10
11 int i,j,k, ok,c1,c2,ct1,ct2,et=0;
12
13 f>>c;
14 if(c==1)
15 {
16 f>>n;
17 for(i=1;i<=n;i++) f>>x;
18
19 c1=-1; c2=-1;
20 while(x!=0)
21 {
22 if(x%10>=c1)
23 {c2=c1; c1=x%10;}
24 else
25 if(x%10>c2) c2=x%10;
26 x=x/10;
27 }
28
29 g<<c2<<’ ’<<c1;
30 }
31 else
32 // cazul 2
CAPITOLUL 4. OJI 2019 4.1. ALBUM 48

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 }

Listing 4.1.5: albumAdyN.cpp


1 #include <fstream>
2 #define Max 1000005
3
4 using namespace std;
5
6 ifstream cin("album.in");
7 ofstream cout("album.out");
8
9 int v[Max], n;
10 int pr;
11 int victor, radu, cine;
12
13 int main()
14 {
15 int i, j, max1, max2; // max1 >= max2
CAPITOLUL 4. OJI 2019 4.1. ALBUM 49

16 int aux, cif;


17 int este[10];
18
19 cin >> pr;
20 cin >> n;
21
22 for(i=1; i<=n; i++)
23 cin >> v[i];
24
25 if(pr == 1)
26 {
27 aux = v[n];
28 max1 = max2 =0;
29 while(aux > 0)
30 {
31 cif = aux%10;
32 aux = aux/10;
33 if(cif > max1)
34 {
35 max2 = max1;
36 max1 = cif;
37 }
38 else
39 if(cif > max2)
40 max2 = cif;
41 }
42 cout << max2 << ’ ’ << max1 << ’\n’;
43 return 0;
44 }
45
46 // cazul 2
47 victor = radu = 0;
48 cine = 1; // cine=1 => victor, cine=2 => radu
49 for(i=1; i<=n; i++)
50 if(v[i]!=0) // poate fi zero ??? DA (poate sa ajunga zero)
51 {
52 aux = v[i];
53 max1 = max2 =0;
54 while(aux > 0)
55 {
56 cif = aux%10;
57 aux = aux/10;
58 if(cif > max1)
59 {
60 max2 = max1;
61 max1 = cif;
62 }
63 else
64 if(cif > max2)
65 max2 = cif;
66 }
67
68 if(cine == 1)
69 victor ++;
70 else
71 radu ++;
72
73 v[i] = 0;
74
75 for(j=i+1; j<=n; j++)
76 {
77 if(v[j] != 0)
78 {
79 aux = v[j];
80 for(int k=0; k<=9; k++) este[k]=0;
81 while(aux > 0) // cifrele lui v[j]
82 {
83 cif = aux %10;
84 aux = aux /10;
85 este[cif] ++;
86 }
87 if((max1 != max2 && este[max1]!=0 && este[max2]!=0) ||
88 (max1 == max2 && este[max1]>=2))
89 {
90 if(cine == 1)
91 victor ++;
CAPITOLUL 4. OJI 2019 4.1. ALBUM 50

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 }

Listing 4.1.6: albumPLV.cpp


1 //autor: prof. Liviu Pinzaru, Palatul Copiilor Suceava
2 #include <fstream>
3
4 using namespace std;
5
6 int v[8],ord[100];
7 short int w[10];
8
9 int main()
10 {
11 ifstream f("album.in");
12 ofstream g("album.out");
13
14 int i,j,N,n,x,z,poz=0,Mm=0,ii,ORD;
15 int p;
16 char a[20];
17 int V=0,R=0;
18
19 f>>p;
20 f>>N;
21
22 if(p==1)
23 {
24 for(ii=1;ii<=N;++ii) f>>a;
25 for(j=0;a[j];++j)
26 {
27 x=a[j]-’0’;
28 w[x]++;
29 }
30
31 i=0;
32 for(j=9;j>=0 ;--j)
33 {
34 if(w[j]>=1)
35 v[++i]=j;
36 }
37
38 x=v[1];
39 if(w[x]>1)
40 g<<x<<" "<<x;
41 else
42 g<<v[2]<<" "<<v[1];
43
44 return 0;
45 }
46
47 // cazul 2 ...................
48 for(ii=1;ii<=N;++ii)
CAPITOLUL 4. OJI 2019 4.1. ALBUM 51

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

125 //g<<"V="<<V<<" R="<<R<<" poz="<<poz<<" ORD="<<ORD<<’\n’;


126 }
127
128 if(V>R)
129 g<<"V"<<’\n’<<V;
130 else
131 if(R>V)
132 g<<"R"<<’\n’<<R;
133 else //if(V==R)
134 g<<"V R"<<’\n’<<V;
135
136 return 0;
137 }

4.1.3 *Rezolvare detaliată

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

Cunoscând N , M şi cele N cifre din şir, să se determine:


1) cel mai mare număr care se poate obţine din primele M dintre cele N cifre date;
2) de unde va lua Ionel M cifre aflate pe poziţii consecutive pentru a obţine un număr maxim;
dacă sunt mai multe poziţii corespunzătoare unui număr maxim, alegerea se va face astfel ı̂ncât
numărul format din cifrele rămase, ı̂n ordinea ı̂n care erau, să fie cât mai mare posibil; dacă şi ı̂n
acest caz există mai multe soluţii, se alege poziţia maximă.

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

ı̂n fişierul maxim.out se scrie:


- pentru P 1: numărul maxim care se poate obţine cu ajutorul primelor M cifre dintre cele
N date, fără spaţii ı̂ntre cifrele numărului;
- pentru P 2: un număr reprezentând poziţia cerută.

Restricţii şi precizări

a M , N numere naturale, 1 & N & 500000, 1 & M & 1000, M $ N


a Cele N valori de pe linia a treia sunt numere naturale ı̂ntre 0 şi 9
a Secvenţa de N cifre poate să ı̂nceapă cu cel mult M  1 cifre nule.
a 30 de puncte se vor obţine cu rezolvarea cerinţei 1, iar 60 de puncte se vor obţine cu rezolvarea
cerinţei 2.
a Pentru 50% dintre teste, N $ 1000 şi M $ 10.

Exemple

maxim.in maxim.out Explicaţii


CAPITOLUL 4. OJI 2019 4.2. MAXIM 53

1 872 Se rezolvă cerinţa 1. Cu primele 3 cifre dintre cele 10


10 3 cifre date se pot forma numerele: 728, 782, 287, 278,
7281004781 827, 872, cel mai mare fiind 872.
2 7 Se rezolvă cerinţa 2. Alegând cifrele ı̂ncepând de la
10 3 poziţia a 7-a (cifrele 4, 7 şi 8), se va forma numărul
7281004781 874, care este cel mai mare posibil.
2 9 Se rezolvă cerinţa 2. Alegând cifrele ı̂ncepând de
10 2 la poziţia a 6-a (cifrele 8 şi 7) sau cifrele ı̂ncepând
0728487178 cu poziţia a 9-a (7 şi 8) va forma numărul 87 care
este cel mai mare număr de două cifre consecutive.
Dar, eliminı̂nd cifrele de pe poziţiile 6 şi 7, secvenţa
rămasă este 07284178 (cu valoarea 7284178), pe când
eliminând cifrele de pe poziţiile 9 şi 10 numărul rămas
este 7284871 care este mai mare.
2 4 Se rezolvă cerinţa 2. Alegând cifrele de pe poziţiile 2,
10 2 3 sau 3, 4 sau 4, 5 se va forma numărul 96 care este
5969682668 cel mai mare număr de două cifre consecutive posibil.
Dar, eliminând cifrele de pe poziţiile 2 şi 3, numărul
rămas este 59682668, eliminând cifrele de pe poziţiile
3 şi 4 numărul rămas este 59682668, eliminând cifrele
de pe poziţiile 4 şi 5 numărul rămas este 59682668. Se
poate afişa poziţia 2 sau 3 sau 4, dar se va alege poziţia
maximă, 4.

Timp maxim de executare/test: 0.5 secunde


Memorie: total 6 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 10 KB
Sursa: maxim.cpp, maxim.c sau maxim.pas va fi salvată ı̂n folderul care are drept nume
ID-ul tău.

4.2.1 Indicaţii de rezolvare

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.

4.2.2 Cod sursă

Listing 4.2.1: maximFB.cpp


1 #include <iostream> // Cum pot sa verific daca numerele ramase
2 #include <fstream> // in urma fiecarei elimiari sunt egale??
CAPITOLUL 4. OJI 2019 4.2. MAXIM 54

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 }

Listing 4.2.2: maximFBB.cpp


1 #include <iostream>
2 #include <fstream>
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 if(c==2)
29 {
30 start=1;
31
CAPITOLUL 4. OJI 2019 4.2. MAXIM 56

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 }

Listing 4.2.3: maximPLV.cpp


1 //autor: prof. Liviu-Vasile Pinzaru,
2 // Palatul Copiilor Suceava & Clubul Copiilor Falticeni
3
4 #include <fstream>
5
6 using namespace std;
7
8 const int dim=500008;
9 short int v[dim];
10
11 int w[10];
12 int W[10];
13
14 int main()
15 {
16 ifstream f("maxim.in");
17 ofstream g("maxim.out");
18 int N,i,j,poz=0,M,x,z,k=0,ii;
19 int ok=1;
20 int p;
21
22 f>>p;
CAPITOLUL 4. OJI 2019 4.2. MAXIM 57

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 }

Listing 4.2.4: maximPLV01cerinta1sort.cpp


CAPITOLUL 4. OJI 2019 4.2. MAXIM 58

1 //autor: prof. Liviu-Vasile Pinzaru


2
3 #include <fstream>
4 #include <algorithm>
5
6 using namespace std;
7
8 const int dim=500008;
9 short int v[dim],b[dim];
10
11 bool cond (short int A, short int B)
12 {
13 return A>B;
14 }
15
16 int main()
17 {
18 ifstream f("maxim.in");
19 ofstream g("maxim.out");
20
21 int N,i,j,poz=0,M,x,z,k=0,ii;
22 int p;
23 long long A,B,maxx=0;
24
25 f>>p;
26 f>>N>>M;
27
28 for(i=1;i<=N;++i)
29 f>>v[i];
30
31 if(p==1)
32 {
33 sort(v+1,v+M+1,cond);
34
35 A=0;
36 for(i=1;i<=M;++i)
37 {
38 A=A*10+v[i];
39 }
40
41 g<<A<<’\n’;
42 }
43
44 return 0;
45 }

Listing 4.2.5: maximPLV02sort.cpp


1 //autor: prof. Liviu-Vasile Pinzaru
2
3 #include <fstream>
4 #include <algorithm>
5
6 using namespace std;
7
8 const int dim=500008;
9 short int v[dim],b[dim];
10
11 bool cond (short int A,short int B)
12 {
13 return A>B;
14 }
15
16 int main()
17 {
18 ifstream f("maxim.in");
19 ofstream g("maxim.out");
20 int N,i,j,poz=0,M,x,z,k=0,ii;
21 int p;
22 long long A,B,maxx=0;
23
24 f>>p;
25 f>>N>>M;
26
CAPITOLUL 4. OJI 2019 4.2. MAXIM 59

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 }

Listing 4.2.6: maximPR.cpp


1 #include <fstream>
2
3 using namespace std;
4 int q[500005];
5
6 int main()
7 {
8 ifstream f("maxim.in");
9 ofstream g("maxim.out");
10
CAPITOLUL 4. OJI 2019 4.2. MAXIM 60

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 }

Listing 4.2.7: maximR1.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("maxim.in");
6 ofstream g("maxim.out");
7
8 int x[500001],i,n,c,ok,a,m,j,k,v[10];
9
10 void cerinta1()
11 {
12 do
13 {
14 ok=0;
15 for(i=1;i<m;i++)
16 if(x[i]<x[i+1])
17 {
18 a=x[i];
19 x[i]=x[i+1];
20 x[i+1]=a;
21 ok=1;
22 }
23 } while (ok);
24
25 for(i=1;i<=m;i++)
26 g<<x[i];
CAPITOLUL 4. OJI 2019 4.2. MAXIM 61

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 }

Listing 4.2.8: maximR2.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("maxim.in");
6 ofstream g("maxim.out");
7
8 int x[500001],i,n,c,ok,a,m,j,k,v[10];
9
10 void cerinta1()
11 {
12 for (i=1;i<=m;i++)
13 v[x[i]]++;
14
15 for(i=9;i>=0;i--)
16 while(v[i])
CAPITOLUL 4. OJI 2019 4.2. MAXIM 62

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 }

4.2.3 *Rezolvare detaliată


Capitolul 5

OJI 2018

5.1 numere - OJI 2018


Problema 1 - numere 90 de
puncte
Se consideră răsturnatul unui număr natural valoarea obţinută prin parcurgerea cifrelor aces-
tuia de la dreapta la stânga. De exemplu, răsturnatul numărului 245 este 542. Un număr este
palindrom dacă este egal cu răsturnatul său. De exemplu 121 este palindrom, iar numărul 21 nu
este palindrom.
Se consideră iniţial şirul numerelor naturale 0, 1, 2, 3, 4, ...
Din acest şir se elimină numerele divizibile cu 10 şi, după fiecare număr care NU este palindrom,
se inserează răsturnatul său. Noul şir astfel obţinut va fi 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 21, 13, 31, ...

Cerinţe

Scrieţi un program care să citească:


1. un număr natural n şi să afişeze al n-lea număr eliminat din şirul iniţial;
2. un număr natural x şi să afişeze următoarele trei numere: n1 - numărul de apariţii ı̂n noul
şir ale numărului obţinut din x prin eliminarea ultimei sale cifre; n2 - numărul de apariţii ı̂n noul
şir ale numărului obţinut din x prin eliminarea ultimelor sale două cifre; n3 - numărul de apariţii
ı̂n noul şir ale numărului obţinut din x prin eliminarea ultimelor sale trei cifre.
3. un număr natural k şi să afişeze numărul valorilor de k cifre din noul şir.

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.

Restricţii şi precizări

- 1 & n & 2.000.000.000


- 1000 & x & 2.000.000.000
- 1 & k & 50 (1 & k & 18, pentru teste ı̂n valoare de 20 de puncte)
- Pentru rezolvarea corectă a primei cerinţe se acordă 10 puncte, pentru rezolvarea corectă a
celei de a doua cerinţe se acordă 25 de puncte, iar pentru rezolvarea corectă a celei de a treia
cerinţe se acordă 55 de puncte. Se acordă 10 puncte din oficiu.

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).

Timp maxim de executare/test: 1.0 secunde


Memorie: total 16 MB
Dimensiune maximă a sursei: 5 KB

5.1.1 Indicaţii de rezolvare


prof. Ana-Maria Arişanu, Colegiul National Mircea cel Batran, Rm. Valcea
Cerinta 1
Numerele eliminate din sir sunt 0,10,20,30, etc. Al n-lea numar eliminat este (n-1)*10 Obs. 1
¡= n ¡= 2.000.000.000 =¿ (n-1)*10 nu se incadreaza in tipul int
Cerinta 2

caz 1. Daca un numar este divizibil cu 10 atunci nu apare in noul sir


caz 2. Daca un numar este palindrom, diferit de 0, atunci apare o singura data
caz 3. Daca un numar nu e palindrom atunci apare o singura data.

Cerinta 3
Numarul elementelor de k cifre din noul sir este 2*(t-a)-b, unde:

t este numarul total de numere de k cifre


a este numarul numerelor de k cifre divizibile cu 10
b este numarul numerelor palindrom de k cifre.
t 9 ˜ 10k  1 (exceptie pentru k=1, t=10)
a 9 ˜ 10k  2
b 9 ˜ 10 k  1©2

=¿ 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.

5.1.2 Cod sursă

Listing 5.1.1: numere cpp.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("numere.in");
6 ofstream g("numere.out");
7
8 int nrap(int x)
CAPITOLUL 5. OJI 2018 5.1. NUMERE - OJI 2018 65

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 }

Listing 5.1.2: numere1.cpp


1 #include <fstream>
2 using namespace std;
3
4 ifstream fin("numere.in");
5 ofstream fout("numere.out");
6
7 long long p,x,k,n,i,ogl,aux,nr;
8
9 int main()
10 {
11 fin>>p;
12
13 if(p==1){fin>>n; fout<<(n-1)*10<<’\n’;return 0;}
14
15 if(p==2)
16 {
17 fin>>x;
18 for(i=1;i<=3;i++)
19 {
20 x=x/10;ogl=0;aux=x;
21 while(aux)ogl=ogl*10+aux%10,aux/=10;
22 if(ogl==x)nr=1;else if(x%10==0)nr=0;
23 else nr=2;
24 fout<<nr<<’ ’;
CAPITOLUL 5. OJI 2018 5.1. NUMERE - OJI 2018 66

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 }

Listing 5.1.3: numere2.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("numere.in");
6 ofstream g("numere.out");
7
8 long long p,n,x,k,nr,p1,p2,i;
9
10 long long nrpalindrom(long long x)
11 {
12 long long nr=0,y;
13 y=x;
14 while(x)
15 {
16 nr=nr*10+x%10;
17 x=x/10;
18 }
19 if (y==nr) return 1;
20 else return 0;
21 }
22
23 void calcul(int k)
24 {
25 int i;
26 g<<161;
27 for(i=1;i<=(k-5)/2;i++) g<<9;
28 if (k%2==0) g<<9;
29 g<<1;
30 for(i=1;i<=(k-5)/2+1;i++) g<<0;
31 g<<0;
32 }
33
34 int cauta(int x)
35 {
36 int nr;
37 if(x%10==0)
38 nr=0;
39 else
40 {
41 if (x<9)
42 nr=1;
43 else
44 if (nrpalindrom(x)==1)
45 nr=1;
46 else
47 nr=2;
48 }
49
50 return nr;
51 }
52
53 int main()
54 {
CAPITOLUL 5. OJI 2018 5.1. NUMERE - OJI 2018 67

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 }

Listing 5.1.4: numere3.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream fin("numere.in");
6 ofstream fout("numere.out");
7
8
9 int cerinta, n, x, k, i, nr;
10 unsigned long long X, A, B;
11
12 bool pali(unsigned long long x)
13 {
14 unsigned long long xi = 0, cx = x;
15 while (x)
16 {
17 xi = xi * 10 + x % 10;
18 x /= 10;
19 }
20 return (cx == xi);
21 }
22
23 int main()
24 {
25 fin >> cerinta;
26
27 if (cerinta == 1)
28 {
29 fin >> n;
30 if (n > 1)
31 fout << n - 1 << 0 << ’\n’;
32 else
33 fout << 0 << ’\n’;
34 return 0;
35 }
36
37 if (cerinta == 2)
38 {
39 fin >> x;
40 for (i = 1; i <= 3; i++)
41 {
42 x = x / 10;
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 68

43 if (x % 10 == 0) fout << 0 << ’ ’;


44 else
45 if (pali(x)) fout << 1 << ’ ’;
46 else
47 fout << 2 << ’ ’;
48 }
49 return 0;
50 }
51
52 fin >> k;
53 if (cerinta == 3 && k <= 3)
54 {
55
56 A = 1; B = 0;
57 for (i = 1; i < k; i++)
58 {
59 A *= 10;
60 B = B * 10 + 9;
61 }
62 B = B * 10 + 9;
63 nr = B - A + 1;
64 for (X = A; X <= B; X++)
65 if (X % 10 == 0)
66 nr--;
67 else
68 if (!pali(X))
69 nr++;
70 fout << nr << ’\n’;
71 }
72 else
73 {
74 fout << 161;
75 for (i = 1; i <= (k - 2) / 2 - 1; i++)
76 fout << 9;
77 fout << 1;
78 for (i = 1; i <= (k - 1) / 2; i++)
79 fout << 0;
80 fout << ’\n’;
81 }
82
83 return 0;
84 }

5.1.3 *Rezolvare detaliată

5.2 turnuri - OJI 2018


Problema 2 - turnuri 90 de
puncte
Într-un laborator cibernetic se fac experimente cu roboţi. Pe o bandă de lucru se află aşezate
unul lângă altul, N cuburi galbene şi albastre, numeroate ı̂n ordine cu valori de la 1 la N . Pen-
tru fiecare cub se cunoaşte latura acestuia, exprimată ı̂n centimetri, şi culoarea, codificată prin
simbolul g (pentru galben) sau a (pentru albastru).
Un robot inteligent este programat să construiască
turnuri prin aşezarea cuburilor unul peste altul. El se află
ı̂n faţa benzii de lucru, analizează fiecare cub ı̂n ordine,
de la primul la ultimul, şi procedează astfel:
a dacă este primul cub, ı̂l lasă la locul lui pe bandă;
a aşează cubul numerotat cu K peste cubul nu-
merotat cu K  1 doar dacă el are culoarea diferită şi
latura mai mică decât cubul K  1. Această operaţie se
efectuează ı̂n cazul ı̂n care cubul K  1 se află deja ı̂ntr- Figura 5.1: Turnuri
un turn constuit anterior sau dacă el a rămas ı̂n poziţia
iniţială. În cazul ı̂n care cubul K nu poate fi aşezat peste cubul K  1, el rămâne la locul lui.

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

Fişierul turnuri.in conţine:


- pe prima linie un număr natural C care reprezintă numărul cerinţei şi poate fi 1 sau 2.
- pe cea de-a doua linie un număr natural N ce reprezintă numărul cuburilor de pe bandă;
- pe fiecare dintre următoarele N linii, câte un număr natural care reprezintă latura unui cub,
urmat de un spaţiu şi simbolul g sau a, pentru codificarea culorii cubului.

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.

Restricţii şi precizări

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

Figura 5.2: Turnuri - exemple

Timp maxim de executare/test: 1.0 secunde


Memorie: total 16 MB
Dimensiune maximă a sursei: 5 KB

5.2.1 Indicaţii de rezolvare

prof. Cristina Iordaiche, Liceul Teoretic ”Grigore Moisil” Timisoara

Pentru rezolvarea cerintei 1)

- se compara latura cubului numerotat cu K, cu latura cubului numerotat cu K  1. Daca


este posibil (cubul K are latura mai mare decat cea a cubului K  1 si culoarea cubului K
este diferita de cea a cubului K  1) cubul K se aseaza peste cubul K  1. In acest caz, se
actualizeaza inaltimea turnului prin adaugarea numarului de centimetri ce reprezinta latura
cubului K;
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 70

- 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.

Pentru rezolvarea cerintei 2)


- O solutie posibila consta in rearanjarea cuburile pe banda, unul dupa altul, ordonate de-
screscator in functie de latura acestora;
- se parcurg liniar cuburile incepand de la cubul cu latura cea mai mare;
- se selecteaza la fiecare pas, cubul cu latura mai mare decat a cubului precedent si se verifica
daca el are culoarea diferita fata de cea a cubului anterior asezat in turn;
- se actualizeaza intr-o variabila de tip contor numarul cuburilor ce se pot aseza unul peste
altul pentru a forma turnul cu numarul maxim de cuburi.

5.2.2 Cod sursă

Listing 5.2.1: turnuri.cpp


1 #include <algorithm>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream fin("turnuri.in");
7 ofstream fout("turnuri.out");
8
9 int C,n,n1,n2;
10 long long nr_turnuri,max_turn;
11 int v1[10003],v2[10003],v3;
12
13 void citire()
14 { int l1,l2,i;
15 long long h_turn;
16 char cul1,cul2;
17
18 fin>>C>>n;
19 fin>>l1>>cul1;
20
21 nr_turnuri=1;h_turn=l1;
22 if(cul1==’g’) v1[++n1]=l1;
23 else v2[++n2]=l1;
24
25 for(i=1; i<=n-1; i++)
26 {
27 fin>>l2>>cul2;
28
29 if(cul2==’g’) v1[++n1]=l2;
30 else v2[++n2]=l2;
31
32 if(l2<l1 && cul2!=cul1)
33 {h_turn=h_turn+l2;}
34 else
35 {nr_turnuri++;h_turn=l2;}
36
37 if (h_turn>max_turn) max_turn=h_turn;
38
39 l1=l2;cul1=cul2;
40 }
41 }
42
43 bool cmp( int a, int b)
44 {
45 return (a>b);
46 }
47
48 int main()
49 {
50 int i,j,k,p;
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 71

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 }

Listing 5.2.2: turnuri1.cpp


1 #include <algorithm>
2 # include <fstream>
3
4 using namespace std;
5
6 ifstream fin("turnuri.in");
7 ofstream fout("turnuri.out");
8
9 int C,n,n1,n2;
10 long long nr_turnuri,max_turn;
11 int v1[10003],v2[10003],v3[10003];
12
13 void citire()
14 { int l1,l2,i;
15 long long h_turn;
16 char cul1,cul2;
17
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 72

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 }

Listing 5.2.3: turnuri2.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream fin("turnuri.in");
6 ofstream fout("turnuri.out");
7
8 unsigned C,T,n,val[10001],i,j,L[10001],lmax1,lmax2,u,p,culoare,ales;
9 long long unsigned H,h;
10 char cul[10001];
11
12 int main()
13 {
14 fin>>C>>n;
15 for(i=1;i<=n;i++)
16 fin>>val[i]>>cul[i];
17
18 if(C==1)
19 {
20 T=1;h=H=val[1];
21 for(i=2;i<=n;i++)
22 {
23 if(cul[i]!=cul[i-1]&&val[i]<val[i-1])
24 h+=val[i];
25 else
26 {
27 T++;if(h>H)H=h;
28 h=val[i];
29 }
30 }
31 if(h>H){H=h;}
32 fout<<T<<" "<<H<<’\n’;
33 return 0;
34 }
35
36 ///cerinta 2
37 for(p=i=1,u=n;i<=n;i++)
38 { if(cul[i]==’a’) L[p++]=val[i];else L[u--]=val[i];}
39
40 for(i=1;i<p-1;i++)///ordonez descrescator cuburile albastre
41 for(j=i+1;j<p;j++)
42 if(L[i]<L[j]) swap(L[i],L[j]);
43
44 for(i=p;i<n;i++)///ordonez descrescator cuburile galbene
45 for(j=i+1;j<=n;j++)
46 if(L[i]<L[j]) swap(L[i],L[j]);
47
48 i=2;j=p;lmax1=1;culoare=1;ales=L[1];///plec cu primul albastru
49 while(i<p&&j<=n)
50 {
51 if(culoare==1)
52 if(L[j]<ales) {lmax1++;ales=L[j++];culoare=2;}
53 else j++;
54 else
55 if(L[i]<ales) {lmax1++;ales=L[i++];culoare=1;}
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 74

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 }

Listing 5.2.4: turnuri3.cpp


1 #include <algorithm>
2 # include <fstream>
3
4 using namespace std;
5
6 ifstream fin("turnuri.in");
7 ofstream fout("turnuri.out");
8
9 int C,n,n1,n2;
10 long long nr_turnuri,max_turn;
11 int v1[10003],v2[10003],v3[10003];
12
13 void citire()
14 { int l1,l2,i;
15 long long h_turn;
16 char cul1,cul2;
17
18 fin>>C>>n;
19 fin>>l1>>cul1;//citesc primul cub;
20
21 nr_turnuri=1;h_turn=l1;
22
23 if(cul1==’g’) v1[++n1]=l1;//memorez in vectorul v1 cuburile galbene
24 else v2[++n2]=l1;//memorez in vectorul v2 cuburile albastre
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 void sortare(int v[],int n)
45 {
46 int i,j,aux;
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 75

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 }

Listing 5.2.5: turnuri4.cpp


1 #include <fstream>
2 #include <cstdlib>
3
4 using namespace std;
5
6 struct cub
7 {
8 int lat;
9 bool cul;
10 };
11
12 ifstream fin("turnuri.in");
13 ofstream fout("turnuri.out");
14
15 void cerinta1()
16 {
17 cub last, cub_curent;
18 int T=1, n, i;
19 long long Hmax, Hcub_curent,L;
20 char C;
21
22 /// citire primul cub
23 fin>>n;
24 fin>>L>>C;
25
26 last.lat=L;
27 if(C==’a’) last.cul=1; else last.cul=0;
28 Hmax=Hcub_curent=L;
29
30 for (i=2; i<=n ; i++)
31 {
32 fin>>L>>C;
33 cub_curent.lat=L;
34 if(C==’a’) cub_curent.cul=1; else cub_curent.cul=0;
35
36 if(last.culˆcub_curent.cul && last.lat>cub_curent.lat) // formeaza turn
37 {
38 Hcub_curent+=cub_curent.lat;
39 if(Hcub_curent>Hmax) Hmax=Hcub_curent;
40 }
41 else
42 {
43 T++;
44 Hcub_curent=cub_curent.lat;
45 if(Hcub_curent>Hmax) Hmax=Hcub_curent;
46 }
47 last=cub_curent;
48 }
49 fout<<T<<" "<<Hmax<<endl;
50 }
51
52 int compare (const void *a, const void *b)
53 {
54 cub c1=*(cub*)a;
55 cub c2=*(cub*)b;
56 return ( c1.lat-c2.lat );
57 }
58
59 int aleg(cub Cb[],int last)
60 {
61 int cub_curent=last-1;
62 while(cub_curent>=0 && (Cb[last].culˆCb[cub_curent].cul)==0) cub_curent--;
63 return cub_curent;
64 }
65
66 void cerinta2()
67 {
68 int n,i,L,cub_curent,T=0;
69 ///long long Hmax=0;
70 char C;
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 77

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 }

Listing 5.2.6: turnuri5.cpp


1 #include <fstream>
2 #include <iostream>
3
4 using namespace std;
5
6 ifstream fin("turnuri.in");
7 ofstream fout("turnuri.out");
8
9 int n,lat[10001];
10 char c[10001];
11
12 void rezolva_a()
13 {
14 int l1,l2,n,i,nrturnuri=0,p;
15 long long h, hmax;
16 char c1, c2;
17
18 fin>>n;
19 fin>>l1>>c1;
20
21 h=l1;
22 hmax=h;
23 for(i=2;i<=n;i++)
24 {
25 fin>>l2>>c2;
26 if (c2!=c1 && l2<l1)
27 h=h+l2;
28 else
29 {
30 nrturnuri++;
31 if (h>hmax) hmax=h;
32 h=l2;
33 }
34
35 l1=l2;c1=c2;
36 }
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 78

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 }

Listing 5.2.7: turnuri6.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("turnuri.in");
6 ofstream g("turnuri.out");
7
8 int lat[10001], cul[10001],auxl,auxc;
9
10 int main()
11 {
12 int C, N, ul,k,j,i;
13 long long h, hmax;
14 char culoare;
15 bool uc;
16
17 f>>C>>N;
18
19 for (i=1;i<=N;i++)
20 {
21 f>>lat[i]>>culoare;
22 if (culoare==’a’) cul[i]=1;
23 else cul[i]=0;
24 }
25
26 if (C==1)
27 {
28 k=1; // nr de turnuri
29 ul=lat[1];
30 uc=cul[1];
31 h=lat[1]; hmax=1;
32
33 for (i=2;i<=N;i++)
34 if (lat[i]<ul && cul[i]!=uc)
35 {
36 ul=lat[i];
37 uc=cul[i];
38 h+=lat[i];
39 }
40 else
41 {
42 if (h>hmax)hmax=h;
43 k++;
44 ul=lat[i];
45 uc=cul[i];
46 h=lat[i];
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 80

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 }

Listing 5.2.8: turnuri7.cpp


1 #include <bits/stdc++.h>
2
3 using namespace std;
4
5 ifstream fin("turnuri.in");
6 ofstream fout("turnuri.out");
7
8 struct cub
9 {
10 int l;
11 char c;
12 } C[10005];
13
14 int n, cerinta, i, j, turnuri, k, cul_ant, ultim;
15 unsigned long long h, hmax, hmax2;
16
17 int main()
18 {
19 fin >> cerinta >> n;
20 for (i = 1; i <= n; i++)
21 {
22 fin >> C[i].l; fin.get(); //latura
23 fin.get(C[i].c); //culoarea
24 }
25
26 //cerinta 1
27 turnuri = 0; h = C[1].l;
28 k = 2;
29 while (k <= n)
30 {
31 while (C[k].c != C[k-1].c && C[k].l < C[k-1].l)
32 {
33 h += C[k].l;
34 if (k == n)
35 ultim = 1; //tin minte ca ultimul cub l-am pus intr-un turn
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 81

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 }

Listing 5.2.9: turnuri8.cpp


1 #include <bits/stdc++.h>
2 using namespace std;
3
4 ifstream f("turnuri.in");
5 ofstream g("turnuri.out");
6
7 const int NM = 10001;
8 const int Ct = 1000000;
9 int t, n, x;
10 char ch;
11 int L[NM];
12
13 int main()
14 {
15 int i, j, k, nr = 0, top, ok;
16
17 f >> t >> n;
18 for(i=1; i<=n; ++i)
19 {
20 f >> x >> ch;
21 if (ch == ’a’)
22 L[i] = x + Ct;
23 else
24 L[i] = x + 2*Ct;
25 }
26
27 if (t == 1)
28 {
29 nr = 1, top = 1;
30 long long h = L[1] % Ct, H = L[1] % Ct;
31 for(i=2; i<=n; ++i)
32 {
33 if (L[i] / Ct != L[top] / Ct && L[top] % Ct >= L[i] % Ct)
34 {
35 h += L[i] % Ct;
36 top = i;
37 }
38 else
39 {
CAPITOLUL 5. OJI 2018 5.2. TURNURI - OJI 2018 82

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 }

5.2.3 *Rezolvare detaliată


Capitolul 6

OJI 2017

6.1 accesibil - OJI 2017


Problema 1 - accesibil 90 de
puncte
Un număr natural de cel puţin două cifre se numeşte accesibil dacă este format din cifre
consecutive ı̂n ordine strict crescătoare (23 şi 6789 sunt numere accesibile, ı̂n timp ce 7, 2334 şi
654 nu sunt numere accesibile).

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.

Restricţii şi precizări

a 2 & k & 9 şi 3 & n & 100000;


a 0 & numerele din şir & 2000000000;
a Din numărul 5073, de exemplu, prin eliminarea unei cifre se obţin numerele 507, 503, 573 şi
73;

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).

Timp maxim de executare/test: 0.4 secunde


Memorie: total 16 MB
Dimensiune maximă a sursei: 5 KB

6.1.1 Indicaţii de rezolvare

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.

6.1.2 Cod sursă

Listing 6.1.1: accesibil1.cpp


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 accesibil (int n)// verific daca n este accesibil
CAPITOLUL 6. OJI 2017 6.1. ACCESIBIL - OJI 2017 85

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 }

Listing 6.1.2: accesibil2.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 int m1, m2, m3, n, k, v[100010], acc, t;
6 int par[] = {0, 0, 4, 3, 3, 2, 2, 1, 1, 0};
7 int imp[] = {0, 0, 4, 4, 3, 3, 2, 2, 1, 1};
8
9 int accesibil(int x)
10 {
11 if (x < 10)
12 return 0;
13 while (x>=10 && x%10 == x/10%10 + 1)
14 x /= 10;
15
16 return (x < 10);
17 }
18
19 int aproapeAccesibil(int x)
20 {
21 if (x < 100)
22 return 0;
23 if (accesibil(x))
24 return 0;
25 int p = 1;
26 while (x / p != 0) {
27 if (accesibil(x/(p*10) * p + x % p))
28 return 1;
29 p*=10;
30 }
31 return 0;
32
33 }
34
35 int main ()
36 {
37 ifstream fin ("accesibil.in");
38 ofstream fout("accesibil.out");
39 fin>>t;
40 fin>>k>>n;
41
42 for (int i=1;i<=n;i++)
43 fin>>v[i];
44
45 if (t == 1)
46 {
47 int m1 = m2 = m3 = 0;
48 for (int i=1;i<=n;i++)
49 if (accesibil(v[i]))
50 {
51 acc++;
52 if (v[i] > m1)
53 {
54 m3 = m2;
55 m2 = m1;
56 m1 = v[i];
57 }
58 else
CAPITOLUL 6. OJI 2017 6.1. ACCESIBIL - OJI 2017 87

59 if (v[i] > m2)


60 {
61 m3 = m2;
62 m2 = v[i];
63 }
64 else
65 if (v[i] > m3)
66 m3 = v[i];
67 }
68
69 if (m3 == 0)
70 {
71 fout<<-1;
72 }
73 else
74 {
75 fout<<m3<<" "<<m2<<" "<<m1;
76 }
77
78 return 0;
79 }
80
81 if (t == 2)
82 {
83 int apa = 0;
84 for (int i=1;i<=n;i++)
85 if (aproapeAccesibil(v[i]))
86 apa++;
87 fout<<apa;
88 return 0;
89 }
90
91 if (t == 3)
92 {
93 for (int i=1;i<=k;i++)
94 fout<<i;
95
96 if (k!=9)
97 {
98 fout<<" ";
99 for (int i=9-k+1;i<=9;i++)
100 fout<<i;
101 }
102 return 0;
103 }
104
105 if (t == 4)
106 {
107 fout<<par[k]<<" "<<imp[k];
108
109 }
110
111 return 0;
112 }

Listing 6.1.3: accesibil3.cpp


1 //marinel serban //februarie 2017 //100 puncte
2
3 #include <bits/stdc++.h>
4
5 using namespace std;
6
7 ifstream fin("accesibil.in");
8 ofstream fout("accesibil.out");
9
10 int cerinta, k, n, x, xx;
11 int fata, spate, p10, p10_fata, p10_spate, nrcifre;
12 int V[100010];
13 int Pare[] = {0, 0, 4, 3, 3, 2, 2, 1, 1, 0};
14 int Impare[] = {0, 0, 4, 4, 3, 3, 2, 2, 1, 1};
15
16 int accesibil(int x)
17 {
18 int c;
CAPITOLUL 6. OJI 2017 6.1. ACCESIBIL - OJI 2017 88

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 }

Listing 6.1.4: accesibil4.cpp


1 #include <iostream>
2 #include <fstream>
3 #include <algorithm>
4
5 using namespace std;
6
7 ifstream f("accesibil.in");
8 ofstream g("accesibil.out");
9
10 int verif(long long n)
11 {
12 while(n%10==n/10%10+1 and n>10)
13 n=n/10;
14 if(n>9)
15 return 0;
16 return 1;
17 }
18
19 int verific_accesibil(long long n)
20 {
21 int nrcif,v[20],i,x,nr;
22 nrcif=0;
23 while(n)
24 {
25 nrcif++;
26 v[nrcif]=n%10;
27 n/=10;
28 }
29
30 x=1; //initial elimin prima cifra
31 while(x<=nrcif)
32 {
33 nr=0;
34 for(i=nrcif;i>=1;i--)
35 if(i!=x)
36 nr=nr*10+v[i];
37 if(nr>10 && verif(nr)==1) return 1;
38 x++;
39 }
40 return 0;
41 }
42
43 int acces1(long long n)
CAPITOLUL 6. OJI 2017 6.1. ACCESIBIL - OJI 2017 90

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 }

Listing 6.1.5: accesibil5.cpp


CAPITOLUL 6. OJI 2017 6.1. ACCESIBIL - OJI 2017 92

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 }

6.1.3 *Rezolvare detaliată

6.2 fermier - OJI 2017


Problema 2 - fermier 90 de
puncte
Dorel şi-a achiziţionat o fermă cu n plantaţii şi o maşină de transport cu o capacitate c, pentru
transportul de ı̂ngrăşăminte la toate plantaţiile. Îngrăşămintele se află ı̂ntr-un depozit, ı̂n cantitate
suficientă pentru scopul propus. Plantaţiile şi depozitul sunt dispuse sub forma unui cerc. Există
drumuri doar ı̂ntre plantaţia i şi plantaţia i  1 (1 & i & n  1), precum şi ı̂ntre depozit şi plantaţia
1 şi depozit şi plantaţia n, ca ı̂n figură.

Figura 6.1: fermier

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

Transportarea ı̂ngrăşămintelor pe plantaţii se face deci, ı̂ncepând cu plantaţia 1. După ce se


transportă toată cantitatea necesară pentru această plantaţie, se trece la plantaţia 2, şi tot aşa ı̂n
ordine la 3, 4 etc. până se deserveşte ultima plantaţie.
Dacă după ce s-au transportat ı̂ngrăşămintele necesare pentru plantaţia i ı̂n maşină au mai
rămas ı̂ncă ı̂ngrăşăminte, acestea trebuie utilizate ı̂n continuare pentru alte plantaţii, alese ı̂n
ordinea impusă (incepând cu plantaţia i  1, apoi i  2 etc.), până se epuizează toată cantitatea
transportată de maşină. Astfel, dacă de la plantaţia i trebuie să ajungă la plantaţia i  1, va
alege cel mai scurt traseu dintre traseul direct de la plantaţia i la i  1 şi traseul care trece prin
plantaţiile i  1, i  2, ..., 1, depozit, n, n  1, ..., i  1.
La final, maşina trebuie să se intoarcă la depozit, goală sau cu cantitatea rămasă după
aprovizionarea cu ingrăşăminte a plantaţiei n.

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.

Restricţii şi precizări

a 1 & n & 100;


a 1 & n & 2, pentru teste in valoare de 20 de puncte;
a 1 & di & 1000, 1 & i & n;
a 1 & qi & 1000, 1 & i & n;
a 1 & c & 1000;
a Se acordă 10 puncte din oficiu.

Exemple

fermier.in fermier.out Explicaţii


CAPITOLUL 6. OJI 2017 6.2. FERMIER - OJI 2017 96

36 22 La plantaţia 1 trebuie transportată o cantitate egală cu 13,


1 10 2 3 valoarea maximă pe care o poate transporta maşina fiind de
13 2 7 6. La plantaţia 1 se ajunge pe drumul cel mai scurt direct
de la depozit. Astfel se va merge mai intâi cu cantitatea 6,
ne ı̂ntoarcem la depozit, ı̂ncărcam iar maşina, ducem 6, ne
ı̂ntoarcem, ı̂ncărcăm şi lăsăm doar 1 (atât mai este necesar).
Pentru aceasta, s-a parcurs distanţa de 1  1  1  1  1 5.
În maşină a mai rămas acum o cantitate egală cu 5.
Trebuie să mergem acum la plantaţia 2 pe drumul cel mai
scurt. Pe drumul direct distanţa este 10, iar pe drumul invers
care trece iar prin depozit este 6 1  3  2. Vom alege drumul
cu distanţa 6. Lăsăm cantitatea 2 (atât e necesar plantaţiei
2), ne mai rămân 3 şi pentru plantaţia 3. De la plantaţia 2
se ajunge direct la plantaţia 3 pe o distanţă egală cu 2 sau
invers, trecând prin depozit pe o distanţă de 14 10  1  3.
Alegem drumul cu distanţa 2. Lăsăm ı̂ngrăşămintele rămase
şi mai mergem iar la depozit, ı̂ncărcăm şi lăsăm 4 la plantaţia
3. Pentru aceasta mai parcurgem distanţa 3  3.
La final maşina trebuie să se intoarcă la depozit, deci ı̂ncă un
drum cu distanţa 3. În total: 5  6  2  6  3 22.

Timp maxim de executare/test: 0.2 secunde


Memorie: total 16 MB
Dimensiune maximă a sursei: 5 KB

6.2.1 Indicaţii de rezolvare

Autor: prof. Timplaru Roxana, Colegiul ”Stefan Odobleja” Craiova.

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.

6.2.2 Cod sursă

Listing 6.2.1: fermier1.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("fermier.in");
7 ofstream g("fermier.out");
8
9 long long maxx, sens[102],st[102],dr[102],n, d[102], p[102];
10
11 void deplasari_st_dr(int i)
12 {
13 int j;
14 if (i==1)
CAPITOLUL 6. OJI 2017 6.2. FERMIER - OJI 2017 97

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 }

Listing 6.2.2: fermier2.cpp


1 #include <fstream>
CAPITOLUL 6. OJI 2017 6.2. FERMIER - OJI 2017 99

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 }

Listing 6.2.3: fermier3.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 int n,c,d[1001],q[1001], ca,drumtotal=0;
7
8 void read()
9 {
10 ifstream fin("fermier.in");
11
12 fin>>n;
13 fin>>c;
14
15 for(int i=0;i<=n;i++)
16 fin>>d[i];
17
18 for(int i=1;i<=n;i++)
19 fin>>q[i];
20
21 ca=c;
22 }
23
24 int dmin(int x, int y)
25 {
26 int k1=0,k2=0;
27 if(y>=x)
28 {
29 for(int i=x;i<y;i++)
30 k1=k1+d[i];
31 for(int i=x-1;i>=0;i--)
32 k2=k2+d[i];
33 for(int i=n;i>=y;i--)
34 k2=k2+d[i];
35 }
36 else
37 {
38 for(int i=x;i<=n;i++)
39 k1=k1+d[i];
40 for(int i=0;i<y;i++)
41 k1=k1+d[i];
42 for(int i=x-1;i>=y;i--)
43 k2=k2+d[i];
44 }
45
46 // cout<<x<<’ ’<<y<<’ ’<<k1<<’ ’<<k2<<endl;
47 if(k2>k1) return k1;
48 return k2;
49 }
50
51 void solve()
52 {
53 int x=0, y=1;
54 while(q[n]>0)
55 {
56 if(ca>0)
57 {
58 drumtotal=drumtotal+dmin(x,y);
59 x=y;
60 if(ca>=q[y])
61 {
62 ca=ca-q[y];
CAPITOLUL 6. OJI 2017 6.2. FERMIER - OJI 2017 101

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 }

Listing 6.2.4: fermier4.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("fermier.in");
7 ofstream g("fermier.out");
8
9 int n,i,d[102],dpart[102],x,q[102],ok,dtotal,c,a,b,dmin_depozit,total,dnext;
10
11 int main()
12 {
13 f>>n>>c;
14 for(i=1;i<=n+1;i++)
15 {
16 f>>d[i];
17 dtotal+=d[i];
18 dpart[i]=dpart[i-1]+d[i];
19 }
20
21 for(i=1;i<=n;i++)
22 f>>q[i];
23
24 b=c; // reprezinta cat am in masina
25 i=1; //parcela pe care sunt
26 while(q[n]!=0)
27 {
28 dmin_depozit=min(dpart[i],dtotal-dpart[i]);
29
30 if(b==c) //daca am masina plina
31 total+=dmin_depozit;//ma duc de la depozit la parcela
32 else
33 {
34 dnext=min(d[i],dtotal-d[i]); //ma duc de la parcela anterioara
35 total+=dnext;
36 }
37
38 while(q[i]>b)
39 {
40 q[i]-=b;
41 b=c;
42 total+=2*dmin_depozit; //am golit masina si ma duc inapoi la
43 // depozit si revin la parcela
CAPITOLUL 6. OJI 2017 6.2. FERMIER - OJI 2017 102

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 }

Listing 6.2.5: fermier5.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f ("fermier.in");
7 ofstream g ("fermier.out");
8
9 int d[102];
10 int q[102];
11
12 int main()
13 {
14 int cant=0,m,i,j,l,v1,v2,v,t=0,c,n;
15 f>>n>>c;
16 for (i=0; i<=n; i++)
17 {
18 f>>d[i];
19 t=t+d[i];
20 }
21
22 for (i=1; i<=n; i++) f>>q[i];
23
24 i=1; // incepem cu plantatia 1
25 while (i<=n)
26 {
27 m=c; // alimentam
28 v1=0;
29 for (j=0; j<i; j++) v1=v1+d[j];
30 v2=t-v1;
31 v=min(v1,v2); // v este drumul min pana la plantatia i
32 cant+=v;
33 if (m<q[i])
34 {
35 q[i]=q[i]-m;
36 cant=cant+v; // ma intorc la depozit
37 }
38 else
39 if (m==q[i])
40 {
CAPITOLUL 6. OJI 2017 6.2. FERMIER - OJI 2017 103

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 }

6.2.3 *Rezolvare detaliată


Capitolul 7

OJI 2016

7.1 cifre - OJI 2016


Problema 1 - cifre 90 de
puncte
Elevii clasei pregătitoare se joacă la matematică cu numere. Învăţătoarea are un săculeţ plin
cu jetoane, pe fiecare dintre ele fiind scrisă câte o cifră. Fiecare elev şi-a ales din săculeţ mai multe
jetoane, cu care şi-a format un număr. Pentru ca totul să fie mai interesant, elevii s-au grupat ı̂n
perechi. Doamna ı̂nvăţătoare a oferit fiecărei perechi de elevi câte o cutiuţă pentru ca cei doi să
ı̂şi pună ı̂mpreună jetoanele. De exemplu, dacă unul din elevii unei echipe şi-a ales jetoane cu care
a format numărul 5137131 iar celălalt elev şi-a ales jetoane cu care a format numărul 6551813,
atunci cutiuţa echipei va conţine 5 jetoane cu cifra 1, câte 3 jetoane cu cifra 3 şi 5 şi câte un jeton
cu cifrele 6, 7 şi 8.
Doar Andrei stătea supărat pentru că numărul de elevi al clasei era impar iar el nu avea
partener, motiv pentru care nu şi-a mai ales jetoane. Din această cauză, doamna ı̂nvăţătoare i-a
spus:
” Alege o echipă din a cărei cutiuţă poţi lua o parte din jetoane, dar ai grijă ca fiecare dintre
cei doi elevi să-şi mai poată forma numărul lui din jetoanele rămase, iar tu să poţi forma un număr
nenul cu jetoanele extrase!”.
Dar cum Andrei nu se mulţumea cu puţin, a vrut să aleagă acea echipă din a cărei cutiuţă ı̂şi
poată forma un număr de valoare maximă folosind jetoanele extrase.

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.

Restricţii şi precizări

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

Timp maxim de executare/test: 0.2 secunde


Memorie: total 2 MB
Dimensiune maximă a sursei: 15 KB

7.1.1 Indicaţii de rezolvare

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.

7.1.2 Cod sursă

Listing 7.1.1: cifre.cpp


1 #include<iostream>
2 #include<fstream>
3
4 using namespace std;
5
6 ifstream f("cifre.in");
7 ofstream g("cifre.out");
8
9 int a[10],b[10],n,i,x,y,j,k,p,cod,cate,maxim, minim;
10
11 int main()
12 {
13 f>>p>>n;
14 for(i=1;i<=n;i++)
15 {
16 f>>x>>y;
17
18 for(j=0;j<10;j++) a[j]=b[j]=0;
19 while(x) {a[x%10]++; x=x/10;}
20 while(y) {b[y%10]++; y=y/10;}
21
22 cod=0;
23 for(j=9;j>=0;j--)
CAPITOLUL 7. OJI 2016 7.2. LITERE - OJI 2016 106

24 if(a[j]>0 && b[j]>0)


25 {
26 if(a[j]<b[j]) minim=a[j]; else minim=b[j];
27 for(k=1;k<=minim;k++) cod=cod*10+j;
28 }
29
30 if(cod) cate++;
31 if(cod>maxim) maxim=cod;
32 }
33
34 if(p==1) g<<cate;
35 else g<<maxim;
36
37 g.close();
38
39 return 0;
40 }

7.1.3 *Rezolvare detaliată

7.2 litere - OJI 2016


Problema 2 - litere 90 de puncte
Un copil doreşte să găsească un mod original de a-şi codifica numele şi foloseşte ı̂n acest scop
o figură formată doar din triunghiuri, desenată pe o foaie de hârtie. El plasează fiecare literă din
numele său, ı̂n câte un triunghi. Dacă numele lui este DARIUS, atunci foaia de hârtie va arăta
ca ı̂n figura 1. Pe primul rând aşează prima literă, pe al doilea rând următoarele trei litere, pe al
treilea rând următoarele cinci litere, şi aşa mai departe până când aşează toate literele din nume.
Dacă numele nu are suficiente litere, copilul foloseşte caracterul * pentru a completa ultimul rând
pe care pe care a aşezat litere. Nemulţumit că numele poate fi citit relativ uşor, răstoarnă figura,
rotind foaia de hârtie, ı̂n sensul acelor de ceasornic, obţinând astfel figura 2.

Figura 7.1: Litere

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.

Restricţii şi precizări

a 1 & N & 10000


a Pentru rezolvarea corectă a cerinţei 1) se acordă 10 puncte, pentru rezolvarea corectă a
cerinţei 2) se acordă 30 de puncte, iar pentru rezolvarea corectă a cerinţei 3) se acordă 60 de
puncte.

Exemple

litere.in litere.out Explicaţii


1 3 Pentru scrierea numelui -Darius- se vor completa 3 rânduri, for-
6 mate din 9 triunghiuri, dintre care 3 vor conţine caracterul *.
DARIUS
2 DAU Prima literă de pe primul rând este D , prima literă de pe rândul
6 2 este A , prima literă de pe rândul 3 este U.
DARIUS
3 US AI R D După rotire, pe primul rând se află litera U, pe al doilea rând
6 literele S A, iar pe rândul al treilea, ı̂n ordine de la stânga la
DARIUS dreapta, literele I R D.

Timp maxim de executare/test: 0.2 secunde


Memorie: total 2 MB
Dimensiune maximă a sursei: 15 KB

7.2.1 Indicaţii de rezolvare

Autor: prof. Cardas Cerasela Daniela, Colegiul National A.T.Laurian Botosani

Citim cele n litere intr-un vector de caractere v.(indexat de la 1 la n)


Observam literele se vor aseza intr-o figura cu x nivele, n¡=x ˜ x, x cel mai mic numar natural
cu aceasta proprietate.
1) Determinam x, numarul de niveluri din figura, programul va afisa valoarea x ˜ x  n = nr
de caractere *.
2) Pentru fiecare nivel i din figura, v  i  1 ˜ i  1  1 reprezinta prima litera de pe nivel.
3) Completam vectorul v cu caractere * pana la pozitia x ˜ x.
Daca numerotam triunghiurile din figura initiala observam ca obtinem pentru 3 niveluri nu-
merele

Dupa rotire, triunghiul de numere va fi

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

7.2.2 Cod sursă

Listing 7.2.1: litere.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream fin("litere.in");
6 ofstream fout("litere.out");
7
8 int ord[10001],p,n,i,j,pas,k,x;
9 char v[10001];
10
11 int main()
12 {
13 fin>>p>>n;
14 for(i=1;i<=n;i++) fin>>v[i];
15
16 if(p==1)//1- nr de * de pe ultimul nivel
17 {
18 x=1;
19 while(x*x<n)x++;
20 fout<<x*x-n<<’\n’;
21 return 0;
22 }
23
24 if(p==2)//2- afisam prima litera de pe fiecare nivel
25 {
26 x=0;
27 while(x*x<n) {fout<<v[x*x+1]<<" ";x++;}
28 return 0;
29 }
30
31 // 3 - ordinea literelor dupa rotire
32 x=1;
33 while(x*x<n) x++;
34 for(i=x*x;i>n;i--) v[i]=’*’;
35
36 ord[1]=(x-1)*(x-1)+1;
37 k=1;
38 ord[0]=0;
39
40 for(i=2;i<=x;i++)//i este nivelul
41 {
42 j=ord[1]+2*i-2;pas=2*x-1;
43 for(;k<i*i-1;j-=pas,pas-=2)
44 {
45 ord[++k]=j;ord[++k]=j-1;
46 }
47 ord[++k]=j;
48 }
49
50 for(i=1,j=1;i<=x;i++)
51 {
52 for(;j<i*i;j++)
53 if(v[ord[j]]!=’*’)fout<<v[ord[j]]<<" ";
54 fout<<v[ord[j++]]<<’\n’;
55 }
56
57 return 0;
58 }

7.2.3 *Rezolvare detaliată


Capitolul 8

OJI 2015

8.1 covor - OJI 2015


Problema 1 - covor 90 de
puncte
Bunica Marei ţese un covor. Mara urmăreşte cu mare atenţie modelul şi ı̂ncearcă să-l recon-
stituie pe caietul de matematică. Modelul este format din romburi. Primul romb, de indice 1, are
latura formată din două pătrăţele, al doilea romb, de indice 2, are latura formată din trei pătrăţele
etc. Un romb de indice i are latura formată din i  1 pătrăţele.

Figura 8.1: Covor1

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.

Figura 8.2: Covor2

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

2. cel mai mic indice al unui romb ce conţine numărul k.

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.

Restricţii şi precizări

a 4 & n, k & 999999999; 1 & k & n


a Dacă numărul k nu se află pe niciunul dintre romburile complete ce pot fi construite folosind
maximum n numere, atunci răspunsul de la cerinţa 2 este 0.
a Pentru rezolvarea corectă a cerinţei 1 se acordă 30% din punctaj, iar pentru rezolvarea
corectă a cerinţei 2 se acordă 70% din punctaj.

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.

Timp maxim de executare/test: 0.5 secunde


Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 5 KB

8.1.1 Indicaţii de rezolvare

prof. Cristina Sichim, Colegiul National ”Ferdinand I” Bacau

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

8.1.2 Cod sursă

Listing 8.1.1: CPP SursaOficialaCovor.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("covor.in");
6 ofstream g("covor.out");
7
8 int n,k,r,p,m,c;
9
10 int main()
11 { f>>n>>k>>c;
12
13 r=1;
14 while(2*(r+1)*(r+2)-r<=n) r++;
15
16 if(c==1)
17 g<<r<<’\n’;
18 else
19 {
20 if(k> 2*r*(r+1)-(r-1)) g<<0<<’\n’;
21 else
22 { p=1;
23 m=1+r*(r+1);
24 if(k<=m) { while(k>1+p*(p+1))p++;
25 g<<p<<’\n’;
26 }
27 else
28 { p=r;
29 while(k>(m+2*p-1))
30 { m=m+2*p-1;
31 p--;
32 }
33 g<<p<<’\n’;
34 }
35 }
36 }
37
38 f.close();g.close();
39 return 0;
40 }

Listing 8.1.2: covor CarmenMinca.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f ("covor.in");
7 ofstream g ("covor.out");
8
9 int n, k, v;
10
11 int main()
12 {
13 f >> n >> k >> v;
14
15 int a1 = 3, r = 4;
16 int sol = 1, i = 1;
17 while(sol <= n)
18 {
19 sol = a1 * i + r * i * (i - 1) / 2 + 1;
20 i++;
21 }
22
23 i -= 2;
24 if (v == 1)
25 {
26 g << i << ’\n’;
CAPITOLUL 8. OJI 2015 8.1. COVOR - OJI 2015 112

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 }

Listing 8.1.3: covor CristinaIordaiche.cpp


1 # include <fstream>
2
3 using namespace std;
4
5 ifstream f("covor.in");
6 ofstream g("covor.out");
7
8 int main()
9 {
10 long long n, k, i=1, j=1, x, v;
11 f>>n>>k>>v;
12
13 if (n<4) {if(v==1) g<<’1’;}
14 else
15 {
16 while (i*(2*i+1)+1<=n)
17 i++;
18 if(v==1) {g<<i-1;}
19 }
20
21 if(v==2)
22 {
23
24 i--;
25 x=i*(i+1)+1;
26 if ((k>i*(2*i+1)+1) ) g<<’0’;
27 else
28 {
29 if (k==1) g<<’1’;
30 else
31 {
32 if (k==0) g<<’0’;
CAPITOLUL 8. OJI 2015 8.1. COVOR - OJI 2015 113

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 }

Listing 8.1.4: covor CristinaSichim.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("covor.in");
6 ofstream g("covor.out");
7
8 int n,k,r,p,m,c;
9
10 int main()
11 { f>>n>>k>>c;
12 r=1;
13 while(2*(r+1)*(r+2)-r<=n) r++;
14 if(c==1)
15 g<<r<<’\n’;
16 else
17 {
18 if(k> 2*r*(r+1)-(r-1)) g<<0<<’\n’;
19 else
20 { p=1;
21 m=1+r*(r+1);
22 if(k<=m)
23 {
24 while(k>1+p*(p+1))p++;
25 g<<p<<’\n’;
26 }
27 else
28 {
29 p=r;
30 while(k>(m+2*p-1))
31 {
32 m=m+2*p-1;
33 p--;
34 }
35 g<<p<<’\n’;
36 }
37 }
38 }
39
40 f.close();g.close();
41 return 0;
42 }

Listing 8.1.5: covor FloreUngureanu.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("covor.in");
6 ofstream g("covor.out");
7
8 int n,k,i,l,v;
CAPITOLUL 8. OJI 2015 8.1. COVOR - OJI 2015 114

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 }

Listing 8.1.6: covor LilianaChira.cpp


1 //prof. Liliana Chira
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("covor.in");
7 ofstream g("covor.out");
8
9 int n,k,i,x,y,a,d,b,v;
10
11 int main()
12 {
13 f>>n>>k>>v;
14 if(v==1)
15 {
16 for(i=1;;i++)
17 {
18 if(2*i*(i+1)-i+1>n)
19 {
20 x=i-1;
21 break;
22 }
23 }
24 g<<x<<endl;
25 }
26
27 if( v==2)
28 {
29 for(i=1;;i++)
30 {
31 if(2*i*(i+1)-i+1>n)
32 {
33 x=i-1;
34 break;
35 }
36 }
CAPITOLUL 8. OJI 2015 8.1. COVOR - OJI 2015 115

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 }

Listing 8.1.7: covor RoxanaTamplaru.cpp


1 #include <iostream>
2 #include <fstream>
3 using namespace std;
4
5 ifstream f("covor.in");
6 ofstream g("covor.out");
7 int n,k,v;
8
9 void calcul()
10 { long long i,nr,t,r, s;
11 //numar romburi complete
12 nr=1;
13 while ((nr+1)*(nr+2)/2+nr*(nr-1)+nr*(nr+1)/2<=n)
14 nr++;
15 if (v==1)g<<nr-1;
16 else
17 {
18 t=0;
19 s=1;
20 while (s+2*t<k && t<=nr-1)
21 { s=s+2*t;
22 t++;
23 }
24 if (t<=nr-1)
25 g<<t;
26 else
27 {
28 t--;
29 while (s+t+t-1<k && t>=1)
30 {
31 s=s+t+t-1;
32 t--;
33 }
34 if (s+2*t-1<k) g<<0;
35 else
36 g<<t;
37 }
38 }
39 }
40 int main()
41 {
42 f>>n>>k>>v;
43 calcul();
44 return 0;
45 }
CAPITOLUL 8. OJI 2015 8.2. ORDINE - OJI 2015 116

8.1.3 *Rezolvare detaliată

8.2 ordine - OJI 2015


Problema 2 - ordine 90 de puncte
Gigel a primit de ziua lui un joc cu bile. Jocul conţine
n bile numerotate cu numerele naturale distincte de la
1 la n. Jucându-se, Gigel a amestecat bilele astfel ı̂ncât
acum ele nu mai sunt ı̂n ordine. Ca să le pună ı̂napoi ı̂n
cutia jocului, Gigel ia de pe masă bilele una câte una,
şi le pune ı̂n cutie formând un şir. Însă Gigel se joacă
şi acum, astfel ı̂ncât el nu pune bilele la rând, una după
alta, ci are o regulă pe care o respectă cu stricteţe. Astfel,
Figura 8.3: Ordine
Gigel ı̂ncearcă să plaseze fiecare bilă pe care a luat-o de pe masă exact la mijlocul şirului de bile
deja format. Dacă acest lucru nu este posibil (şirul are lungime impară), atunci el plasează bila la
sfârşitul şirului de bile deja format. După ce toate bilele au fost puse ı̂n cutie, Gigel ı̂şi dă seama
că nu a notat ordinea ı̂n care a luat bilele de pe masă şi, ı̂n mod firesc, ı̂şi pune problema dacă nu
cumva poate deduce acest lucru din şirul de bile pe care tocmai l-a format.

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

Fişierul de ieşire ordine.out va conţine pe prima linie o valoarea naturală reprezentând


numărul ultimei bile luate de Gigel, dacă cerinţa a fost 1, respectiv n numere naturale, cu valori
cuprinse ı̂ntre 1 şi n, separate prin câte un spaţiu, care reprezintă ordinea ı̂n care Gigel a luat
bilele de pe masă, dacă cerinţa a fost 2.

Restricţii şi precizări

a 1 & n & 250000


a Pentru cerinţa 1 se acordă 30% din punctaj, iar pentru cerinţa 2 se acordă 70% din punctaj.

Exemple

ordine.in ordine.out
7 5
1725346
1
7 1374265
1725346
2

Timp maxim de executare/test: 1.0 secunde


Memorie: total 8 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 5 KB
CAPITOLUL 8. OJI 2015 8.2. ORDINE - OJI 2015 117

8.2.1 Indicaţii de rezolvare

prof. Marinel Serban, Colegiul National ”Emil Racovita” Iasi

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 ...

Figura 8.4: Covor1

8.2.2 Cod sursă

Listing 8.2.1: CPP SursaOficialaOrdine.cpp


1 //serban marinel decembrie 2014
2 //cu 1 vector - direct din citire O(n)
3
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 b[DIM];
CAPITOLUL 8. OJI 2015 8.2. ORDINE - OJI 2015 118

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 }

Listing 8.2.2: ordine CarmenMinca.cpp


1 //#include <iostream>
2
3 #include <fstream>
4
5 using namespace std;
6
7 int v[500001],n;
8 ifstream f("ordine.in");
9 ofstream g("ordine.out");
10
11 int main()
12 { int i, k, p,j;
13 f>>n;
14 for(i=1;i<=n;i++)f>>v[i];
15 f>>k;
16 if(k==1)
17 {
18 if(n%2)p=(n+1)/2;
19 else p=n;
20 g<<v[p]<<endl;
21 }
22 else
23 {
24 p=(n+1)/2+1;
25 i=1;j=p;
26 while (i<p && j<=n)
27 {
28 g<<v[i]<<" "<<v[j]<<" ";
29 i++; j++;
30 }
31 if(i<p)g<<v[i];
32 if(j<=n)g<<v[j];
33 g<<endl;
34 }
35
36 return 0;
37 }

Listing 8.2.3: ordine CristinaIordaiche.cpp


1 #include<fstream>
2 #include<vector>
3
4 using namespace std;
5
6 ifstream fin("ordine.in");
CAPITOLUL 8. OJI 2015 8.2. ORDINE - OJI 2015 119

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 }

Listing 8.2.4: ordine CristinaSichim.cpp


1 #include <fstream>
2 #include <vector>
3
4 using namespace std;
5
6 ifstream f("ordine.in");
7 ofstream g("ordine.out");
8
9 int n,i,j,m,k;
10 vector <int> v;
11
12 int main()
13 {
14 f>>n;
15 for(i=1;i<=n;i++)
16 {
17 f>>k;
18 v.push_back(k);
CAPITOLUL 8. OJI 2015 8.2. ORDINE - OJI 2015 120

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 }

Listing 8.2.5: ordine FloreUngureanu.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("ordine.in");
6 ofstream g("ordine.out");
7
8 int n,i,j,m,k, v[500001];
9
10 int main()
11 { f>>n;
12 for(i=1;i<=n;i++)f>>v[i];
13
14 f>>k;
15
16 if(k==1)
17 if(n%2==0) g<<v[n]<<’\n’;
18 else g<<v[n/2+1]<<’\n’;
19 else
20 {
21 i=1;j=(n+1)/2;
22 for(i=1;i<=n/2;i++) g<<v[i]<<’ ’<<v[i+j]<<’ ’;
23 if(n%2) g<<v[j]<<’ ’;
24 g<<’\n’;
25 }
26
27 f.close();
28 g.close();
29 return 0;
30 }

Listing 8.2.6: ordine GinaBalacea.cpp


1 #include<fstream>
2
3 using namespace std;
4
5 int o[250001],n,i,c,k,N,b1,b2;
6
7 ifstream f("ordine.in");
8 ofstream g("ordine.out");
9
10 int main()
11 {
12 f>>n;
13 k=1;
14
15 if(n==1)
16 {
17 f>>o[1];b1=o[1];
18 }
19 else
CAPITOLUL 8. OJI 2015 8.2. ORDINE - OJI 2015 121

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 }

Listing 8.2.7: ordine LilianaChira.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("ordine.in");
6 ofstream g("ordine.out");
7
8 int main()
9 {
10 long n,a[50001];
11 int i,k,m;
12
13 f>>n;
14
15 for(i=1;i<=n;i++)
16 f>>a[i];
17
18 f>>m;
19 if(m==1)
20 if(n%2==0) g<<a[n];
21 else g<<a[(n+1)/2];
22
23 if(m==2)
24 {
25 i=1;
26 k=n/2+n%2;
27 while(i<=n/2)
28 {
29 g<<a[i]<<" "<<a[i+k]<<" ";
30 i++;
31 }
32
33 if(n%2==1) g<<a[i];
34 }
35
36 return 0;
37 }

Listing 8.2.8: ordine MarinelSerban.cpp


1 //serban marinel decembrie 2014
2 //cu 2 vectori O(2n)
3
CAPITOLUL 8. OJI 2015 8.2. ORDINE - OJI 2015 122

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 }

Listing 8.2.9: ordine RoxanaTamplaru.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("ordine.in");
7 ofstream g("ordine.out");
8
9 int n,x[500001],k,y[500001],i,j,m;
10
11 int main()
12 {
13 f>>n;
14 m=n;
15 for (i=1;i<=n;i++)
16 f>>x[i];
17 f>>k;
18 if (k==1)
19 if (n%2==1) g<<x[(n+1)/2];
20 else g<<x[n];
21 else
22 {
23 k=1;
24 for (i=1;i<=(n+1)/2;i++)
25 {
26 y[k]=x[i];
CAPITOLUL 8. OJI 2015 8.2. ORDINE - OJI 2015 123

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 }

8.2.3 *Rezolvare detaliată


Capitolul 9

OJI 2014

9.1 imprimanta - OJI 2014


Problema 1 - imprimanta 90 de puncte

Cif-Oji6 este o imprimantă matriceală numită şi imprimantă cu ace, deoarece


tipărirea se realizează prin impactul acelor capului de imprimare pe o bandă cu
tuş.
Acele sunt aranjate ı̂ntr-o grilă dreptunghiulară formată din 5 rânduri de ace,
pe fiecare rând aflându-se la distanţe egale câte 3 ace, aşa cum se observă ı̂n
figura alăturată.
Prin acţionarea diferitelor combinaţii de ace din grilă, se defineşte forma
fiecărei cifre ce permite tipărirea acesteia prin puncte, ı̂n felul următor: Figura 9.1:
Imprimanta1

Figura 9.2: Imprimanta2

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

Fişierul de ieşire imprimanta.out va conţine:


- pe prima linie un singur număr natural ce reprezintă cea mai mare cifră a numărul N pentru
care s-a acţionat un număr minim de ace ale grilei.
- pe cea de-a doua linie a fişierului se va scrie cel mai mare număr natural ce poate fi tipărit
prin K puncte.

124
CAPITOLUL 9. OJI 2014 9.1. IMPRIMANTA - OJI 2014 125

Restricţii şi precizări

a 10 & N & 1015


a 14 & K & 100000
a Pentru rezolvarea corectă a cerinţei a) se acordă 30% din punctajul fiecărui test iar pentru
rezolvarea corectă a cerinţei b) se acordă 70% din punctajul fiecărui test.

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.

Timp maxim de executare/test: 1.0 secunde


Memorie: total 2 MB din care pentru stivă 1 MB
Dimensiune maximă a sursei: 5 KB

9.1.1 Indicaţii de rezolvare

Figura 9.3: ImprimantaIR2


CAPITOLUL 9. OJI 2014 9.1. IMPRIMANTA - OJI 2014 126

Figura 9.4: ImprimantaIR2

9.1.2 Cod sursă

Listing 9.1.1: imprimanta cristina 0.cpp


1 //Iordaiche Cristina
2
3 #include <fstream>
4
5 using namespace std;
6
7 ifstream f("imprimanta.in");
8 ofstream g("imprimanta.out");
9
10 int main()
11 {
12 long long N,K;
13 int c,minim_ace=15,cifra_maxima=0,nrace,nr_maxim_de_cifre, puncte_ramase,i;
14 f>>N>>K;
15 f.close();
16
17 //Rezolvare cerinta a)
18 while(N)
19 {
20 c=N%10;
21 switch(c)
22 {
23 case 0:
24 case 6:
25 case 9: nrace=12;break;
26 case 1: nrace=5;break;
27 case 2:
28 case 3:
29 case 5: nrace=11;break;
30 case 4: nrace=9;break;
31 case 7: nrace=7;break;
32 case 8: nrace=13;break;
33 }
34
35 if(nrace<minim_ace)
36 {
37 minim_ace=nrace;
38 cifra_maxima=c;
39 }
40 else
CAPITOLUL 9. OJI 2014 9.1. IMPRIMANTA - OJI 2014 127

41 if(nrace==minim_ace && c>cifra_maxima)


42 cifra_maxima=c;
43 N=N/10;
44 }
45
46 g<<cifra_maxima<<’\n’;
47
48 //Rezolvare cerinta b)
49 nr_maxim_de_cifre=K/5; puncte_ramase=K%5;
50 switch(puncte_ramase)
51 {
52 case 0: g<<"11";break;
53 case 1: g<<’7’;
54 if(nr_maxim_de_cifre==3) {g<<’4’;nr_maxim_de_cifre=0;}
55 else {g<<"77"; nr_maxim_de_cifre-=2;}
56 break;
57 case 2: g<<"71";break;
58 case 3: g<<’8’;break;
59 case 4: g<<"77";break;
60 }
61
62 for(i=1;i<=nr_maxim_de_cifre-2;i++)
63 g<<’1’;
64 g<<’\n’;
65
66 return 0;
67 }

Listing 9.1.2: imprimanta cristina 1.cpp


1 //Cristina Iordaiche
2
3 #include <fstream>
4
5 using namespace std;
6
7 ifstream f("imprimanta.in");
8 ofstream g("imprimanta.out");
9
10 int main()
11 {
12 long long N,K;
13 int c,minim_ace=15,cifra_maxima=0,nrace,nr_maxim_de_cifre, puncte_ramase,i;
14 f>>N>>K;
15 f.close();
16
17 while(N)
18 {
19 c=N%10;
20 switch(c)
21 {
22 case 0:
23 case 6:
24 case 9: nrace=12;break;
25 case 1: nrace=5;break;
26 case 2:
27 case 3:
28 case 5: nrace=11;break;
29 case 4: nrace=9;break;
30 case 7: nrace=7;break;
31 case 8: nrace=13;break;
32 }
33
34 if(nrace<minim_ace)
35 {
36 minim_ace=nrace;
37 cifra_maxima=c;
38 }
39 else
40 if(nrace==minim_ace && c>cifra_maxima)
41 cifra_maxima=c;
42
43 N=N/10;
44 }
45
CAPITOLUL 9. OJI 2014 9.1. IMPRIMANTA - OJI 2014 128

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 }

Listing 9.1.3: imprimanta lili.cpp


1 #include<cstdio>
2
3 using namespace std;
4
5 const int P[]= {12,5,11,11,9,11,12,7,13,12};
6
7 long long N;
8 int K,Min=14,Cif;
9 long long V[100];
10
11 int Point(long long x)
12 {
13 int ans=0;
14 if(!x) return P[0];
15 for(;x;x/=10)
16 ans+=P[x%10];
17 return ans;
18 }
19
20 int main()
21 {
22 int i;
23
24 freopen("imprimanta.in","r",stdin);
25 freopen("imprimanta.out","w",stdout);
26
27 scanf("%lld%d",&N,&K);
28
29 for(; N; N/=10)
30 if(P[N%10]<Min || (P[N%10]==Min && N%10>Cif))
31 {
32 Min=P[N%10];
33 Cif=N%10;
34 }
35
36 printf("%d\n",Cif);
37
38 /* Pentru a fi maxim, numarul format trebuie sa contina
CAPITOLUL 9. OJI 2014 9.1. IMPRIMANTA - OJI 2014 129

39 doar cifrele 1, 4, 7, 5, 9, 8, astfel incat cifra mai


40 mare sa apara inaintea oricarei alte cifre mai mici.
41
42 ˆForget it, imi ajung numai 1, 7 si 8*/
43
44 if(K%5==0)
45 {
46 for(i=1;i<=K/5;i++) printf("1");
47 printf("\n");
48 }
49
50 if(K%5==1)
51 {
52 if(K==16) printf("74");
53 else printf("777");
54 for(i=1; i<=(K-3*P[7])/5; i++) printf("1");
55 printf("\n");
56 }
57
58 if(K%5==2)
59 {
60 printf("7");
61 for(i=1; i<=(K-1*P[7])/5; i++) printf("1");
62 printf("\n");
63 }
64
65 if(K%5==3)
66 {
67 printf("8");
68 for(i=1; i<=(K-1*P[8])/5; i++) printf("1");
69 printf("\n");
70 }
71
72 if(K%5==4)
73 {
74 printf("77");
75 for(i=1; i<=(K-2*P[7])/5; i++) printf("1");
76 printf("\n");
77 }
78
79 return 0;
80 }

Listing 9.1.4: imprimanta marinel.cpp


1 //Marinel Serban O(k)
2
3 #include <fstream>
4
5 using namespace std;
6
7 ifstream fin("imprimanta.in");
8 ofstream fout("imprimanta.out");
9
10 long long N, K, s_max, s;
11 int cifra, ace, min_ace = 25, max_cifra, i;
12
13 int main()
14 {
15 fin >> N >> K;
16
17 //punctul a)
18 while (N)
19 {
20 cifra = N % 10;
21 N /= 10;
22 switch (cifra)
23 {
24 case 0:
25 case 6:
26 case 9: ace = 12; break;
27 case 1: ace = 5; break;
28 case 2:
29 case 3:
30 case 5: ace = 11; break;
CAPITOLUL 9. OJI 2014 9.1. IMPRIMANTA - OJI 2014 130

31 case 4: ace = 9; break;


32 case 7: ace = 7; break;
33 case 8: ace = 13; break;
34 }
35 if (ace < min_ace)
36 {
37 min_ace = ace;
38 switch (ace)
39 {
40 case 12: max_cifra = cifra; break;
41 case 11: max_cifra = cifra; break;
42 case 5: max_cifra = 1; break;
43 case 7: max_cifra = 7; break;
44 case 9: max_cifra = 4; break;
45 case 13: max_cifra = 8; break;
46 }
47 }
48 else
49 if (ace == min_ace)
50 switch (ace)
51 {
52 case 12: if (cifra>max_cifra) max_cifra = cifra; break;
53 case 11: if (cifra>max_cifra) max_cifra = cifra; break;
54 }
55 }
56 fout << max_cifra << ’\n’;
57
58 //punctul b)
59 if (K % 5 == 0)
60 for (i = 1; i <= K / 5; ++i) fout << 1; //numai 1
61 else
62 if (K % 5 == 1)
63 {
64 if (K == 16) fout << 74; //caz particular
65 else
66 {
67 fout << 777; //21 ace (3 * 7)
68 for (i = 1; i <= (K - 21) / 5; ++i) fout << 1;//restul 1 (cate 5 ace)
69 }
70 }
71 else
72 if (K % 5 == 2)
73 {
74 fout << 7; //7 ace (2+5)
75 for (i = 1; i <= (K - 7) / 5; ++i) fout << 1; //restul 1
76 }
77 else
78 if (K % 5 == 3)
79 {
80 fout << 8; //13 ace (3+2*5)
81 for (i = 1; i <= (K - 13)/ 5; ++i) fout << 1; //restul 1
82 }
83 else
84 {
85 fout << 77; //9 ace (4+5)
86 for (i = 1; i <= (K - 14) / 5; ++i) fout << 1;
87 }
88
89 fout << ’\n’;
90 fout.close();
91 return 0;
92 }

Listing 9.1.5: imprimanta mot.cpp


1 // imprimanta Eu Nistor Mot - O(k)
2
3 #include <fstream>
4
5 using namespace std;
6
7 int main()
8 { ifstream fi("imprimanta.in"); ofstream fo("imprimanta.out");
9 int k,i,cm,pm,r,p[10]={12,5,11,11,9,11,12,7,13,12};
10 long long int n;
CAPITOLUL 9. OJI 2014 9.1. IMPRIMANTA - OJI 2014 131

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 }

Listing 9.1.6: imprimanta ovidiu.cpp


1 //solutie Ovidiu Marcu
2
3 #include <fstream>
4
5 using namespace std;
6
7 ifstream f("imprimanta.in");
8 ofstream g("imprimanta.out");
9
10 int ap[10]={12,5,11,11,9,11,12,7,13,12};
11
12 long long n;
13 int pmin=100,cfmax,cf,k;
14
15 void afis_1(int k){ for(int i = 4 ;i<= k ; i++ ) g<<1;}
16
17 int main()
18 {
19 f>>n>>k;
20
21 while ( n )
22 {
23 cf = n%10; n = n/10;
24 if( ap[ cf ] < pmin ) {pmin = ap[ cf ] ; cfmax=cf; }
25 else
26 if ( ap[ cf ] == pmin )
27 if( cfmax < cf )
28 cfmax = cf ;
29 }
30
31 g <<cfmax<< ’\n’;
32
33 if( k == 14 ) g<<77;
34 else
35 {
36 int rest = k%5 ;
37 int cat = k/5;
38
39 if ( rest == 0 ) { g<<111; afis_1(cat);}
40 if ( rest == 1 )
41 if ( cat >=4 )
42 {
43 g<<777;
44 afis_1(cat-1);
45 }
46 else
CAPITOLUL 9. OJI 2014 9.2. MUNTE - OJI 2014 132

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 }

9.1.3 *Rezolvare detaliată

9.2 munte - OJI 2014


Problema 2 - munte 90 de puncte
Se consideră un şir x1 , x2 , ..., xn format din n numere naturale distincte. O secvenţă de număr
maxim de elemente vecine ı̂n şir, de forma xi , xi1 , ..., xk1 , xk , xk1 , ..., xj (1 & i $ k $ j & n) cu
proprietatea că xi $ xi1 $ ... $ xk1 $ xk % xk1 % ... % xj , se numeşte munte cu vârful xk .
Două secvenţe munte au maxim un element comun ı̂n şir. O secvenţă munte are cel puţin 3
elemente. Un exemplu de şir format cu valorile 3 4 6 8 nu conţine nicio secvenţă munte, iar unul
format cu valorile 3 4 8 1 2 5 0 conţine 2 secvenţe munte: 3 4 8 1 şi 1 2 5 0.
După determinarea tuturor secvenţelor munte şi a vârfurilor acestora, se elimină din şir
vârfurile secvenţelor munte şi procedura continuă repetat cu determinarea noilor secvenţe munte
şi a vârfurilor lor din şirul nou obţinut. Procedura se opreşte ı̂n momentul ı̂n care ı̂n şir nu mai
există nicio secvenţă munte.

Cerinţe

Scrieţi un program care citeşte numerele n, x1 , x2 , ..., xn şi apoi determină:


a) numărul de secvenţe munte din şirul iniţial;
b) numărul total de secvenţe munte obţinute pornind de la şirul iniţial până la cel care nu mai
conţine nicio secvenţă munte;
c) numărul de elemente din şirul final care nu mai conţine secvenţe munte.

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).

Restricţii şi precizări

3 & n & 100


a
0 & xi & 100000, 1 & i & n
a
a Pentru rezolvarea corectă a cerinţei a) se obţine 20% din punctaj.
a Pentru rezolvarea corectă a cerinţei b) se obţine 40% din punctaj.
a Pentru rezolvarea corectă a cerinţei c) se obţine 40% din punctaj.
a Pentru testele date se asigură că şirul de numere dat iniţial conţine cel puţin o secvenţă
munte.

Exemple

munte.in munte.out Explicaţii


CAPITOLUL 9. OJI 2014 9.2. MUNTE - OJI 2014 133

8 2 a) Sunt două secvenţe munte: 1250 şi 0693


12506934 4 b) După eliminarea vârfurilor secvenţelor munte, şirul
4 nou este 120634. Acest şir conţine 2 secvenţe munte:
120 şi 063. După eliminarea vârfurilor secvenţelor munte,
şirul nou este 1034. Noul şir nu mai conţine nicio secvenţă
munte. În total sunt deci 4 secvenţe.
c) şirul final care nu mai conţine secvenţe munte 1034 are
4 elemente.

Timp maxim de executare/test: 0.1 secunde


Memorie: total 2 MB din care pentru stivă 1 MB
Dimensiune maximă a sursei: 5 KB

9.2.1 Indicaţii de rezolvare

Autor: prof. Timplaru Roxana, Colegiul ”Stefan Odobleja” Craiova.

Solutia 1 100 puncte


Se cauta elementele din sir care sunt varfurile unei secvente munte si se pastreaza pozitiile lor
intr-un vector. Se afiseaza numarul de elemente din acest vector.
Se elimina varfurile din vectorul initial si se repeta algoritmul pana la intalnirea unui sir care
nu mai contine secvente. Se numara la fiecare pas secventele munte obtinute.
Se afiseaza numarul lor si numarul de elemente din sirul final care nu mai contine secvente
munte.
Solutia 2 100 puncte
Se cauta secvente de tip munte si se retin valorile varfurilor. Se afiseaza numarul secventelor
gasite.
Se elimina varfurile din vector si se repeta algoritmul pana la intalnirea unui sir care nu mai
contine secvente.
Pentru eliminare se poate folosi un vector y, in care daca elementul xk  este varf, y xk  1,
iar restul elementelor raman egale cu 0.
La parcurgerea sirului vor fi eliminate elementele xi pentru care y xi 1.
La fiecare parcuregere a sirului, se numara secventele munte obtinute.
Se afiseaza numarul lor si numarul de elemente din sirul final care nu mai contine secvente
munte.
Solutia 3 100 puncte
Se cauta doar varfurile (ele sunt mai mari ca vecinii lor din stanga/dreapta) si se contorizeaza.
La prima parcurgere se afiseaza rezultatul pentru cerinta a).
Celelalte elemente, care nu sunt varfuri, se copiaza in alt sir.
La sfarsit se copiaza noul sir in vechiul sir. Noul n este exact lungimea acestuia.
Se reia procedura.
La final - cand nu mai exista nicio secventa munte - se afiseaza numarul total de varfuri (cerinta
b) si ultima valoare n (cerinta c).

9.2.2 Cod sursă

Listing 9.2.1: munte csifo.cpp


1 //csifo lorand
2 #include <fstream>
3 #define NMAX 101
4
5 using namespace std;
6
7 int n, i, j, k, v[NMAX], varf[NMAX];
8 bool ok;
CAPITOLUL 9. OJI 2014 9.2. MUNTE - OJI 2014 134

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 }

Listing 9.2.2: munte lili0.cpp


CAPITOLUL 9. OJI 2014 9.2. MUNTE - OJI 2014 135

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 }

Listing 9.2.3: munte lili1.cpp


1 //prof. Liliana Chira
2
3 #include<cstdio>
4 #include<bitset>
5
6 using namespace std;
7
8 int N,a,b;
9 int V[105];
10
11 bitset<105> B;
12
13 int main()
14 {
CAPITOLUL 9. OJI 2014 9.2. MUNTE - OJI 2014 136

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 }

Listing 9.2.4: munte marinel 1.cpp


1 //Serban Marinel
2 //O(nxn)
3 #include <fstream>
4
5 using namespace std;
6
7 #define MAX 1000000
8
9 ifstream fin("munte.in");
10 ofstream fout("munte.out");
11
12 int n, i, j, parcurgere, munti = 0, cati;
13 int x[110];
14 bool gasit_munte;
15
16 int main()
17 {
18 fin >> n;
19 for (i = 1; i <= n; ++i) fin >> x[i];
20 parcurgere = 1;
21 gasit_munte = true;
22 while (gasit_munte)
23 {
24 gasit_munte = false; cati = 0;
25 i = 1;
26 while (i<n && x[i]>x[i+1]) i++; //trec peste primii descrescatori
CAPITOLUL 9. OJI 2014 9.2. MUNTE - OJI 2014 137

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 }

Listing 9.2.5: munte marinel 2.cpp


1 // serban marinel
2 // O(n x parcurgeri)
3 // utilizeaza vector suplimentar
4
5 #include <fstream>
6 #include <cstring>
7
8 using namespace std;
9
10 #define MAX 1000000
11
12 ifstream fin("munte.in");
13 ofstream fout("munte.out");
14
15 int n, i, j, parcurgere, munti = 0, cati;
16 int x[110], x1[110];
17 bool gasit_munte;
18
19 int main()
20 {
21 fin >> n;
22 for (i = 1; i <= n; ++i) fin >> x[i]; //citire
23 parcurgere = 1; //numar parcurgerile
24 gasit_munte = true; //tine minte daca a gasit un munte
25
26 while (gasit_munte) //cat timp a mai gasit
27 {
28 gasit_munte = false; //presupune ca nu a gasit
29 j = 1;
30 x1[j] = x[j]; //copiaza in x1 pe x[1] (asta nu poate fi varf)
31
CAPITOLUL 9. OJI 2014 9.2. MUNTE - OJI 2014 138

32 for (i = 2; i < n; ++i) //cauta elemente mai mari decat vecinii


33 if (x[i] > x[i-1] && x[i] > x[i+1])//astia sunt varfuri de munte
34 gasit_munte = true, munti++; //am gasit, numar
35 else //altfel
36 x1[++j] = x[i]; //nu este varf il copiez in x1
37
38 x1[++j] = x[n]; //il copiez si pe x[n] (nu poate fi varf)
39 if (parcurgere == 1) //daca sunt la prima trecere
40 fout << munti << ’\n’; //afisez cati munti am gasit
41
42 parcurgere++; //trec la alta parcurgere
43 memcpy(x, x1, sizeof(x1)); //copiez x1 in x
44 n = j; //atatea elemente mai am
45 memset(x1, 0, sizeof(x1)); //pun x1 pe 0
46 }
47
48 fout << munti << ’\n’;
49 fout << n << ’\n’;
50 fout.close();
51
52 return 0;
53 }

Listing 9.2.6: munte ovidiu 1.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5 ifstream f("munte.in");
6 ofstream g("munte.out");
7
8 int a[1000],n,i,j,total,local,prima= -1, ultim ;
9
10 int main()
11 {
12 f >> n ;
13 for( i =1 ; i <= n; i++ ) f >> a[i];
14
15 do
16 {
17 i = 2 ;
18 local = 0;
19 ultim=0;
20 while( i <= n - 1 )
21 if( a[ i - 1 ] < a[ i ] and a[ i ] > a[ i + 1 ] and ultim != i )
22 {
23 local++;
24 ultim = i;
25 for(j= i + 1 ; j <= n ; j++ ) a[ j-1 ]=a[ j ];
26 n--;
27 }
28 else i++;
29
30 if(prima == -1)
31 {
32 prima = local;
33 g<<local<<’\n’;
34 }
35
36 total = total + local ;
37 } while(local);
38
39 g<<total<<’\n’<<n<<’\n’;
40
41 return 0;
42 }

Listing 9.2.7: munte ovidiu 2.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
CAPITOLUL 9. OJI 2014 9.2. MUNTE - OJI 2014 139

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 }

Listing 9.2.8: munte roxana1.cpp


1 //Timplaru Roxana
2
3 #include <iostream>
4 #include <fstream>
5
6 using namespace std;
7
CAPITOLUL 9. OJI 2014 9.2. MUNTE - OJI 2014 140

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 }

Listing 9.2.9: munte roxana2.cpp


1 //Timplaru Roxana
2
3 #include <fstream>
4 #include <iostream>
5
6 using namespace std;
7
8 int main()
9 {
10 ifstream f("munte.in");
11 ofstream g("munte.out");
12 long x[101],i;
13 int q,n,t=0,j,k,ok=1,nr=0,gasit,y[100000];
14
15 f>>n;
16 for (i=1;i<=n;i++)
17 f>>x[i];
18
19 for(i=0;i<=100000;i++) y[i]=0;
20
21 do
22 {
23 ok=0;t++;i=1;q=i;
24 while (i<n)
25 {
26 gasit=0;
27 while (i<n && x[i]<x[i+1])
28 {
29 gasit=1;i++;
30 }
31
32 if (gasit)
33 {
CAPITOLUL 9. OJI 2014 9.2. MUNTE - OJI 2014 141

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 }

9.2.3 *Rezolvare detaliată


Capitolul 10

OJI 2013

10.1 cladiri - OJI 2013


Problema 1 - cladiri 100 de puncte
Având mai multe cuburi la dispoziţie, Crina şi Rareş au hotărât să construiască clădiri prin
alipirea a două sau mai multor turnuri. Turnurile au fost obţinute prin aşezarea cuburilor unul
peste celălalt. Înălţimea unui turn este dată de numărul de cuburi din care este format.
Clădirile construite au fost aşezate ı̂n linie, una lângă alta formând astfel o stradă, pe care cei
doi copii se vor plimba.
Pentru numerotarea clădirilor Crina şi Rareş au stabilit următoarele reguli:
- Crina porneşte dintr-un capăt al străzii, iar Rareş din celălalt capăt al acesteia; fiecare dintre
ei traversează strada complet, trecând prin dreptul fiecărei clădiri

Figura 10.1: Imprimanta2

- 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).

Restricţii şi precizări

- 1 & N & 10000


- Fiecare clădire este alcătuită din cel mult 9 turnuri, iar ı̂nălţimea fiecărui turn este exprimată
printr-o cifră nenulă.
- Pentru rezolvarea corectă a cerinţei a) se acordă 20% din punctajul fiecărui test, pentru
rezolvarea corectă a cerinţei b) se acordă 40% din punctajul fiecărui test, iar pentru rezolvarea
corectă a cerinţei c) se acordă 40% din punctajul fiecărui test.
- Respectaţi formatul fişierului de ieşire! Pentru a obţine punctajul acordat unei cerinţe,
trebuie ca răspunsul din fişier să fie corect şi scris exact pe linia precizată ı̂n enunţ.

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.

Timp maxim de executare/test: 0.5 secunde


Memorie: total 32 MB
Dimensiune maximă a sursei: 10 KB

10.1.1 Indicaţii de rezolvare

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.

10.1.2 Cod sursă

Listing 10.1.1: cladiri S9cif.cpp


1 #include <cstdio>
2 using namespace std;
3
4 int main()
5 {
6
CAPITOLUL 10. OJI 2013 10.1. CLADIRI - OJI 2013 144

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 }

Listing 10.1.2: cladiridl.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("cladiri.in");
6 ofstream g("cladiri.out");
7
8 int n, i, j, na, np, nc, Cmax, Cx, ct, a, x, inv, dif, v[20];
CAPITOLUL 10. OJI 2013 10.1. CLADIRI - OJI 2013 145

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 }

Listing 10.1.3: cladiriMN.cpp


1 #include <cstdio>
2
3 using namespace std;
4
5 int x,y,inv;
6 int i,p,j,n,cmax,maxim,nrmaxim,sum,nrpal;
7
8
9 int main()
10 {
11 FILE *fin = fopen("cladiri.in","r");
12 FILE *fout = fopen("cladiri.out","w");
13
14 fscanf(fin,"%d",&n);
15
16 for (i=1;i<=n;i++)
17 {
18 fscanf(fin,"%lld",&x);
19 y = x;
20 inv = 0;
21 cmax = 0;
22 p = 0;
23 while (y)
24 {
25 if (y%10 > cmax)
26 cmax = y%10;
27 inv = inv*10 + y%10;
28 p++;
29 y/=10;
30 }
31
32 if (cmax > maxim)
CAPITOLUL 10. OJI 2013 10.1. CLADIRI - OJI 2013 146

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 }

Listing 10.1.4: cladiristream.cpp


1 #include <fstream>
2 using namespace std;
3
4 int x,y,inv;
5 int i,p,j,n,cmax,maxim,nrmaxim,sum,nrpal;
6
7
8 int main()
9 {
10 ifstream fin("cladiri.in");
11 ofstream fout("cladiri.out");
12
13 fin>>n;
14 for (i=1;i<=n;i++)
15 {
16 fin>>x;
17 y = x;
18 inv = 0;
19 cmax = 0;
20 p = 0;
21 while (y)
22 {
23 if (y%10 > cmax)
24 cmax = y%10;
25 inv = inv*10 + y%10;
26 p++;
27 y/=10;
28 }
29
30 if (cmax > maxim)
31 {
32 maxim = cmax;
33 nrmaxim = 1;
34 }
35 else
36 if (cmax == maxim)
37 nrmaxim++;
38
39 if (x == inv)
40 nrpal++;
41
42 for (j=1;j<=p/2;j++)
43 {
44 if (x % 10 > inv % 10)
45 sum += (x%10-inv%10);
CAPITOLUL 10. OJI 2013 10.1. CLADIRI - OJI 2013 147

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 }

Listing 10.1.5: Cristina cladiri.cpp


1 #include <fstream>
2 #include <stdlib.h>
3 #include <math.h>
4
5 using namespace std;
6
7 ifstream fin("cladiri.in");
8 ofstream fout("cladiri.out");
9
10 int main()
11 {
12 int i,n,k,sir[20],j;
13 int max_inaltime=0,max_turn=0,apare=0,sunt_identice;
14 int nr_Crina,s=0,aux;
15 int nr_bilete_identice=0;
16
17 fin>>n;
18
19 for(i=1;i<=n;i++)
20 {
21 fin>>nr_Crina;aux=nr_Crina;
22 k=0;max_inaltime=0;
23
24 while(nr_Crina)//memoram in sir cifrele fiecarui numar
25 {
26 k++; sir[k]=nr_Crina%10;nr_Crina=nr_Crina/10;
27 if (max_inaltime<sir[k])//calculam inaltimeea maxima a unei cladiri
28 max_inaltime=sir[k];
29 }
30
31 if (max_inaltime>max_turn)//calculam inaltimea maxima a tuturor turnurilor
32 {max_turn=max_inaltime; apare=1;}
33 else
34 if (max_inaltime==max_turn)
35 apare++;
36
37 //rezolabre b)
38
39 sunt_identice=1; //verificam daca sirul construit e palindromic
40
41 for(j=1;j<=k/2;j++)
42 if (sir[j]!=sir[k-j+1])
43 sunt_identice=0;
44
45 if(sunt_identice) nr_bilete_identice++;
46 // rezolvare c)
47 for(j=1;j<=k/2;j++)//calculam numarul de cuburi ce pot fi adaugate
48 //astfel inacat toate numerele sa devina palindroame
49 s=s+labs(sir[j]-sir[k-j+1]);
50 }
51
52 fin.close();
53 fout<<max_turn<<" "<<apare<<endl<<nr_bilete_identice<<endl<<s<<endl;
54
55 return 0;
56 }

Listing 10.1.6: Ovidiu cladiri cu vector.cpp


CAPITOLUL 10. OJI 2013 10.1. CLADIRI - OJI 2013 148

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 }

Listing 10.1.7: Ovidiu cladiri fara vector.cpp


1 #include<iostream>
2 #include<cstdio>
3 #include<cstdlib>
4
5 using namespace std;
6
7 int x,y,n,i,j,cmax,ogl,cf,cm,nr,nrpal,s,a,b,nrcf;
8
9 int main()
10 {
11 freopen("cladiri.in","r",stdin);
12 freopen("cladiri.out","w",stdout);
13
14 cin>>n;
15 for(i=1;i<=n;i++)
16 { cin>>x;
17 y=x;
18 cmax=x%10;
19 ogl=x%10;
20 x=x/10;nrcf=1;
21 while(x)
22 { cf=x%10;
CAPITOLUL 10. OJI 2013 10.2. GALBENI - OJI 2013 149

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 }

10.1.3 *Rezolvare detaliată

10.2 galbeni - OJI 2013


Problema 2 - galbeni 100 de puncte
După ce au descoperit ascunzătoarea piratului Spânu, marinarii de pe corabia ”Speranţa” au
hotărât să ofere sătenilor o parte din comoara acestuia. Întrucât comoara avea un număr nelimitat
de bani din aur, numiţi galbeni, singura problemă a marinarilor a fost regula după care să ı̂mpartă
banii. După ı̂ndelungi discuţii au procedat astfel: i-au rugat pe săteni să se aşeze ı̂n ordine la
coadă şi să vină, pe rând, unul câte unul pentru a-şi ridica galbenii cuveniţi. Primul sătean a fost
rugat să ı̂şi aleagă numărul de galbeni, cu condiţia ca acest număr să fie format din exact K cifre.
Al doilea sătean va primi un număr de galbeni calculat astfel: se ı̂nmulţeşte numărul de galbeni
ai primului sătean cu toate cifrele nenule ale acelui număr, rezultatul se ı̂nmulţeşte cu 8 şi apoi se
ı̂mparte la 9 păstrându-se doar ultimele K cifre ale câtului ı̂mpărţirii. Dacă numărul obţinut are
mai puţin de K cifre, atunci acestuia i se adaugă la final cifra 9, până când se completează K cifre.
Pentru a stabili câţi galbeni primeşte al treilea sătean, se aplică aceeaşi regulă, dar pornind de
la numărul de galbeni ai celui de-al doilea sătean. Regula se aplică ı̂n continuare fiecărui sătean,
plecând de la numărul de galbeni primiţi de săteanul care a stat la coadă exact ı̂n faţa lui.

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.

Restricţii şi precizări


CAPITOLUL 10. OJI 2013 10.2. GALBENI - OJI 2013 150

a 2 & N & 1000000000


a 1&K&3
a Se garantează că S are exact K cifre.

Exemple

galbeni.in galbeni.out Explicaţii


51 2 3 77 Primul sătean a luat 51 de galbeni.
Cel de al doilea sătean va primi 26 de galbeni (51 se ı̂nmulţeşte
cu cifrele nenule 51 ˜ 5 ˜ 1 255, 255 se ı̂nmulţeşte cu 8, 255 ˜ 8
2040. Câtul ı̂mpărţirii lui 2040 la 9 este 226, ultimele două cifre
fiind 26).
Cel de al treilea sătean va primi 77 de galbeni (26 se ı̂nmulţeşte
cu cifrele nenule 26 ˜ 2 ˜ 6 312, 312 se ı̂nmulţeşte cu 8 şi
obţinem numărul 2496. Câtul ı̂mpărţirii dintre 2469 şi 9 este
277, ultimele două cifre fiind 77).
10 2 3 96 Primul sătean primeşte 10 galbeni.
Pentru a calcula câţi galbeni primeşte al doilea sătean procedăm
astfel: ı̂nmulţim 10 cu cifele sale nenule: 10 ˜ 1 10, apoi cu
8, 10 ˜ 8 80. Câtul ı̂mpărţirii lui 80 la 9 este 8. Acest număr
având mai puţin de k 2 cifre, se adaugă la finalul său cifra 9
şi se obţine 89.
Pentru al treilea sătean se pleacă de la 89 (89 ˜ 8 ˜ 9 6408,
6408 ˜ 8 51264, câtul ı̂mpărţirii lui 51264 la 9 este 5696,
ultimele două cifre sunt 96).

Timp maxim de executare/test: 0.5 secunde


Memorie: total 32 MB
Dimensiune maximă a sursei: 10 KB

10.2.1 Indicaţii de rezolvare

prof. Marius Nicoli, C.N. ”Fratii Buzesti”, Craiova

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

10.2.2 Cod sursă

Listing 10.2.1: galbeni.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 int x, k, n, z, p, y, i, m;
6 int v[10010], w[10010];
7
8 int main()
9 {
10 ifstream fin("galbeni.in");
11 ofstream fout("galbeni.out");
12
13 fin>>x>>k>>n;
14 v[x] = 1;
15 z = 1;
16 for (i=1;i<=k;i++)
17 z = z * 10;
18 w[1] = x;
19 for (i=2;i<=n;i++)
20 {
21 y = x;
22 p = x;
23 while (y!=0)
24 {
25
26 if (y%10 != 0)
27 {
28 p = p * (y%10);
29 }
30 y = y/10;
31 }
32
33 p = p * 8;
34 p = p/9;
35 p = p%z;
36 while (p*10 < z)
37 p = p * 10 + 9;
38
39 if (v[p]!=0)
40 {
41 m = n-(v[p]-1);
42 m = m % (i-v[p]);
43 if (m == 0)
44 {
45 fout<<w[i-1]<<"\n";
46 }
47 else
48 {
49 fout<<w[v[p] + m - 1]<<"\n";
50 }
51
52 return 0;
53 }
54
55 x = p;
56 v[x] = i;
57 w[i] = x;
58 }
59
60 fout<<w[n]<<"\n";
61 return 0;
62 }

Listing 10.2.2: galbeni dt.cpp


1 #include <fstream>
2 using namespace std;
3
4 ifstream f("galbeni.in");
CAPITOLUL 10. OJI 2013 10.2. GALBENI - OJI 2013 152

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 }

Listing 10.2.3: galbeniBrut.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 int n, s, k, x, p, c, inv, i, z;
6
7 int main()
8 {
9 ifstream fin("galbeni.in");
10 ofstream fout("galbeni.out");
11
12 fin>>s>>k>>n;
13 z = 1;
14
15 for (i=1;i<=k;i++)
16 z = z * 10;
17
18 for (i=2;i<=n;i++)
19 {
20 x = s;
21 p = s;
22 while (x!=0)
23 {
24 if (x%10 != 0)
25 {
26 p = p*(x%10);
CAPITOLUL 10. OJI 2013 10.2. GALBENI - OJI 2013 153

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 }

Listing 10.2.4: galbenidl.cpp


1 #include <fstream>
2 #include <iostream>
3 #include <cstring>
4
5 using namespace std;
6
7 int A[10000], x,i, p ,j, N ,K , Nr, S, Lg, rest, P, L, V[10010];
8 bool ok=true;
9
10 ifstream f("galbeni.in");
11 ofstream g("galbeni.out");
12
13 int main()
14 {
15 f>>S>>K>>N;
16
17 memset(A,0,sizeof(A));
18
19 p=1;
20 for(i=1; i<=K;i++) p*=10;
21
22 Nr=S; V[1]=S; A[Nr]=1;
23
24 for(i=2; ok && i<=N; i++)
25 {
26 x=Nr;
27 while (x)
28 {
29 if (x%10) Nr*=x%10;
30 x/=10;
31 }
32
33 Nr*=8;
34 Nr/=9;
35 Nr%=p;
36
37 while(Nr<p/10) Nr=Nr*10+9;
38
39 if (A[Nr])
40 {
41 ok=false;
42 Lg = i - A[Nr];
43 L= i - 1;
44 }
45 else { A[Nr] = i; V[i] = Nr;}
46 }
47
48 if (ok) g<<V[N]<<’\n’;
49 else
CAPITOLUL 10. OJI 2013 10.2. GALBENI - OJI 2013 154

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 }

10.2.3 *Rezolvare detaliată


Capitolul 11

OJI 2012

11.1 cifru - OJI 2012


Problema 1 - cifru 100 de puncte
Costel a descoperit ı̂ntr-o debara servieta cu cifru a tatălui său. Cifrul este compus din 4 discuri
metalice pe care sunt inscripţionate cifrele de la 0 la 9. Fiecare disc se poate mişca individual, de
sus ı̂n jos sau de jos ı̂n sus, formându-se combinaţii de cifre. De multe ori, datorită comodităţii,
combinaţia ce permite deschiderea servietei este formată numai din cifre identice: 0000, 1111 etc.
Costel ı̂şi imaginează un cifru compus din N discuri metalice, fiecare având inscripţionate
cifrele de la 0 la 9, fiecare putând fi deplasat ı̂n cele două direcţii specificate anterior. Prin mutare
Costel ı̂nţelege deplasarea unui disc ı̂n sus sau ı̂n jos, cu o singură poziţie, adică deplasarea discului
până la cifra precedentă, respectiv următoare celei curente.

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

Fişierul cifru.in conţine:


a pe prima linie numărul natural N reprezentând numărul discurilor;
a pe următoarele N linii câte o cifră, reprezentând cifra curentă de pe fiecare disc al cifrului.

Date de ieşire

În fişierul cifru.out se vor afişa, pe linii separate, cele 4 valori solicitate.

Restricţii şi precizări

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

cifru.in cifru.out Explicaţii


4 9 Avem un cifru cu 4 discuri. Iniţial, cifrul este ı̂n starea 7390 (primul
7 7 disc este poziţionat pe cifra 7, al doilea pe cifra 3 etc.) Cea mai mare
3 0 cifră de pe cifru este cifra 9. Numărul minim de mutări este 7 şi se
9 2 poate obţine ı̂n două moduri:
0 1. Deplasăm primul disc cu 2 poziţii ı̂n sus, al doilea disc cu 4 poziţii
ı̂n jos, al treilea rămâne nemişcat, iar ultimul se deplasează cu o
poziţie ı̂n jos. Combinaţia obţinută este 9999.
2. Deplasăm primul disc cu 3 poziţii ı̂n sus, al doilea disc cu 3 poziţii
ı̂n jos, al treilea cu o poziţie ı̂n sus, iar ultimul rămâne nemişcat.
Combinaţia obţinută este 0000.
Astfel, cifra cea mai mică ce formează combinaţia cu număr minim
de mutări este 0. Avem 2 combinaţii care se pot obţine ı̂n numărul
minim de mutări determinat: 0000 şi 9999.

Timp maxim de executare/test: 1.0 secunde


Memorie: total 2 MB din care pentru stivă 2 MB

11.1.1 Indicaţii de rezolvare

Autor: prof. Alin Burta

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.

11.1.2 Cod sursă

Listing 11.1.1: flori.cpp


1 #include <fstream>
2 using namespace std;
3
4 ifstream fin("flori.in");
5 ofstream fout("flori.out");
6
CAPITOLUL 11. OJI 2012 11.1. CIFRU - OJI 2012 157

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 }

Listing 11.1.2: flori dana.cpp


1 #include<iostream>
2 using namespace std;
3
4 short int n,h[102],H,i;
5 int s,k,poz,gasit,val;
6
7 int cmp(const void *p,const void *q)
8 {
9 return *(short int *)p - *(short int *) q;
10 }
11
12 int rez()
13 {
14 k=1;
15 do
16 {
17 for(i=1;i<=k;i++)
18 {
19 h[i]=1+h[i];
20 if(h[i]==H) return k-1;
21 }
22
23 val=h[k+1];
CAPITOLUL 11. OJI 2012 11.2. FLORI - OJI 2012 158

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 }

11.1.3 *Rezolvare detaliată

11.2 flori - OJI 2012


Problema 2 - flori 100 de puncte
Lizuca are n flori ornamentale de ı̂nălţimi h1 , h2 , ..., hn , exprimate ı̂n centimetri. Pentru a uda
plantele, Lizuca stabileşte următorul program: ı̂n prima zi va alege o plantă pe care o va uda, ı̂n
a doua zi va alege două plante pe care le va uda, ı̂n ziua a treia va alege trei plante pe care le va
uda şi aşa mai departe. Dacă o plantă este udată ı̂ntr-o anumită zi, atunci creşte 1 centimetru
până la sfârşitul acelei zile, iar dacă nu este udată, rămâne la ı̂nălţimea pe care o avea la sfârşitul
zilei precedente.

Cerinţe

Scrieţi un program care determină:


a) un număr natural S, exprimat ı̂n centimetri, reprezentând suma ı̂nălţimilor finale ale tuturor
plantelor, dacă Lizuca le-ar uda după procedeul descris, timp de n zile;
b) un număr natural K, reprezentând numărul maxim de zile ı̂n care Lizuca poate uda florile
după procedeul descris anterior, astfel ca la sfârşitul celei de a K-a zi, nicio plantă ornamentală
să nu atingă ı̂nălţimea H.

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).

Restricţii şi precizări

a 1 & N, H & 100


a 1 & h1 , h2 , ...hn $ H
a O plantă poate fi udată o singură dată pe zi.
a Pentru rezolvarea corectă a cerinţei a) se acordă 30 % din punctajul total pentru fiecare test.
a Pentru rezolvarea corectă a cerinţei b) se acordă 70 % din punctajul total pentru fiecare test.

Exemple

flori.in flori.out Explicaţii - cerinţa b)


34 10 Dacă ı̂n prima zi se udă planta 3, atunci ı̂nălţimile devin: 212
211 2 Dacă ı̂n a doua zi se udă plantele 1 şi 2, atunci ı̂nălţimile devin: 322
Procedeul se opreşte aici, deoarece ı̂n ziua a treia, ar trebui să se ude
toate plantele, iar planta 1 ar ajunge să aibă ı̂nălţimea 4.
45 17 Dacă ı̂n prima zi se udă planta 1, atunci ı̂nălţimile devin: 2321
1321 3 Dacă ı̂n a doua zi se udă plantele 1 şi 4, atunci ı̂nălţimile devin: 3322
Dacă ı̂n a treia zi se udă plantele 1, 3 şi 4, atunci ı̂nălţimile devin: 4333.

Timp maxim de executare/test: 1.0 secunde


Memorie: total 4 MB din care pentru stivă 3.5 MB

11.2.1 Indicaţii de rezolvare

Autor: prof. Susana Galatan

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:

Fie k = 1 (k reprezinta numarul de zile)


Cat timp nicio planta nu atinge inaltimea H, executa
{
Sorteaza sirul inaltimilor in ordine crescatoare

Parcurge sirul h pana la pozitia k


{
Incrementeaza inaltimea plantei curente
Daca planta atinge inaltimea H, atunci
{
CAPITOLUL 11. OJI 2012 11.2. FLORI - OJI 2012 160

Scrie k - 1
Stop
}
}
Incrementeaza k
}

11.2.2 Cod sursă

Listing 11.2.1: sol-cifru.cpp


1 // autor Alin Burtza
2
3 #include <fstream>
4 #define Fin "cifru.in"
5 #define Fou "cifru.out"
6
7 using namespace std;
8
9 int main()
10 {
11 ifstream IN(Fin);
12 ofstream OUT(Fou);
13 int N; //numarul discurilor
14 int Apar[10]; //Apar[i] = 1 daca culoarea i apare pe cel putin un disc
15 int MAX; //cifra maxima
16 int NrMin; //numarul minim de mutari
17 int Cif; //cifra obtinuta in numarul minim de mutari
18 int Cate; //numarul posibilitatilor
19 int i,j, Nr, x;
20
21 //initializari
22 for(i=0;i<=9;i++) Apar[i] = 0;
23
24 //citesc datele de intrare si
25 //determin cifrele care apar initial si cifra maxima
26 IN>>N; MAX = 0; Cif = -1; Cate = 0;
27 for(i=1;i<=N;i++)
28 {
29 IN>>x;
30 Apar[x]++;
31 if(MAX < x) MAX = x;
32 }
33
34 //calculez numarul de mutari pentru fiecare cifra care apare
35 NrMin = 10 * N + 1;
36 for(i=0;i<=9;i++)
37 {
38 Nr = 0;
39 for(j=0;j<=9;j++)
40 if(Apar[j] && j!=i)
41 Nr += abs(j-i) <= 10 - abs(j-i) ?
42 Apar[j]*abs(j-i) :
43 Apar[j]*(10 - abs(j-i));
44
45 if(Nr<NrMin) NrMin = Nr, Cif = i, Cate = 1;
46 else if(Nr==NrMin) Cate++;
47 }
48
49 OUT<<MAX<<’\n’<<NrMin<<’\n’<<Cif<<’\n’<<Cate<<’\n’;
50
51 IN.close();
52 OUT.close();
53 return 0;
54 }

11.2.3 *Rezolvare detaliată


Capitolul 12

OJI 2011

12.1 carte - OJI 2011


Problema 1 - carte 100 de puncte
Rareş a primit ı̂n dar o carte ı̂n care paginile sunt amestecate. Se hotărăşte totuşi să o citească,
răsfoind cartea ı̂ntr-un singur sens, de la prima pagină către ultima, ı̂n ordinea aşezării lor
ı̂n carte, respectând următorul algoritm:
”Caută la ı̂nceput pagina numerotată cu x 1.
După ce a citit o pagină cu numărul x caută printre paginile următoare acestei pagini, răsfoind
cartea, pagina cu numărul x  1, fără a căuta printre paginile aşezate ı̂naintea paginii cu numărul
x. Dacă o găseşte atunci va continua lectura ı̂n acelaşi mod, iar dacă nu o găseşte atunci va ı̂nchide
cartea şi, ı̂n ziua următoare, va relua lectura de la pagina cu numărul x  1, pe care mai ı̂ntâi o
va cauta răsfoind cartea de la ı̂nceput.
Rareş va proceda la fel şi ı̂n zilele următoare până când va citi ı̂ntreaga carte”.

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.

Restricţii şi precizări

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).

Timp maxim de executare/test: 1.0 secunde

12.1.1 Indicaţii de rezolvare

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.

12.1.2 Cod sursă

Listing 12.1.1: CARTE CI.CPP


1 #include <fstream>
2
3 using namespace std;
4
5 int main()
6 {
7 ifstream in("carte.in");
8 ofstream out("carte.out");
9
10 int i,j,n,v[10000],zi,maxi,zimaxi,contor;
11 in>>n;
12
13 for(i=1;i<=n;i++)
14 in>>v[i];
15
16 j=1;
17 zi=0;
18 maxi=0;
19 while(j<=n)
20 {
21 contor=0;
22 for(i=1;i<=n;i++)
23 if(v[i]==j)
24 {
25 j++;
26 contor++;
27 }
28
29 if(maxi<contor)
30 {
31 maxi=contor;
32 zimaxi=zi;
33 }
34
35 zi++;
36 }
37
38 out<<zi<<" "<<(zimaxi+1)<<" "<<maxi;
39 return 0;
40 }
CAPITOLUL 12. OJI 2011 12.1. CARTE - OJI 2011 163

Listing 12.1.2: CARTE CS.cpp


1 #include<fstream>
2
3 using namespace std;
4
5 ifstream f("carte.in");
6 ofstream g("carte.out");
7
8 int n,u[10001],i,p,m,maxx,imaxx,z,nr;
9
10 int main()
11 {
12 f>>n;
13 for(i=1;i<=n;i++) {f>>p;u[p]=i;}
14 for(i=1;i<=n;i++)
15 if(u[i]!=0)
16 {
17 nr=1,p=i,m=u[i],z++;
18 while(p<n && u[p+1]>m) nr++,p++,m=u[p],u[p]=0;
19
20 if(nr>maxx) maxx=nr,imaxx=z;
21 }
22
23 g<<z<<’ ’<<imaxx<<’ ’<<maxx<<’ ’<<’\n’;
24
25 return 0;
26 }

Listing 12.1.3: CARTE LU.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 int main()
6 {
7 ifstream f("carte.in");
8 ofstream g("carte.out");
9
10 int n,v[10000],i,nr,x,k,max=0,zimax;
11
12 f>>n;
13 for (i=0; i<n; i++)
14 {
15 f>>v[i];
16 if (v[i]==1) x=i;
17 }
18
19 x=0; nr=0;
20 while (x<n)
21 {
22 i=0; k=0; nr++;
23 while (i<n)
24 {
25 if (v[i]==x+1)
26 {
27 k++;
28 x++;
29 }
30 i++;
31 }
32
33 if (k>max)
34 {
35 max=k;
36 zimax=nr;
37 }
38 }
39
40 g<<nr<<’ ’<<zimax<<’ ’<<max<<endl;
41 f.close();
42 g.close();
43
44 return 0;
CAPITOLUL 12. OJI 2011 12.2. GRAD - OJI 2011 164

45 }

Listing 12.1.4: CARTE OM.CPP


1 #include<fstream.>
2 #include<stdio.h>
3
4 using namespace std;
5
6 int a[10002],n,i;
7 int val,nr_pag,zile,maxx,poz;
8
9 ifstream f("carte.in");
10 ofstream g("carte.out");
11
12 void citire()
13 {f>>n;
14 for(i=1;i<=n;i++)
15 f>>a[i];
16 }
17
18 void o_solutie()
19 { val=1;zile=0;
20
21 while(val<=n)
22 { zile++ ;
23 nr_pag=0;
24 i=1;
25 while(i<=n)
26 { if(a[i]==val)
27 {nr_pag++;
28 val++;
29 }
30 i++;
31 }
32 if(nr_pag>maxx)
33 {maxx=nr_pag;
34 poz=zile;
35 }
36 }
37
38 g<<zile<<" ";
39 g<<poz<<" ";
40 g<<maxx;
41 g.close();
42 }
43
44 int main()
45 { citire();
46 o_solutie();
47
48 return 0;
49 }

12.1.3 *Rezolvare detaliată

12.2 grad - OJI 2011


Problema 2 - grad 100 de puncte
Se consideră un şir x1 , x2 , ..., xn de n numere naturale distincte, două câte două. Pentru
o secvenţă de k numere (xp , xp1 , ..., xpk1 ), care ı̂ncepe cu numărul de pe poziţia p din şirul
dat, definim gradul său ca fiind numărul de numere din secvenţă, care rămân pe aceleaşi poziţii
după ordonarea crescătoare a secvenţei. De exemplu, pentru n 7 şi şirul format din numerele
1, 5, 7, 4, 6, 2, 9, secvenţa formată din numerele 7, 4, 6, 2 (corespunzătoare lui p 3 şi k 4) are
gradul egal cu 2 deoarece, după ordonarea crescătoare a numerelor din secvenţă, aceasta devine
2, 4, 6, 7, numerele 4 şi 6 rămânând pe aceleaşi poziţii.

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.

Restricţii şi precizări

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

grad.in grad.out Explicaţii


74 3 După ordonare, şirul 1574629 devine 1245679, pe aceleaşi
1574629 32 poziţii rămân 1, 6 şi 9, deci gradul ı̂ntregului şir este 3.
Avem patru secvenţe cu câte 4 elemente:
1574, care are gradul 1
5746, care are gradul 0
7462, care are primul număr pe poziţia 3 şi gradul 2.
4629, care are gradul 1.

Timp maxim de executare/test: 1.0 secunde

12.2.1 Indicaţii de rezolvare

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

Pentru a obtine un algoritm eficient, nu ordonam de fiecare data vectorul y.


Din vectorul ordonat pentru secventa anterioara se elimina xp  1 si se introduce xp  k  1
(prin cateva interschimbari se realizeaza ordonarea lui y). La fiecare pas se actualizeaza gmax si
pmax.

----------------------------
| |
x[1], ... , x[p-1], x[p-2], ..., x[p+k-2] , x[p+k-1] ,..., x[n].
| |
-------------------------------

12.2.2 Cod sursă

Listing 12.2.1: GRAD.CPP


1 #include <fstream>
2
3 using namespace std;
4
5 int x[10002],y[10002],g,n,k,pmax,gmax,aux;
6
7 ifstream fin("grad.in");
8 ofstream fout("grad.out");
9
10 void cit()
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 n)
20 {
21 int i,sw,aux;
22 do
23 {
24 sw=0;
25 for(i=1;i<n;i++)
26 if(y[i]>y[i+1])
27 {
28 aux=y[i];y[i]=y[i+1];y[i+1]=aux;sw=1;
29 }
30 //n--;
31 } while(sw);
32 }
33
34 int main()
35 {
36 int i,j,gr;
37
38 cit();
39
40 for(i=1;i<=n;i++)
41 y[i]=x[i];
42
43 ordonare(n);
44
45 g=0;
46 for(i=1;i<=n;i++)
47 if(x[i]==y[i])
48 g++;
49
50 fout<<g<<’\n’;
51 for(i=1;i<=k;i++)
52 y[i]=x[i];
53
54 ordonare(k);
55
56 gmax=0;
CAPITOLUL 12. OJI 2011 12.2. GRAD - OJI 2011 167

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 }

Listing 12.2.2: GRAD CR.CPP


1 #include<fstream>
2
3 using namespace std;
4
5 ifstream f("grad.in");
6 ofstream g("grad.out");
7
8 int v[10001],w[10001],n,k,i,p,x,y,j,maxx,t;
9
10 void ordo(int m)
11 {int aux,o,i;
12 do{o=1;
13 for(i=1;i<m;i++)
14 if(w[i]>w[i+1])aux=w[i],w[i]=w[i+1],w[i+1]=aux,o=0;
15 m--;}while(!o);
16 }
17
18 int egale(int d,int n)
19 { int i,x=0;
20 for(i=1;i<=n;i++) x+=(v[i+d]==w[i]);
21 return x;
22 }
23
24 int main()
25 { f>>n>>k;
26 for(i=1;i<=n;i++) f>>v[i],w[i]=v[i];
27
CAPITOLUL 12. OJI 2011 12.2. GRAD - OJI 2011 168

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 }

Listing 12.2.3: GRAD IC.CPP


1 #include <fstream>
2
3 using namespace std;
4
5 int n,k,j,i,a[10001],ma,nr,b[10001],ind;
6
7 int main ()
8 {
9 ifstream f("grad.in");
10
11 f>>n>>k;
12
13 for(i=1;i<=n;i++)
14 f>>a[i];
15
16 f.close();
17
18 for(i=1;i<=k;i++)
19 {
20 for(j=1;j<i;j++)
21 if(a[i]>a[j])
22 b[i]++;
23 else
24 b[j]++;
25 }
26
27 for(i=1;i<=k;i++)
28 if(b[i]+1==i)
29 ma++;
30
31 ind=1;
32 if(k!=n)
33 {
34 for(i=k+1;i<=n;i++)
35 {
36 nr=0;
37 for(j=1;j<k;j++)
38 {
39 if(a[i-j]<a[i])
40 b[i]++;
41 else
42 b[i-j]++;
43
44 if(a[i-j]>a[i-k])
45 b[i-j]--;
46
47 if(b[i-j]+1==k-j)
CAPITOLUL 12. OJI 2011 12.2. GRAD - OJI 2011 169

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 }

Listing 12.2.4: GRAD OM.CPP


1 #include<fstream>
2 #include<stdlib.h>
3
4 using namespace std;
5
6 int a[10005],n,k,i;
7
8 ifstream f("grad.in");
9 ofstream g("grad.out");
10
11 int mic[10005],maxx,poz;
12
13 void citire()
14 { f>>n>>k;
15 for(i=1;i<=n;i++)
16 f>>a[i];
17 }
18
19 void mai_mici_egale(int p,int q)
20 { int i,j;
21 for(i=p;i<=q;i++)
22 for(j=p;j<=q;j++)
23 if(a[i]<=a[j])
24 mic[j]++;
25
26 }
CAPITOLUL 12. OJI 2011 12.2. GRAD - OJI 2011 170

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 }

Listing 12.2.5: GRADFSLAB.CPP


1 #include <fstream>
2
3 using namespace std;
4
5 int x[10002],y[10002],g,n,k,pmax,gmax,aux;
6
7 ifstream fin("grad.in");
8 ofstream fout("grad.out");
9
10 void cit()
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 {
CAPITOLUL 12. OJI 2011 12.2. GRAD - OJI 2011 171

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 }

Listing 12.2.6: GRADSLAB.CPP


1 #include <fstream>
2
3 using namespace std;
4
5 int x[10002],y[10002],g,n,k,pmax,gmax,aux;
6
7 ifstream fin("grad.in");
8 ofstream fout("grad.out");
9
10 void cit()
CAPITOLUL 12. OJI 2011 12.2. GRAD - OJI 2011 172

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

12.2.3 *Rezolvare detaliată


Capitolul 13

OJI 2010

13.1 loto - OJI 2010


Problema 1 - loto 100 de puncte
La Loteria Naţională există N bile inscripţionate cu numere naturale, nenule, distincte de cel
mult 4 cifre. Şeful de la loterie primeşte o cutie ı̂n care se află cele 6 bile extrase la ultima rundă,
restul bilelor neextrase fiind puse ı̂ntr-un seif. Deoarece are o fire poznaşă, el scoate din cutie bila
pe care este ı̂nscris numărul cel mai mic şi o păstrează ı̂n buzunarul hainei sale. În locul ei va
pune o bilă neextrasă, aflată ı̂n seif, având numărul cel mai apropiat de aceasta. Apoi continuă
operaţia şi scoate din cutie şi bila pe care este ı̂nscris numărul maxim extras iniţial, pe care o va
pune ı̂n celălalt buzunar al său. De asemenea o va ı̂nlocui cu o altă bilă neextrasă iniţial, aflată
ı̂n seif, având numărul cel mai apropiat de aceasta.
Cerinţe
Realizaţi un program care afişează ı̂n ordine crescătoare numerele de pe bilele aflate ı̂n cutie
după modificările făcute de şef.
Date de intrare
Fişierul de intrare loto.in conţine pe prima linie numărul natural N , pe a doua linie cele N
numere naturale scrise pe bile, iar pe a treia linie cele 6 numere naturale scrise pe bilele extrase
de angajaţii loteriei. Valorile scrise pe aceeaşi linie sunt separate prin spaţii.
Date de ieşire
În fişierul de ieşire loto.out se vor afişa pe prima linie, separate prin câte un spaţiu, cele 6
numere obţinute ı̂n cutie după modificărie făcute de şef, ı̂n ordine crescătoare.
Restricţii şi precizări
a 8 $ N $ 1000
a Dacă o bilă poate fi ı̂nlocuită cu două bile la fel de apropiate de ea, atunci aceasta se va
ı̂nlocui cu bila având numărul mai mare.
a Pentru datele de test, atât bila cu numărul cel mai mic, cât şi bila cu numărul cel mai mare
pot fi ı̂nlocuite cu alte bile.

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

13.1.1 Indicaţii de rezolvare

Numerele inscrise pe N bile vor fi marcate in vectorul A cu valoarea true.


Vectorul B va retine bilele extrase.
Elementul minim din B (min) se va inlocui cu valoarea cea mai aproiata de el pentru care
elementul corecpunzator din A este true. Acesta se va identifica prin parcurgerea in ambele
sensuri a vectorul A incepand cu indicele min.
Identic se va proceda si pentru valoarea max din B.
Inainte de afisare, se vor ordona crescator elementele din B.

13.1.2 Cod sursă

Listing 13.1.1: 6 pr1 s.pas


1 var i,j,n,mx,mn,max,min,x:longint;
2 a:array[0..10000]of boolean;
3 b:array[1..6]of integer;
4
5 begin
6
7 assign(input,’loto.in’); reset(input);
8 assign(output,’loto.out’);rewrite(output);
9
10 readln(n);
11 fillchar(a,sizeof(a),false);
12
13 for i:=1 to n do
14 begin
15 read(x);a[x]:=true;
16 end;
17
18 max:=0; min:=10000; mx:=0;mn:=0;
19
20 for i:=1 to 6 do
21 begin
22 read(b[i]); a[b[i]]:=false;
23 if b[i]<min then begin min:=b[i]; mn:=i; end;
24 if b[i]>max then begin max:=b[i]; mx:=i; end;
25 end;
26
27 i:=min; j:=min;
28
29 repeat
30 if i<10000 then inc(i);
31 if j>1 then dec(j)
32 until a[i] or a[j];
33
34 if a[i] then b[mn]:=i else b[mn]:=j;
35
36 a[b[mn]]:=false;
37 i:=max; j:=max;
38
39 repeat
40 if i<10000 then inc(i);
41 if j>1 then dec(j)
42 until a[i] or a[j];
43
44 if a[i] then b[mx]:=i else b[mx]:=j;
45
46 for i:=1 to 5 do
47 for j:=i+1 to 6 do
48 if b[i]>b[j] then
49 begin
50 b[i]:=b[i]+b[j];
51 b[j]:=b[i]-b[j];
52 b[i]:=b[i]-b[j];
53 end;
54
55 for i:=1 to 5 do write(b[i],’ ’);
56 writeln(b[6]);
CAPITOLUL 13. OJI 2010 13.2. SUBMIT - OJI 2010 176

57 close(output);
58 end.

13.1.3 *Rezolvare detaliată

13.2 submit - OJI 2010


Problema 2 - submit 100 de puncte
Vasilică se antrenează pe un site de probleme cu evaluare online. Când el trimite pe site soluţia
la o problemă, aceasta este evaluată pe un anumit număr de teste. Punctajul obţinut la problema
respectivă va fi egal cu suma punctajelor obţinute la fiecare test. Punctajele asociate testelor pot
fi diferite. În plus, dacă problema a fost complet rezolvată (a obţinut punctaj maxim la toate
testele), Vasilică primeşte şi un bonus.
Vasilică poate trimite soluţia la o problemă de mai multe ori. Când trimite soluţia prima dată,
punctajul se calculează ı̂n modul prezentat anterior. Când trimite soluţia a doua oară, Vasilică va
fi penalizat cu două puncte (adică din punctajul total obţinut la problemă se scad două puncte).
Când trimite soluţia a treia oară penalizarea este de 4 puncte, a patra oară de 6 puncte ş.a.m.d.
Observaţi că la fiecare nouă ı̂ncercare penalizarea creşte cu două puncte.

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ă.

Restricţii şi precizări

a 1 & N, M & 100


a 0 & P i & 100, pentru orice 1 & i & N
a 0 & B & 100

Exemple

submit.in submit.out Explicaţii


CAPITOLUL 13. OJI 2010 13.2. SUBMIT - OJI 2010 177

4 51 Problema este evaluată pe 4 teste. Punctajele acordate pe teste


10 5 5 20 sunt 10, 5, 5 şi respectiv 20. În cazul ı̂n care toate testele sunt
13 rezolvate corect, se acordă 13 puncte bonus.
3 La această problemă Vasilică trimite 3 surse.
0000 Prima sursă trimisă nu rezolvă corect niciun test, deci obţine 0
1111 puncte.
0101 A doua sursă trimisă rezolvă corect toate testele, primind 10  5 
5  20 40 puncte pe teste, la care se adaugă 13 puncte bonus;
dar fiind a doua soluţie trimisă se aplică o penalizare de două
puncte. În total 40  13  2 51 puncte.
A treia sursă trimisă rezolvă numai teste 2 şi 4 deci obţine 5  20
25 puncte şi este penalizată cu 4 puncte, deci punctajul total este
21.
Punctajul maxim obţinut de Vasilică este prin urmare 51.

Timp maxim de executare/test: 1.0 secunde

13.2.1 Indicaţii de rezolvare

Vom citi punctajele pe teste intr-un vector pct.


Apoi vom citi succesiv rezultatele obtinute de Vasilica la fiecare submit, insumand punctajele
pe teste.
Pe parcursul citirii verificam si daca problema este complet rezolvata pentru a acorda bonusul.
Aplicam eventuala penalizare si astfel obtinem punctajul pentru submitul respectiv.
Maximul se calculeaza pe parcusrul citirii.

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);

if complet then crt:=crt+bonus;

crt:=crt - 2*(j-1);

if crt>max then max:=crt;


end;

writeln(fout, max);

13.2.2 Cod sursă


CAPITOLUL 13. OJI 2010 13.2. SUBMIT - OJI 2010 178

Listing 13.2.1: 6 pr2 s.pas


1 const NMAX=100;
2
3 var n: integer;
4 pct: array[1..NMAX] of integer;
5 bonus: integer;
6 m: integer;
7 p: integer;
8
9 i, j: integer;
10 complet: boolean;
11 crt: integer;
12 max: integer;
13 fin, fout: text;
14
15 begin
16
17 assign(fin, ’submit.in’); reset(fin);
18 assign(fout,’submit.out’); rewrite(fout);
19
20 readln(fin, n);
21
22 for i:=1 to n do read(fin, pct[i]);
23
24 readln(fin);
25 readln(fin, bonus);
26 readln(fin, m);
27
28 max:=0;
29 for j:=1 to m do
30 begin
31
32 complet:=true;
33 crt:=0;
34
35 for i:=1 to n do
36 begin
37 read(fin, p);
38 if p=0 then complet:=false
39 else crt:=crt+pct[i];
40 end;
41 readln(fin);
42
43 if complet then crt:=crt+bonus;
44
45 crt:=crt - 2*(j-1);
46
47 if crt>max then max:=crt;
48 end;
49
50 writeln(fout, max);
51 close(fin);
52 close(fout);
53
54 end.

13.2.3 *Rezolvare detaliată


Part II

ONI - Olimpiada naţională de


informatică

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

În fişierul iluminat.out se va afişa răspunsul ı̂n funcţie de cerinţă:


ˆ dacă c 1 se va afişa pe prima linie un singur număr reprezentând numărul de stâlpi de
iluminat din cartierul cu număr maxim de stâlpi de iluminat la etapa k
ˆ dacă c 2 se va afişa pe prima linie un singur număr reprezentând câte becuri se sting, ı̂n
total, la etapa cu numărul k
ˆ dacă c 3 se va afişa numărul maxim de becuri aprinse ı̂ntr-o zonă pătratică de dimensiune
k  k ı̂nainte de stingerea becurilor

180
CAPITOLUL 14. ONI 2022 14.1. ILUMINAT 181

Restricţii şi precizări

ˆ 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

Numărul total de becuri stinse la etapa cu numărul k = 2 este: 15 + 11 + 8 + 14 + 4 = 52.

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

14.1.1 Indicaţii de rezolvare

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 optimă. Presupune folosirea unor vectori astfel:


2
ˆ doi vectori, xLinie şi xColoana, fiecare având n elemente, ı̂n care xLiniei = linia ı̂n care
se află valoarea i ı̂n tablou, iar xColoanai = coloana ı̂n care se află valoarea i ı̂n tablou.
Odată cu citirea datelor de intrare se completează şi valorile corespunzătoare acestor doi
vectori.
ˆ doi vectori linie şi coloana, cu maximum n elemente fiecare, ı̂n care:
- liniei 0 dacă becurile de pe linia i nu au fost stinse (maximul nu s-a găsit ı̂ncă pe
linia i)
- linieii 1 dacă becurile de pe linia i au fost stinse (maximul s-a găsit pe linia i)
Acelaşi rol ı̂l are vectorul coloana, referitor la coloanele pe care se găseşte maximul.

Simularea stingerii becurilor presupune parcurgerea simultană, ı̂n ordinea descrescătoare a


indicilor, a vectorilor xLinie şi xColoana, până când se găseşte o valoare i pentru care liniei 0
şi coloanai 0. Acesta este, pe rând, maximul căutat la o etapă. Procedeul se repetă pentru
fiecare etapă, până la etapa k de stingere a becurilor. Apoi:
ˆ Pentru cerinţa 1 se afişează maximul maximul găsit la etapa k.
ˆ Pentru cerinţa 2 se calculează suma elementelor de pe linia şi coloana maximului, prin
verificarea condiţiei ca linia şi coloana corespunzătoare elementului să fie egale cu 0 (becurile
nu sunt ı̂ncă stinse).
Această abordare va lua punctaj maxim la aceste două cerinţe.
2
Complexitatea temporală este O n  n k .

Cerinţa 3. Presupune calcule care să pornească de la tabloul iniţial.


CAPITOLUL 14. ONI 2022 14.2. INUNDATIE 183

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:

cartieri,j cartieri,j 1  cartieri1,j  cartieri1,j 1

Pe baza acestor sume parţiale se calculează maximul dintr-o submatrice de dimensiune k  k


2
a tabloului. Această abordare a cerinţei, de complexitate O n , va lua punctaj maxim.

14.1.2 *Cod sursă

14.1.3 *Rezolvare detaliată

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

Fişierul de intrare inundatie.in conţine pe prima linie un număr natural C, reprezentând


cerinţa ce trebuie rezolvată (1, 2, 3, sau 4).
Pe a doua linie numerele N , P şi S, despărţite prin câte un spaţiu, cu semnificaţia din enunţ.
Pe a treia linie se găsesc N numere naturale separate prin câte un spaţiu ce reprezintă ı̂nălţimile
coloanelor.

Date de ieşire

Fişierul de ieşire inundatie.out va conţine un singur număr, astfel:


ˆ Dacă C 1: ı̂nălţimea H cu semnificaţia de mai sus.
ˆ Dacă C 2: timpul T cu semnificaţia de mai sus.
ˆ Dacă C 3: poziţia D cu semnificaţia de mai sus.
ˆ Dacă C 4: poziţia R cu semnificaţia de mai sus.

Restricţii şi precizări

ˆ 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:

Figura 14.1: ***

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

14.2.1 Indicaţii de rezolvare

Propusă de: prof. Cristian Frâncu - Nerdvana


Obervaţii. Următoarele observaţii sunt importante pentru toate cerinţele:
ˆ Apa va acoperi coloanele ı̂n ordinea de la stânga la dreapta. Este ordinea ı̂n care vârfurile
coloanelor sunt atinse de apă;
ˆ Odată ce apa atinge vârful unei coloane, deci acoperă acea coloană, nu este obligatoriu ca
apa să se acumuleze deasupra acelei coloane. Dacă are unde se duce spre dreapta, ı̂nălţimile
coloanelor fiind mai mici sau egale cu coloana curentă, apa se va deplasa.

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 2. timpul ı̂n care apa ajunge la ı̂nălţimea de pe poziţia P


Presupunem că apa tocmai a ajuns la coloana P . În acel moment există apă acumulată ı̂n
diverse coloane spre stânga. Dacă ı̂nsumăm numărul de pătrătele al fiecărei coloane vom obţine
timpul necesar. Aşadar pornim de la coloana P , de ı̂nălţime H, deplasându-ne către stânga.
Deoarece apa a ajuns la coloana P ı̂nseamnă că spre stânga apa are cel puţin acea ı̂nălţime.
Avem, deci, două posibilităţi:
(1) Coloana din stânga, hi , este mai mică sau egală cu cea curentă. În acest caz nivelul apei
este la ı̂nălţime H, iar coloana de apă are ı̂nălţime H  hi . Vom ı̂nsuma această ı̂nălţime la
totalul de timp necesar.
(2) Coloana din stânga, hi , este mai mare decât cea curentă. În acest caz vom actualiza H la
acea ı̂nălţime hi .
Continuăm, astfel, deplasarea către stânga ı̂nsumând coloanele de apă şi actualizând ı̂nălţimea
H. Suma acestor coloane este timpul minim ı̂n care apa ajunge la ı̂nălţimea P .
Complexitate timp: O N , complexitate memorie: O N .

Cerinţa 3. numărul ı̂nălţimii la care ajunge apa după S secunde


Soluţie 1: căutare binară. O soluţie este să folosim rezolvarea cerinţei 1: vom căuta binar
coloana la care ajunge apa. Vom porni cu un interval de căutare 1, N  şi la fiecare pas ne vom
ı̂ntreba, pentru coloana de la jumatea acelui interval, ı̂n cât timp ajunge apa la acea coloană,
folosind algoritmul de la cerinţa 2. Dacă timpul depăşeşte S vom deplasa limita din dreapta a
intervalului, ı̂n caz contrar pe cea din stânga.
Complexitate timp: O N log2 N , complexitate memorie: O N .
Soluţie 2. : parcurgere de la stânga la dreapta. Pornim de la coloana 1, de ı̂nălţime H.
Avem două variante:
(1) Coloana din dreapta, hi , este mai mică sau egală cu cea curentă, H. În acest caz nu
consumăm apă pentru a ne deplasa spre dreapta, deci nu avem nimic de făcut.
(2) Coloana din dreapta, hi , este mai mare decât cea curentă, H. În acest caz apa se acumulează.
Ne ı̂nălţăm cu o unitate faţă de H şi ne deplasăm către stânga până găsim prima coloană
la această ı̂nălţime (sau până depăşim prima coloană). La fiecare deplasare adunăm unu la
necesarul de apă. Dacă nu am depăşit ş ne ı̂nălţăm ı̂ncă o unitate faţă de H şi repetăm
procedeul de deplasare la stânga. Ne vom ı̂nălţa până ce ajungem la ı̂nălţimea hi , sau până
ce depăşim bugetul de S unităţi de apă. Dacă ajungem la ı̂nălţimea hi , vom relua deplasarea
către stânga.
Ultima coloană la care am reuş it să ajungem este răspunsul la cerinţă.
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.2.2 *Cod sursă

14.2.3 *Rezolvare detaliată

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

Dându-se cele N numere din şir să se determine:


1. Câte numere din şirul iniţial nu au nevoie de transformare (conţin doar cifre distincte)?
2. Câte numere va conţine şirul după realizarea tuturor operaţiilor de unire?
3. Care este numărul maxim de cifre ale unui număr din noul şir şi câte numere au acest număr
maxim de cifre?

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

În fişierul de ieşire siruri.out se va afla ı̂n funcţie de cerinţa dată:


ˆ dacă c 1, se va afişa pe prima linie numărul de numere ce nu au nevoie de transformare
ˆ dacă c 2, se va afişa pe prima linie numărul de numere din şir după realizarea tuturor
operaţiilor de unire
ˆ dacă c 3, se vor afişa pe prima linie două numere separate printr-un singur spatiu,
reprezentând numărul maxim de cifre ale unui număr după efectuarea operaţiilor de unire,
respectiv numărul de astfel de numere cu număr maxim de cifre.

Restricţii şi precizări

ˆ 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].

14.3.1 Indicaţii de rezolvare

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.

14.3.2 *Cod sursă

14.3.3 *Rezolvare detaliată


Capitolul 15

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

Scrieţi un program care să rezolve următoarele cerinţe:


1. Determinaţi câte modalităţi de umplere a butoiului există;
2. Determinaţi o modalitate de umplere a butoiului cu număr minim de operaţii;
3. O secvenţa de exact P găleţi alăturate se numeşte norocoasă dacă prin efectuare operaţiei de
acelaşi număr de ori pentru fiecare dintre ele, vom putea umple complet butoiul. Determinaţi
secvenţa norocoasă care permite folosirea celor P găleţi de un număr minim de ori pentru
umplerea completă a butoiului. Secvenţa norocoasă se va identifica prin poziţia primei găleţi
folosite. Dacă există mai multe soluţii se va afişa cea cu poziţia minimă. Găleţile din secvenţa
norocoasă se pot folosi de câte ori este nevoie.

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ă.

Restricţii şi precizări

189
CAPITOLUL 15. ONI 2021 15.1. BUTOI 190

ˆ 5&V & 360 000


ˆ Pentru cerinţele 1 şi 2 restricţiile sunt: 1 & N & 9; 1 & ci & 8 000 şi 1 & K & 5
ˆ Pentru cerinţa 3 restricţiile sunt: 3 &N & 100 000; 1 & ci & 200 000; 3 & P & 10 000 şi
P &N
ˆ Pentru cerinţa 3 capacităţile c1 , c2 , ..., cN ale găleţilor nu sunt neapărat distincte
ˆ Pentru rezolvarea corectă a primei cerinţe se obţin 30 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 30 de puncte.

Exemple:

butoi.in butoi.out Explicaţii


1 3 Cerinţa este 1. Există 3 modalităţi de a umple butoiul
90 7 1 2 folosind cel mult o dată fiecare găleată, deoarece K 1.
30 56 70 34 60 15 5 Acestea sunt 30 + 60, 56 + 34 şi 70 + 15 + 5.
1 19 Cerinţa este 1. Există 19 modalităţi de a umple butoiul.
2020 6 5 3
17 42 200 101 51 171
2 005343 Cerinţa este 2. Numărul minim de operaţii este 15.
2020 6 5 3 Găleţile au fost folosite astfel: 0 * 17 + 0 * 42 + 5 *
17 42 200 101 51 171 200 + 3 * 101 + 4 * 51 + 3 * 171 = 0 + 0 + 1000 +
303 + 204 + 513 = 2020.
3 2 Cerinţa este 3. Secvenţa norocoasă de lungime 3 de-
120 7 1 3 terminată ı̂ncepe la poziţia 2. Prin folosirea de 3 ori a
90 12 20 8 41 80 11 fiecărei găleţi din secvenţă butoiul se umple.

Timp maxim de executare/test: 0.5 secunde pe Windows, 0.5 secunde pe Linux


Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 15 KB

15.1.1 Indicaţii de rezolvare

Propunător: prof. Marinel Şerban Colegiul Naţional ”Emil Racoviţă” Iaşi


1.1 Pentru cerinţa1 şi cerinţa2
Notăm cu t1 , t2 , ..., tn numărul de utilizări pentru fiecare tip de găleată.
Se foloseşte un algoritm de tip succesor prin adunare cu 1 ı̂n baza k  1 pe n poziţii. Algoritmul
ı̂ncepe de la combinaţia nulă:

t1 0, t2 0, ..., tn1 0; tn 0 (15.1.1)

După o adunare cu 1 o să obţinem:

t1 0, t2 0, ..., tn1 0; tn 1 (15.1.2)

După k adunări cu 1 o să obţinem:

t1 0, t2 0, ..., tn1 0; tn k (15.1.3)

Iar după k  1 adunări de 1:

t1 0, t2 0, ..., tn1 1; tn 0 (15.1.4)

Cantitatea totală de apă se calculează folosind formula:

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

Pentru cerinţa 1 se numără ı̂ncă o soluţie şi se trece la combinaţia următoare.


Pentru cerinţa 2 se verifică dacă combinaţia are mai puţine operaţii şi se reţine minimul apoi
se trece la combinaţia următoare.
Cantitatea totală de apă se calculează folosind formula: V t1 ˜ c1  t2 ˜ c2  ...  tn ˜ cn .
1.2 Soluţii alternative

ˆ 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)

1.3 Pentru cerinţa 3


Se calculează suma S a oricăror p capacităţi succesive. Dacă V se divide la S atunci am
detectat o soluţie posibilă. Dintre toate soluţiile găsite o reţinem şi afişăm pe cea care foloseşte
numărul minim de găleţi.
Pentru calcularea lui S se pot folosi următoarele metode:

ˆ 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:

ˆ lucrul cu tablouri unidimensionale


ˆ adunare pe vector ı̂ntr-o bază de numeraţiedunare ı̂n baza de numeraţie k
ˆ lucrul cu baze de numeraţie
ˆ determinare minim
ˆ tehnica algoritm de tip succesor
ˆ sume parţiale pe vector

15.1.2 *Cod sursă

15.1.3 *Rezolvare detaliată

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

Fişierul de ieşire pasari.out va conţine pe prima linie


ˆ dacă C 1 un singur număr natural, reprezentând coloana minimă determinată conform
cerinţei
ˆ dacă C 2 două numere naturale, reprezentând linia şi coloana determinată conform cerinţei

Restricţii şi precizări

ˆ 5&N & 1 000


ˆ 1 & ı̂nu alţimea oricărui pom & 100 000
ˆ Pentru rezolvarea corectă a primei cerinţe se obţin 30 de puncte, iar pentru rezolvarea corectă
a celei de a doua cerinţe se obţin 70 de puncte.

Exemple:

pasari.in pasari.out Explicaţii


1 3 Pe linia 2 aşezarea optimă este pe coloana 3, ı̂n felul acesta fiind
52 protejaţi 8 pomi. În exemplu pomii protejaţ i de sistemul plasat
84 391 pe coloana a treia sunt marcaţi cu roşu.
5 1421
67 231
76 411
11 111

2 32 Pomul situat la poziţia (3,2), adică pe linia 3 şi coloana 2, este


5 supravegheat de opt sisteme. Acestea sunt situate la poziţiile
1 2 3 2 1 (1,2), (2,2), (3,2), (4,2), (5,2), (3,1), (3,3) şi (3,5) şi sunt mar-
2 2 3 2 2 cate ı̂n exemplu cu albastru. Pomul situat la poziţia (3,4) este
3 2 3 2 3 protejat tot de 8 sisteme de supraveghere, dar conform regulii
2 2 3 2 2 din enunţ se va afişa cel situat pe linia mai mică, respectiv 3 2.
1 2 3 2 1

Timp maxim de executare/test: 0.5 secunde pe Windows, 0.5 secunde pe Linux


Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 15 KB
CAPITOLUL 15. ONI 2021 15.2. PĂSĂRI 193

15.2.1 Indicaţii de rezolvare

Propunător: Prof. Daniela Lica, Centrul Judeţean de Excelenţa Prahova, Ploieşti


2.1 Notaţii:

ˆ 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);

2.2 Cerinţa 1 - C 1 (30 de puncte)

ˆ În cadrul acestei cerinţ e, avem la dispoziţie un singur dispozitiv de supraveghere, pe


care dorim să ı̂l amplasăm ı̂ntr-un pom situat pe linia L, astfel ı̂ncât numărul pomilor
supravegheaţi de acesta să fie maxim.
Putem spune că un dispozitiv amplasat ı̂n pomul de pe linia i şi coloana j (1 & i & N ; 1 &
j & N ) va supraveghea un număr de pomi (inclusiv pomul de pe linia i şi coloana j) egal cu
Extindereij , după cum arată formula următoare:

Extindereij  Sudij   N ordij 1  Estij   V estij   1  1

ˆ 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ă:

int ans = 0, Max = 0;


for(int j = 1; j <= N; ++j)
if(Extindere[L][j] > Max)
Max = Extindere[L][j], ans = j;
afiseaza ans;

ˆ 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.

2.3 Cerinţa 2 - C 2 (70 de puncte)

ˆ Î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).

- pe orizontală (direcţia V est  Est):

(i; V est[i][j] + 1);


(i; V est[i][j] + 2);
...;
(i; j 1); (i; j + 1);
...;
(i;Est[i][j] 2);
(i;Est[i][j] 1)

- ı̂n care este amplasat: (i; j).


ˆ Aşadar, pentru fiecare pom, vom introduce notaţia: cntij  V 
pomul situat pe linia
i şi coloana j va fi supravegheat de V dispozitive (1 & i & N ; 1 & j & N ). Răspunsul va
fi dat de indicii liniei x, respectiv coloanei y pentru care valoarea cntxy  este maximă,
după cum urmează:
CAPITOLUL 15. ONI 2021 15.3. PUTERNIC 195

int ans_i = 0, ans_j = 0, Max = 0;


for(int x = 1; x <= N; ++x)
for(int y = 1; y <= N; ++y)
if(cnt[x][y] > Max)
Max = cnt[x][y], ans_i = x, ans_j = y;
afiseaza ans_i ans_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);

ˆ Pentru a nu degenera complexitatea totală O N N , marcarea pomilor supravegheaţi de


dispozitive se va face utilizând Şmenul lui Mars.

15.2.2 *Cod sursă

15.2.3 *Rezolvare detaliată

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

1. Câte numere puternice sunt ı̂n şirul dat;


2. Care sunt perechile de numere din şirul rămas după ştergerea numerelor puternice, numere
egal departate de capetele şirului, prin concatenarea cărora se obţine un număr puternic.

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.

Restricţii şi precizări

ˆ 1&N & 100 000


ˆ 1 & X1 , X2 , X3 , ..., XN & 1 000 000 000
ˆ Pentru rezolvarea corectăa a primei cerinţe se obţin 30 de puncte, iar pentru rezolvarea
corectă a celei de a doua cerinţe se obţin 70 de puncte.

Exemple:

puternic.in puternic.out Explicaţii


1 8 Se rezolva prima cerinţa. Numerele puternice sunt
8 100 16 484 25 27.
100 28 16 11 484 25 162 27
2 12 5 Se rezolvă a doua cerinţă şi se va folosi doar val-
11 1 21 oarea N . După ştergerea numerelor puternice,
12 9 1 8 19 6 3 4 49 21 5 şirul rămas este: 12 1 19 6 3 21 5.

Timp maxim de executare/test: 0.5 secunde pe Windows, 0.5 secunde pe Linux


Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 15 KB

15.3.1 Indicaţii de rezolvare

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

catenării se obţin numere & 10 (long long).


18

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:

– dacă este număr prim NU poate fi puternic


4 2 2
– dacă este produs de 4 numere prime, pentru a fi puternic, poate fi de forma p sau p q
(adică pătrat perfect, indiferent de formă)
3
– daca e produs de 3 numere prime pentru a fi puternic trebuie să fie de forma p (trebuie
2
să se divida cu p şi cu p ).
2
– daca e produs de 2 numere prime pentru a fi puternic trebuie să aibă forma p

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).

15.3.2 *Cod sursă

15.3.3 *Rezolvare detaliată


Capitolul 16

ONI 2020 - suspendat !!!

... ... ... ...

198
Capitolul 17

ONI 2019

17.1 maya - ONI 2019


Problema 1 - maya 100 de puncte
Regina stupului este plecată, iar cele N albinuţe nou născute trebuie
hrănite. Maya este albina care trebuie să ı̂ndeplinească această sarcină.
Maya ı̂şi face un plan pentru a putea acţiona. Pentru fiecare albinuţă,
Maya porneşte dintr-o celulă iniţială ce conţine cantitatea de miere
necesară şi se deplasează din celulă ı̂n celulă, până la albinuţa pe care
o va hrăni.
Un fagure este format din coloane numerotate cu litere mari ale
alfabetului englez de la A la Z, iar poziţia fiecărei celule de pe o coloană
este identificată prin valori 1, 2, 3, 4, 5, ... de jos ı̂n sus, ca ı̂n figură.
Fiecare celulă a fagurelui are formă hexagonală. Dintr-o celulă se
poate ajunge ı̂n cele 6 celule vecine, prin deplasarea ı̂n direcţiile: 1 -
sus, 2 - dreapta sus, 3 - dreapta jos, etc. (ca ı̂n figura alăturată).
Fagurele este circular, astfel după coloana Z urmează, spre dreapta, Figura 17.1: Maya
coloana A, iar ı̂nainte de coloana A se află, la stânga, coloana Z.

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

Fişierul de ieşire maya.out:


- dacă cerinţa este 1, va conţine o secvenţă de litere mari, ı̂n ordine alfabetică, separate prin
câte un spaţiu, reprezentând coloanele care conţin un număr maxim de celule iniţiale;
- dacă cerinţa este 2, va conţine N linii formate din adrese de forma ColoanăNumăr
reprezentând celulele destinaţie.

Restricţii şi precizări

199
CAPITOLUL 17. ONI 2019 17.1. MAYA - ONI 2019 200

1 & N & 1000


a Fiecare secvenţă de mutări este formată din cel mult 200 de cifre
a În teste nu vor exista deplasări ı̂n direcţia 4 pentru celulele aflate pe primele poziţii din
fiecare coloană A1, B1, C1, ..., Z1 şi nici ı̂n direcţiile 3 şi 5 pentru fiecare dintre coloanele:
B1, D1, F 1, H1, ...
a Pe fiecare verticală, coloanele pot conţine cel mult 5000 de celule.

Exemple

Figura 17.2: MayaIR

Timp maxim de executare/test: 0.5 secunde


Memorie: total 4 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 10 KB
Sursa: maya.cpp, maya.c sau maya.pas va fi salvată ı̂n folderul care are drept nume ID-ul tău.

17.1.1 Indicaţii de rezolvare

prof. Adrian NITA - Colegiul National ”Emanuil Gojdu”, Oradea

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, ...

ˆ Daca suntem in coloanele A, C, E, G ... atunci val urmatoare se va construi astfel,


val anterioara+1 pe directiile 1, 2, 6 i val anterioara -1 pe directia 4 si aceeasi valoare
pe directiile 3 si 5

ˆ Daca suntem in coloanele B, D, F, H, ... atunci val urmatoare se va construi astfel,


val anterioara +1 pe directia 1, aceeasi valoare pe directiile 2 si 6 si val anterioara -1 pe
directiile 3, 4, 5

17.1.2 Cod sursă


CAPITOLUL 17. ONI 2019 17.1. MAYA - ONI 2019 201

Listing 17.1.1: maya100Adi.cpp


1 #include <fstream>
2 #define M 10000
3 #include<cstring>
4
5 using namespace std;
6
7 ifstream fin("maya.in");
8 ofstream fout("maya.out");
9
10 int n;
11 char start[M][11];
12
13 void cerinta_1()
14 {
15 int viz[27]={0}, maxf=0, maxv=0, val, x;
16 char ch;
17 fin >> n;
18 for(int i=1; i<=n; i++)
19 {
20 fin >> ch >> val;
21 x = ch -’A’;
22 if(x > maxv)
23 maxv = x;
24 viz[x]++;
25 if(viz[x] > maxf)
26 maxf = viz[x];
27 }
28 for(x=0; x<=maxv; x++)
29 if(viz[x] == maxf)
30 fout <<(char)(x+’A’)<<’ ’;
31 fout << ’\n’;
32 }
33
34 void cerinta_2()
35 {
36 char ant, urm, cif;
37 int valin, valfin, val, i, c, cate;
38 fin >> n;
39 for(i=1; i<=n; i++)
40 {
41 fin >> start[i];
42 //fout<<start[i]<<’ ’;
43 }
44 //fout << ’\n’;
45 for(i=1; i<=n; i++)
46 {
47 ant = start[i][0];
48 valin = 0;
49 for(unsigned int k=1; k<strlen(start[i]); k++)
50 valin = valin*10 + (start[i][k]-’0’);
51 fin >> cate;
52 for(int j=1; j<=cate; j++)
53 {
54 fin >> cif;
55 c = ant - ’A’;
56 val = cif - ’0’;
57 if(c%2 == 0)
58 {
59 switch(val)
60 {
61 case 1:
62 urm = ant;
63 valfin = valin + 1;
64 break;;
65 case 2:
66 urm =(char)(ant + 1);
67 valfin = valin + 1;
68 break;
69 case 3:
70 urm =(char)(ant + 1);
71 valfin = valin;
72 break;
73 case 4:
74 urm = ant;
CAPITOLUL 17. ONI 2019 17.1. MAYA - ONI 2019 202

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 }

Listing 17.1.2: maya100PLV.cpp


1 //autor: prof. Liviu-Vasile Pinzaru,
2 // Palatul Copiilor Suceava & Clubul Copiilor Falticeni
3
4 #include <fstream>
5
CAPITOLUL 17. ONI 2019 17.1. MAYA - ONI 2019 203

6 using namespace std;


7
8 const int dim=10004;
9
10 int w[140];
11 int v[dim];
12 char ch[dim],s[dim];
13
14 int main()
15 {
16 ifstream f("maya.in");
17 ofstream g("maya.out");
18
19 int p;
20 int i=0,j=0,k=0,N=0,x=0,y=0,maxx=0,n;
21 int cod, ref1,ref2;
22 char a;
23
24 f>>p;
25 f>>N;
26
27 if(p==1)
28 {
29 for(i=1;i<=N;i++)
30 {
31 f>>a>>x;
32 w[a]++;
33 }
34
35 for(j=’A’;j<=’Z’;j++)
36 {
37 if(maxx<w[j])
38 maxx=w[j];
39 }
40
41 //g<<maxx;
42 for(j=’A’;j<=’Z’;j++)
43 {
44 if(maxx==w[j])
45 g<<(char)j<<’ ’;
46 }
47 }
48
49
50 if(p==2)
51 {
52 for(i=1;i<=N;i++)
53 {
54 f>>ch[i]>>v[i];
55 }
56
57 ref1=’A’-1;
58 ref2=’Z’+1;
59
60 for(i=1;i<=N;i++)
61 {
62 f>>n;
63 f>>s;
64 /***************************/
65 //g<<n<<" "<<s<<’\n’;
66 /***************************/
67 //x=0;
68 y=v[i];
69
70 //g<<ch[i]<<" "<<v[i]<<’\n’;
71 cod=ch[i];
72
73
74 //-------------------------------
75 for(j=0;j<n;j++)
76 {
77 //g<<s[j]<<’ ’;
78 if(s[j]==’1’)
79 {
80 y++;
81 }
CAPITOLUL 17. ONI 2019 17.2. OPTIME - ONI 2019 204

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 }

17.1.3 *Rezolvare detaliată

17.2 optime - ONI 2019


Problema 2 - optime 100 de
puncte
Maria iubeşte numerele prime. Ea scrie pe o foaie de hârtie, ı̂n ordine
strict crescătoare, un şir format din numerele prime care au cel puţin 2 cifre.
Apoi, din numerele care conţin mai mult de 2 cifre taie cifrele din stânga,
astfel ı̂ncât să rămână exact 2 cifre. Dacă după tăierea cifrelor numărul
obţinut nu este cuprins ı̂ntre 10 şi 99, numărul este eliminat din şir. De
exemplu, numărul prim 101, care are 3 cifre, nu va fi scris, deoarece i se taie
cifra din stânga, rezultând numărul 01, adică 1, care nu are exact 2 cifre,
deci după tăiere va fi eliminat din şir.
Maria umple un tabel cu 2˜k linii şi k coloane, astfel ı̂ncât, parcurgându-l
pe linii, de sus ı̂n jos şi fiecare linie de la stânga la dreapta, se obţin numerele
Figura 17.3: Op-
time
CAPITOLUL 17. ONI 2019 17.2. OPTIME - ONI 2019 205

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

Cunoscând un număr natural k nenul şi un număr natural x, ajutaţi-o pe Maria:


1. Să determine suma numerelor din tabel care nu sunt prime. Dacă nu există numere care nu
sunt prime, suma are valoarea 0.
2. Să aleagă x coloane consecutive din tabel, astfel ı̂ncât acestea să conţină, ı̂n total, un
număr maxim de numere prime. Dacă există mai multe posibilităţi, se va alege secvenţa de
coloane consecutive care are o valoare cât mai mare a coloanei de ı̂nceput din secvenţă. Să se
determine numărul primei coloane din secvenţa aleasă, precum şi numărul total de numere prime
din secvenţă.

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.

Restricţii şi precizări

1 & x & k & 200;


a Pentru rezolvarea primei cerinţe se acordă 30% din punctaj, iar pentru cerinţa a doua se
acordă 70% din punctaj.

Exemple

optime.in optime.out Explicaţii


1 286 Pentru k 4, ı̂n tabel se află următoarele numere neprime:
4 27, 39, 49, 51, 57, 63, suma lor fiind 286.
2 2 19 Coloana 1 conţine 7 numere prime, coloana 2 conţine 6 nu-
43 mere prime, coloana 3 conţine 6 numere prime, iar coloana
4 conţine 7 numere prime. Putem alege fie coloanele 1, 2, 3,
fie coloanele 2, 3, 4, ambele variante conţinând câte 19 numere
prime. Se alege a doua variantă, pentru că are valoarea mai
mare a coloanei de ı̂nceput a secvenţei.

Timp maxim de executare/test: 0.2 secunde


Memorie: total 16 MB din care pentru stivă 8 MB
Dimensiune maximă a sursei: 10 KB
Sursa: optime.cpp, optime.c sau optime.pas va fi salvată ı̂n folderul care are drept nume ID-ul
tău.

17.2.1 Indicaţii de rezolvare

VARIANTA 1 - 100 PUNCTE


Prof. Violeta Grecea - Colegiul National de Informatica ”Matei Basarab” Ramnicu Valcea
Pentru rezolvarea ambelor cerinte se vor genera numerele prime folosind ciurul lui Eratostene.
CAPITOLUL 17. ONI 2019 17.2. OPTIME - ONI 2019 206

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.

17.2.2 Cod sursă

Listing 17.2.1: optimeFBB.cpp


1 #include <iostream>///Flavius Boian
2 #include<fstream>
3
4 using namespace std;
5
6 ifstream f("optime.in");
7 ofstream g("optime.out");
8
9 int v[]= {0,2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
10 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131,
11 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
12 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
13 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373,
14 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457,
15 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557,
16 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641,
17 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
18 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827,
19 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929,
20 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019,
21 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087};
22
23 int prim(int n)
24 {
25 int i, ok=1;
26 for(i=1; v[i]*v[i]<=n; i++)
27 if(n%v[i]==0)
28 {
29 ok=0;
30 break;
31 }
32 return ok;
33 }
34
35 int i,j,k,n,d,s,ap[201],x,maxim,suma,incepe,C;
36
37 int main()
38 {
39 f>>C;
40
41 if(C==1)
42 {
43 f>>k;
44 d=11;
45 for(i=1; i<=2*k; i++)
46 for(j=1; j<=k; j++)
47 {
48 while(prim(d)==0 or (d/10)%10==0)
49 d=d+2;
50 if(prim(d%100)==0)
CAPITOLUL 17. ONI 2019 17.2. OPTIME - ONI 2019 207

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 }

Listing 17.2.2: optimePLV.cpp


1 //autor: prof. Liviu-Vasile Pinzaru,
2 // Palatul Copiilor Suceava & Clubul Copiilor Falticeni
3
4 #include <fstream>
5 #include<bitset>
6 #include<cmath>
7
8 using namespace std;
9 const int dim=1200004;
10
11 bitset<dim>a;
12
13 int v[408];
14 int N;
15
16 int main()
17 {
18 int p;
19 int i=0,j=0,k,N,x,y,nr=0,stop,S=0,poz;
20 int Smax=0,gasit=0;
21
22 ifstream f("optime.in");
23 ofstream g("optime.out");
24
25 /********sita Eratostene************/
26 N=dim;
27 x=sqrt(N);
28 a[0]=1;
29 a[1]=1;
30 for(j=2*2;j<=N;j=j+2)
31 a[j]=1;
CAPITOLUL 17. ONI 2019 17.2. OPTIME - ONI 2019 208

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 }

Listing 17.2.3: optimeVMG.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 bool ciur[1200001];
6 int i,j,n,k,v[201], mx,c,ct,nrn,x,p;
7 unsigned int s;
8
9 int main()
10 {
11 ifstream f("optime.in");
12 ofstream g("optime.out");
13
14 f>>c;
15 n=1200000;
16 ciur[1]=1;
17
18 for(i=2;i*i<=n;i++)
19 for(j=2;j<=n/i;j++)
20 ciur[i*j]=1;
21
22 if(c==1)
23 {
24 f>>k;
25 nrn=2*k*k;
26 i=11;
27 while(ct<nrn)
28 {
29 if(ciur[i]==0 && i%100>=10)
30 {
31 ct++;
32 if(ciur[i%100]==1)
33 {
34 x++;
35 s=s+i%100;
36 }
37 }
38
39 i=i+2;
40 }
41
42 g<<s;
43 }
44 else
45 {
46 f>>k>>x;
47
48 nrn=2*k*k;
49 i=11;
50 while(ct<nrn)
51 {
52 if(ciur[i]==0 && i%100>=10)
53 {
54 ct++;
55 if(ct%k!=0)
56 {
57 if(ciur[i%100]==0) v[ct%k]++;
58 }
CAPITOLUL 17. ONI 2019 17.3. ROATA - ONI 2019 210

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 }

17.2.3 *Rezolvare detaliată

17.3 roata - ONI 2019


Problema 3 - roata 100 de puncte
Cei N elevi participanţi la olimpiadă au fost invitaţi să admire panorama oraşului din roata cu
N locuri instalată ı̂n Orăşelul Copiilor. Fiecare elev poartă un tricou inscripţionat cu un număr
natural, numerele de pe tricouri fiind diferite două câte două şi având valori cuprinse ı̂ntre 1 şi
N . Iniţial, ei ocupă toate cele N locuri din roată, ı̂ncepând cu cel mai de jos scaun şi continuând
cu următoarele scaune, ı̂n sensul acelor de ceasornic. Roata se mişcă circular, ı̂n sensul acelor de
ceasornic, cu un număr de poziţii, se opreşte şi elevul aflat pe scaunul cel mai de jos coboară. În
continuare, ea se roteşte ı̂n acelaşi sens, un număr mai mare de poziţii, apoi se opreşte şi coboară
elevul aflat pe scaunul cel mai de jos şi aşa mai departe până când coboară toţi elevii.

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.

Restricţii şi precizări


CAPITOLUL 17. ONI 2019 17.3. ROATA - ONI 2019 211

2 & N & 50000;


a pentru 50% din punctaj, 2 & N & 1000;
a dacă, iniţial, elevul cu tricoul inscripţionat cu 1 se află ı̂n scaunul cel mai de jos al roţii, el
va coborı̂ după ce roata se va mişca N poziţii şi va ajunge din nou pe scaunul cel mai de jos.

Exemple

Figura 17.4: RoataIR1

Figura 17.5: RoataIR2

Timp maxim de executare/test: 0.2 secunde


Memorie: total 4 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 5 KB
Sursa: roata.cpp, roata.c sau roata.pas va fi salvată ı̂n folderul care are drept nume ID-ul tău.

17.3.1 Indicaţii de rezolvare

Prof. Rodica Pintea, liceul teoretic RADU VLADESCU, Patirlagele, Buzau


Pentru a obtine numarul de pozitii cu care trebuie miscata roata, trebuie sa cunoastem numarul
scaunului pe care este asezat elevul cu tricoul i la rotirea cu numarul i.
Memoram numarul scaunului pe care afla initial elevul cu tricoul i, pentru fiecare i de la 1 la
n. Acest lucru se poate realiza odata cu citirea datelor, fara sortare.
Apoi, la fiecare moment i, se calculeaza numarul scaunului pe care se afla elevul cu tricoul i,
cunoscand numarul initial si numarul de pozitii cu care s-a miscat roata pana in acel moment.
Daca numarul scaunului este mai mare sau egal cu numarul scaunului pe care se afla elevul cu
CAPITOLUL 17. ONI 2019 17.3. ROATA - ONI 2019 212

tricoul i  1 la momentul i  1, se va adauga o rotatie completa suplimentara la rotatiile complete


adaugate anterior.

17.3.2 Cod sursă

Listing 17.3.1: roata100FB.cpp


1 #include<iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("roata.in");
7 ofstream g("roata.out");
8
9 long long n,x,i,k,suma,a,poz[100010];
10
11 int main()
12 {
13 f>>n;
14 for(i=0; i<n; i++)
15 f>>x,poz[x-1]=i;
16 x=0;
17 for(i=0; i<n; i++)
18 {
19 k=n-(suma+poz[i])%n;
20 if(k<=x)
21 a=a+n;
22 x=k;
23 k=k+a;
24 suma=suma+k;
25 g<<k<<" ";
26 }
27 return 0;
28 }

Listing 17.3.2: roata100PLV.cpp


1 // autor: prof. Liviu-Vasile Pinzaru,
2 // Palatul Copiilor Suceava & Clubul Copiilor Falticeni
3 // long long in loc de int ia 100 de puncte
4
5 #include <fstream>
6
7 using namespace std;
8
9 const int dim=100004;
10 int v[dim], ord[dim];
11
12 int main()
13 {
14 ifstream f("roata.in");
15 ofstream g("roata.out");
16
17 int N,i,j,k;
18 int aux,y,nr,dif,x,cat;
19
20 f>>N;
21 f>>v[1];
22 aux=v[1];
23 ord[aux]=1;
24
25 for(i=N;i>1;i--)
26 {
27 f>>v[i];
28 aux=v[i];
29 ord[aux]=i;
30 }
31
32 /**********************************/
33 //for(i=1;i<=N;i++)
34 //{
CAPITOLUL 17. ONI 2019 17.3. ROATA - ONI 2019 213

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 }

Listing 17.3.3: roata100RP.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream fin("roata.in");
6 ofstream fout("roata.out");
7
8 int poz[100010];
9 long long n,i,j,k,sum,vi;
10
11 int main()
12 {
13 fin >> n;
14 for (i=0;i<n;i++)
15 {
16 fin >> j;
17 poz[j-1]=i;
18 }
19
20 k=0;j=0;sum=0;vi=0;
21 for (i=0;i<n;i++)
22 {
23 k=n-(sum+poz[i])%n;
24 if(k<=j){vi+=n;}
25 j=k;
26 k=k+vi;
27 sum+=k;
28 fout<<k<<" ";
29 }
30
31 return 0;
32 }

17.3.3 *Rezolvare detaliată


Capitolul 18

ONI 2018

18.1 descmult - ONI 2018


Problema 1 - descmult 0 de puncte
Se consideră două şiruri D D1 , D2 , ..., Dn  şi E E1 , E2 , ..., En  ce reprezintă descom-
punerea ı̂n factori primi pentru un număr natural nenul X, după cum urmează: Di - factorul
prim, Ei - puterea la care apare factorul prim Di ı̂n descompunerea numărului X (1 & i & n),
unde n reprezintă numărul factorilor primi.

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 .

Restricţii şi precizări

- 2 & n & 20
- 1 & A & B & 10
7

- 2 & Di $ 1000 (numere prime distincte), 1 & i & n


- 1 & Ei & 10, 1 & i & n
- Factorii primi D1 , D2 , ..., Dn nu sunt obligatoriu ı̂n ordine crescătoare
- Se garantează că numărul maxim de divizori naturali ai lui X & 10
19

- Intervalul A, B  conţine cel puţin un divizor


- Numărul maxim de divizori aflaţi ı̂n intervalul A, B  este & 10
6

- Ordinea de afişare a divizorilor nu este importantă


- Pentru rezolvarea corectă a cerinţei 1 se acordă 20 de puncte, iar pentru cea de-a doua cerinţă
se acordă 80 de puncte.

214
CAPITOLUL 18. ONI 2018 18.1. DESCMULT - ONI 2018 215

Exemple

descmult.in descmult.out Explicaţii


1 48 Pentru acest test se rezolvă cerinţa 1.
1 3 2 1
4 30 50 X 3 ˜ 2 ˜ 5 ˜ 11 6600 şi are 48 de divizori: 1, 2, 3, 4,
3 2 5 11 5, 6, 8, 10, 11, 12, 15, 20, 22, 24, 25, 30, 33, 40, 44, 50, 55, 60,
1321 66, 75, 88, 100, 110, 120, 132, 150, 165, 200, 220, 264, 275, 300,
330, 440, 550, 600, 660, 825, 1100, 1320, 1650, 2200, 3300, 6600.
2 30 44 50 40 33 Pentru acest test se rezolvă cerinţa 2.
1 3 2 1
4 30 50 X 3 ˜ 2 ˜ 5 ˜ 11 6600.
3 2 5 11 Divizorii ce aparţin intervalului 30, 50 sunt: 30, 33, 40, 44, 50.
1321 Ordinea de afişare a divizorilor nu este importantă.
Tabelul 18.1: descmult

Timp maxim de executare/test: 1.0 secunde


Memorie: total 32 MB din care pentru stivă 32 MB
Dimensiune maximă a sursei: 10 KB

18.1.1 Indicaţii de rezolvare

prof. Eugen Nodea, Colegiul Naţional ”Tudor Vladimirescu”, Tg-Jiu

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:

Figura 18.1: descmult

18.1.2 Cod sursă

Listing 18.1.1: descmult.cpp


1 // Sursa oficiala autor - Eugen Nodea
2
3 #include <stdio.h>
4
5 int n, a, b, c, nr, k, i, j, m;
6 int D[23], E[23];
7 int F[1000003];
8 unsigned long long nrd, p, y;
CAPITOLUL 18. ONI 2018 18.1. DESCMULT - ONI 2018 216

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

Soluţia anterioară pierde timp ı̂n următoarele puncte:


a Calculează mulţi divizori mai mari decı̂t B pe care ı̂i ignoră
a Din acest motiv face calcule ı̂n long long

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ă:”

Listing 18.1.2: descmult algopedia.cpp


1 #include <stdio.h>
2
3 #define MAXD 999
4 #define MAXN 20
5
6 char puteri[MAXD + 1]; // puteri[d[i]] = puterea factorului d[i] la intrare
7 int d[MAXN + 1], // factorii primi
8 e[MAXN + 1], // puterile maxime
9 f[MAXN + 1], // puterile actuale
10 bmax[MAXN + 1], // valori maxime ce se pot inmulti cu d[i]
11 val[MAXN + 1]; // divizorul curent = produsul factorilor val[i]
12
13 int main() {
14 FILE *fin, *fout;
15 int c, n, a, b, i, t, num;
16 long long p;
17
18 fin = fopen( "descmult.in", "r" );
19 fscanf( fin, "%d%d%d%d", &c, &n, &a, &b );
20 for ( i = 0; i < n; i++ )
21 fscanf( fin, "%d", &d[i] );
22 p = 1; // numarul total de divizori al lui X
23 for ( i = 0; i < n; i++ ) {
24 fscanf( fin, "%d", &num ); // puterea factorului prim d[i]
25 puteri[d[i]] = num;
26 p *= num + 1;
27 }
28 fclose( fin );
29
30 fout = fopen( "descmult.out", "w" );
31 if ( c == 1 ) // cerinta 1, numarul de divizori al lui X
32 fprintf( fout, "%lld\n", p );
33 else { // cerinta 2, numarul de divizori ai lui X in intervalul [a, b]
34 // sortam vectorul de divizori si calculam puterile lor maxime
35 i = 0;
36 for ( t = 2; t <= MAXD; t++ )
37 if ( puteri[t] > 0 ) {
38 d[i] = t;
39 e[i] = 0; // e[i] = puteri[t] (sau mai putin daca d[i]ˆputeri[t] > b)
40 bmax[i] = b / t; // numarul maxim ce se mai poate inmulti cu d[i]
41 num = 1;
42 while ( e[i] < puteri[t] && num <= bmax[i] ) {
43 e[i]++; // d[i]ˆe[i] <= b deci putem incrementa
44 num *= t; // calculam num = d[i]ˆe[i]
45 }
46 i++;
47 }
48 // initializam vectorul de valori ale factorilor primi
49 for ( i = 0; i < n; i++ ) { // d[i]ˆ0 este 1
50 val[i] = 1;
51 f[i] = e[i];
52 }
53 f[n] = bmax[n] = b; // santinela
54 num = 1; // num ia, pe rind, valorile divizorilor doriti
55 do {
56 if ( num >= a )
57 fprintf( fout, "%d ", num );
58 // decrementeaza vect de puteri f[] cu 1 si calculeaza-i val in num
59 // cita vreme nu pot decrementa puterea factorului curent i
60 i = 0;
61 while ( f[i] == 0 || num > bmax[i] ) { // se opreste in santinela
CAPITOLUL 18. ONI 2018 18.2. GAZON - ONI 2018 218

62 num /= val[i]; // resetam exponentul la 0


63 val[i] = 1; // factorul curent este 1
64 f[i] = e[i]; // avem disponibile e[i] puteri
65 i++;
66 }
67 f[i]--; // folosim puterea
68 val[i] *= d[i]; // marim factorul curent
69 num *= d[i]; // numarul curent (produsul valorilor val[i])
70 } while ( i < n ); // cita vreme ultimul divizor a fost <= b
71 fprintf( fout, "\n" );
72 }
73 fclose( fout );
74
75 return 0;
76 }

”Această rezolvare pare a fi de peste două ori mai rapidă.”

18.1.3 *Rezolvare detaliată

18.2 gazon - ONI 2018


Problema 2 - gazon 0 de puncte
Tudorel şi-a construit la Buşteni o casă de vacanţă frumoasă.
Pentru că doreşte ca şi curtea să fie frumoasă, a decis să o
acopere cu gazon. Curtea are formă dreptunghiulară, cu di-
mensiunile a şi b, exprimate ı̂n metri.
Tudorel a discutat cu o firmă de specialitate, iar specialiştii
firmei i-au spus că pot acoperi grădina cu dale de gazon de
formă pătrată de latură d metri. Dacă este necesar, dalele pot
fi tăiate cu un cuţit special. Cuţitul are o lamă lungă (% d), Figura 18.2: gazon1
poate fi plasat paralel cu una dintre laturile dalei, iar atunci când taie, face o tăietură completă,
de la un capăt la celălalt, obţinându-se două fâşii dreptunghiulare.
Totuşi, specialiştii afirmă că gazonul nu rezistă dacă ı̂ntr-o dală se execută mai multe tăieturi
şi că este obligatoriu ca, atunci când o zonă de grădină nu este acoperită de o dală ı̂ntreagă, să
fie acoperită de o singură fâşie (nu mai multe). ı̂n acest mod, spun specialiştii, este posibil ca ı̂n
unul dintre colţurile grădinii să rămână o zonă dreptunghiulară neacoperită.
Tudorel spune că ı̂n acest caz va cumpăra un câine şi va instala acolo cuşca câinelui.
Evident, Tudorel doreşte să acopere cu gazon ı̂ntreaga curte cheltuind cât mai puţini bani.
Firma i-a comunicat:
- costul cd al unei dale de gazon;
- costul ct al unei tăieturi;
- costul cm al montării unei dale sau al unei fâşii.

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).

Restricţii şi precizări

a 1 & a, b, d & 10000000


a 1 & ct, cd, cm & 1000
a Dacă nu rămâne loc pentru cuşca câinelui, amin va fi 0.
a Pentru rezolvarea cerinţei 1 se acordă 10% din punctaj, pentru rezolvarea cerinţei 2 se acordă
60% din punctaj, iar pentru rezolvarea cerinţei 3 se acordă 30% din punctaj.

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

Figura 18.3: gazon2

Timp maxim de executare/test: 0.1 secunde


Memorie: total 16 MB din care pentru stivă 8 MB
Dimensiune maximă a sursei: 10 KB

18.2.1 Indicaţii de rezolvare

prof. Marinel Şerban, Colegiul Naţional ”Emil Racoviţă”, Iaşi

surse oficiale: Ana-Maria Arişanu Miana, Cerchez Emanuela


Cazuri posibile:
1. a şi b divizibile cu d
2. a sau b divizibile cu d
3. a % d + b % d = d şi a % d j d / 2 si b % 2 j d / 2
4. a % d j 0 şi b % d = d / 2
5. a % d = d / 2 şi b % d != 0
CAPITOLUL 18. ONI 2018 18.2. GAZON - ONI 2018 220

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

18.2.2 Cod sursă

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

Iată o soluţie bazată pe aceste idei: ”


CAPITOLUL 18. ONI 2018 18.2. GAZON - ONI 2018 221

Listing 18.2.1: gazon algopedia.cpp


1
2 #include <stdio.h>
3
4 int main() {
5 FILE *fin, *fout;
6 int c, a, b, d, cd, ct, cm; // valorile de intrare
7 int n, nl, nc, dv, dh, nm, nt, i;
8 int ndale[2]; // ndale[i] = numarul de dale de tip i
9 int ddale[2]; // ddale[i] = latimea unei dale de tip i
10 long long di, amin;
11
12 fin = fopen( "gazon.in", "r" );
13 fscanf( fin, "%d%d%d%d%d%d%d", &c, &a, &b, &d, &cd, &ct, &cm );
14 fclose( fin );
15
16 // punctul 1 - dale intregi si aria minima ramasa neacoperita
17 nl = a / d; // numarul de dale pe linii
18 nc = b / d; // numarul de dale pe coloane
19 di = nl * (long long)nc; // numarul de dale intregi
20 dv = a % d; // dimensiunea verticala ramasa jos
21 dh = b % d; // dimensiunea orizontala ramasa la dreapta
22 amin = dv * (long long)dh; // aria ramasa neacoperita
23
24 // punctul 2 si 3 - numarul minim de dale necesare, si numarul de taieturi
25 // avem nc dale de dimensiune dv x d
26 // avem nl dale de dimensiune d x dh
27 // incercam sa le combinam cit mai bine
28 // asezam numarul de dale precum si dimensiunea mica a lor intr-un vector
29 n = 0; // numarul de tipuri de dale extra
30 nm = 0; // numarul de dale extra de montat
31 if ( dh > 0 && nl > 0 ) { // adaugam doar daca avem cel putin o dala
32 ndale[0] = nl; // de arie nenula
33 ddale[0] = dh;
34 n++;
35 nm += nl; // avem de montat nl dale
36 }
37 if ( dv > 0 && nc > 0 ) { // adaugam doar daca avem cel putin o dala
38 ndale[n] = nc; // de arie nenula
39 ddale[n] = dv;
40 n++;
41 nm += nc; // avem de montat nc dale
42 }
43
44 nt = 0; // numarul de taieturi (egal cu numarul de dale extra)
45 if ( n > 1 && // daca avem dale atit pe orizontala cit si pe verticala si
46 ddale[0] == ddale[1] ) { // dimensiunile lor sint egale, le combinam
47 ndale[0] += ndale[1];
48 n = 1;
49 }
50
51 // in acest moment avem 1 sau 2 tipuri de dale
52 if ( n == 2 && ddale[0] + ddale[1] == d ) // daca se pot combina
53 nt += ndale[0] > ndale[1] ? ndale[0] : ndale[1]; // taiem maximul
54 else // se pot combina cel mult in cadrul aceluiasi tip
55 for ( i = 0; i < n; i++ )
56 if ( 2 * ddale[i] == d )
57 nt += (ndale[i] + 1) / 2; // nr de taieturi e aproximativ jumate
58 else
59 nt += ndale[i]; // altfel le taiem pe toate
60
61 fout = fopen( "gazon.out", "w" );
62 if ( c == 1 )
63 fprintf( fout, "%lld %lld\n", di, amin );
64 else
65 fprintf( fout, "%lld\n", c == 2 ? di + nt :
66 (di + nt) * cd + nt * (long long)ct + (di + nm) * cm );
67 fclose( fout );
68
69 return 0;
70 }

”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

18.2.3 *Rezolvare detaliată

18.3 pietre - ONI 2018


Problema 3 - pietre 0 de puncte
O tablă de joc cu n linii, numerotate de la 1 la n şi m coloane, numerotate de la 1 la m conţine
n ˜ m celule identice. Celula din colţul din stânga sus se află pe linia 1 şi coloana 1.
O celulă poate fi: celulă liberă, celulă ı̂n care se află o piatră sau celulă de tip gaură.
Pietrele sunt numerotate cu valori ı̂ncepând de la 1. Numerotarea pietrelor pe tablă se face ı̂n
ordinea ı̂n care sunt date ı̂n fişierul de intrare.
O celulă de pe tablă are maxim patru celule vecine, aflate ı̂n direcţiile: nord, vest, sud, est,
iar o piatră poate sări doar peste o celulă vecină ı̂n care se află o piatră. ı̂n urma unei astfel de
sărituri, piatra peste care s-a sărit dispare de pe tablă. Astfel, o piatră situată ı̂n celula de pe
linia i şi coloana j, poate sări:
- ı̂n direcţia nord peste piatra situată ı̂n celula de pe linia i  1 şi coloana j şi ajunge ı̂n celula
de pe linia i  2 şi coloana j, iar piatra aflată pe linia i  1 şi coloana j dispare; o astfel de săritură
se notează cu litera N ;
- ı̂n direcţia est peste piatra situată ı̂n celula de pe linia i şi coloana j  1 şi ajunge ı̂n celula de
pe linia i şi coloana j  2, iar piatra aflată pe linia i şi coloana j  2 dispare; o astfel de săritură
se notează cu litera E;
- ı̂n direcţia sud peste piatra situată ı̂n celula de pe linia i  1 şi coloana j şi ajunge ı̂n celula
de pe linia i  2 şi coloana j, iar piatra aflată pe linia i  1 şi coloana j dispare; o astfel de săritură
se notează cu litera S;
- ı̂n direcţia vest peste piatra situată ı̂n celula de pe linia i şi coloana j  1 şi ajunge ı̂n celula
de pe linia i şi coloana j  2, iar piatra aflată pe linia i şi coloana j  1 dispare; o astfel de săritură
se notează cu litera V .
O săritură a unei pietre este permisă doar dacă celula ı̂n care urmează să ajungă se află pe
tabla de joc, este liberă şi ı̂n celula peste care sare există o piatră.
Se cunoaşte o succesiune de sărituri formată din maxim 255 de caractere S, N, E sau V, după
care o piatră realizează săriturile specificate, ı̂n ordine, de la stânga la dreapta. Dacă piatra ar
trebui execute o săritură care nu este permisă, poziţia ei nu se modifică şi se trece la săritura
următoare din succesiune.

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

Fişierul de intrare pietre.in va conţine:


- pe prima linie din fişier numărul natural n care reprezintă numărul de linii, numărul natural
m care reprezintă numărul de coloane, numărul natural de pietre k şi numărul natural de găuri g,
valori separate ı̂ntre ele două câte două printr-un spaţiu;
- pe următoarele k linii, câte două valori separate două câte două printr-un spaţiu, reprezentând
linia şi coloana unei pietre;
- pe următoarele g linii, câte două valori separate două câte două printr-un spaţiu, reprezentând
linia şi coloana unei găuri;
- pe ultima linie se află succesiunea de sărituri.

Date de ieşire

Fişierul de ieşire pietre.out va conţine:


- pe prima linie numărul pietrei căreia aplicându-i-se succesiunea de sărituri conduce la
configuraţia conţinând cel mai mic număr de pietre;
- pe a doua linie se află numărul de pietre din configuraţia finală (fie acesta t);
- pe următoarele t linii se află câte două valori, separate ı̂ntre ele printr-un spaţiu, reprezentând
linia şi coloana fiecărei pietre rămase pe tablă, ı̂ncepând cu cea mai de sus (linia cea mai mică) şi
CAPITOLUL 18. ONI 2018 18.3. PIETRE - ONI 2018 223

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.

Timp maxim de executare/test: 2.0 secunde


Memorie: total 16 MB din care pentru stivă 8 MB
Dimensiune maximă a sursei: 10 KB

18.3.1 Indicaţii de rezolvare

prof. Tı̂mplaru Roxana, Colegiul ”Ştefan Odobleja” Craiova


Se marchează existenţa pietrelor ı̂n matrice cu o valoare, de exemplu cu valoarea 1.
Se marchează găurile ı̂n matrice cu o valoare diferită de cea ı̂n care există pietre, de exemplu
cu 1.
Se poate borda matricea cu aceeaşi valoare ca şi găurile sau cu o valoare convenabilă, diferită
de cea ı̂n care există pietre.
Se alege pe rând fiecare piatră, se aplică secvenţa de sărituri, la fiecare pas verificându-se
posibilitatea efectuării mişcării respective.
Se determină numărul de pietre rămase dacă se aplică secvenţa de sărituri pentru fiecare piatră
pe rând.
Se afişează numărul pietrei şi configuraţia finală pentru care rămân cele mai puţine pietre ı̂n
final.

18.3.2 *Cod sursă

18.3.3 *Rezolvare detaliată


Capitolul 19

ONI 2017

19.1 faleza - ONI 2017


Problema 1 - faleza 100 de puncte
Acum iarna s-a terminat şi, apropiindu-se sezonul de vară, gospodarii din oraşul de pe malul
fluviului doresc să pregătească faleza pentru a primi cum se cuvine turiştii. Faleza este sub formă
dreptunghiulară cu lungimea de n metri şi lăţimea de 2 metri. În toamnă ea era pavată cu 2n
dale pătrate cu latura de un metru, lipite una de alta şi care acopereau complet zona falezei. În
urma iernii grele, unele dale s-au deteriorat şi acum se doreşte ı̂nlocuirea lor. Cum de multe ori
oamenii fac treaba doar ”pe jumătate”, gospodarii au hotărât să cheltuie cât mai puţin pentru
reamenajarea falezei, aşa că au decis că nu trebuie neapărat să ı̂nlocuiască toate dalele deteriorate,
ci doar un număr minim dintre acestea astfel ı̂ncât să fie posibil să se parcurgă faleza de la un
capăt la altul păşind doar pe dale bune (nedeteriorate). De pe o dală pe alta se poate păşi doar
dacă ele au o latură comună.

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.

Restricţii şi precizări

a 3 & n & 100000;


a pentru teste ı̂n valoare de 20 puncte, una dintre părţile falezei are ı̂n ı̂ntregime dale deterio-
rate.

Exemple

224
CAPITOLUL 19. ONI 2017 19.1. FALEZA - ONI 2017 225

faleza.in faleza.out Explicaţii


8 5 Am notat cu D o dală ı̂nlocuită.
00111000 DD111000
00000001 0000DDD1
ı̂n această soluţie, faleza poate fi parcursă de la stânga la dreapta
păşind pe 5 dale de sus, apoi se coboară pe partea de jos şi se
păşeşte pe cele 4 dale, până se ajunge ı̂n dreapta.
sau
DD111DDD
00000001
ı̂n această soluţie, faleza poate fi parcursă de la stânga la dreapta
păşind doar pe dalele de sus.

Timp maxim de executare/test: 0.3 secunde


Memorie: total 8 MB
Dimensiune maximă a sursei: 10 KB

19.1.1 Indicaţii de rezolvare

prof. Marius Nicoli, Colegiul Naţional ”Fraţii Buzeşti”, Craiova

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.

19.1.2 Cod sursă

Listing 19.1.1: faleza CristinaI.cpp


1 #include<fstream>
2
3 using namespace std;
4
5 ifstream fin("faleza.in");
6 ofstream fout("faleza.out");
7
8 bool v[2][200005];
9
10 int main()
11 {
12 char c;
13 int N,i,t=0,kint;
14 fin>>N;
15 v[0][N+1]=1;
16 v[1][N+1]=1;
17 v[0][0]=1;
18 v[1][0]=1;
19
20 for(kint=0;kint<=1;kint++)
21 {
22 for(i=1;i<=N;i++)
23 {
24 fin>>c;
25 v[kint][i]+=c-’0’;
26 }
27 }
28
29 for(i=0;i<=N;i++)
30 {
31 if(v[0][i]==1&&v[1][i]==0&&v[0][i+1]==0)
32 {
CAPITOLUL 19. ONI 2017 19.1. FALEZA - ONI 2017 226

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 }

Listing 19.1.2: faleza Flavius.cpp


1 /// Flavius Boian
2
3 #include <iostream>
4 #include <fstream>
5 #include <cstring>
6
7 using namespace std;
8
9 ifstream f("faleza.in");
10 ofstream g("faleza.out");
11
12 int a[200001],b[200001],i,n,poza,pozb,k;
13
14 int main()
15 {
16 f>>n;
17
18 for(i=1; i<=n; i++) //citesc caracter cu caracter si le pun in vector
19 {
20 f>>a[i];
21 }
22 for(i=1; i<=n; i++)
23 {
24 f>>b[i];
25 }
26
27 i=1;
28 while(a[i]==0 && b[i]==0) //caut primul 1
29 {
30
31 k++;
32 a[i]=b[i]==k;
33 i++;
34 if(i==n+1)
35 break;
36 }
37
38 if(a[i]==1)
39 poza=1; // marchez randul pe care ma deplasez,
40 // cel in care am gasit primul 1
41 else
42 if(b[i]==1)
43 pozb=1;
44
45 while(i<n)
46 {
47 while(a[i]==0 && b[i]==0) // daca ajung in cazul in care pe pozitia
48 // curenta am 0 pe amandoua liniile
49 { // merg pana ajung la primul 1 si cresc
50 // numarul de placute
51
52 k++;
53 a[i]=b[i]==k;
CAPITOLUL 19. ONI 2017 19.1. FALEZA - ONI 2017 227

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 }

Listing 19.1.3: falezaFB.cpp


1 #include <iostream>
2 #include <fstream>
3 #include <cstring>
4
5 using namespace std;
6
7 ifstream f("faleza.in");
8 ofstream g("faleza.out");
9
10 char x;
11 int a[200001],b[200001],i,n,poza,pozb,k;
12
13 int main()
14 {
15 f>>n;
16 for(i=1; i<=n; i++) //citesc caracter cu caracter si le pun in vector
17 {
18 f>>x;
19 a[i]=x-’0’;
20 }
21 for(i=1; i<=n; i++)
22 {
23 f>>x;
24 b[i]=x-’0’;
25 }
26
27 i=1;
28 while(a[i]==0 && b[i]==0) // caut primul 1
29 {
30 k++;
31 a[i]=b[i]==k;
32 i++;
33 if(i==n+1)
34 break;
35 }
36
37 if(a[i]==1)
38 poza=1; // marchez randul pe care ma deplasez,
39 // cel in care am gasit primul 1
40 else if(b[i]==1)
41 pozb=1;
42
43 while(i<n)
44 {
45 while(a[i]==0 && b[i]==0) // daca ajung in cazul in care pe pozitia
46 // curenta am 0 pe amandoua liniile
47 { // merg pana ajung la primul 1 si cresc numarul de placute
48
49 k++;
50 a[i]=b[i]==k;
51 i++;
52 if(i==n+1)
53 break;
54 }
55
CAPITOLUL 19. ONI 2017 19.1. FALEZA - ONI 2017 229

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 }

Listing 19.1.4: falezaMA.cpp


1 #include <fstream>
2 #include <iostream>
3
4 using namespace std;
5
6 ifstream f ("faleza.in");
7 ofstream g("faleza.out");
8
9 using namespace std;
10
11 bool a[200005],b[200005];
12
13 int main()
14 {
15 char x;
16 int n,i,nr=0, p=0,u,ua,ub;
17 f>>n;
18 for (i=1; i<=n; i++)
19 {
20 f>>x;
21 a[i] = x-’0’;
22 }
23 for (i=1; i<=n; i++)
24 {
25 f>>x;
26 b[i] = x-’0’;
27 }
28 // determin p = prima pozitie unde a[i]!=b[i]
29 // determin u=ultima pozitie pentru care a[i]!=b[i]
30 // plec cu nr de la nr de pozitii succesive de la inceputul sirului
31 // in care a[i]=b[i]=0 + nr de pozitii de la finalul sirului
32
33 for (i=1; i<=n; i++)
34 if (a[i]!=b[i])
35 {
36 p=i;
37 break;
38 }
39 else if (a[i]==0) nr++;
40
41 if (p==0)
42 {
43 g<<nr;
44 return 0;
45 }
46 for (i=n; i>=p; i--)
47 if (a[i]!=b[i])
48 {
49 u=i;
50 break;
51 }
52 else if (a[i]==0) nr++;
53 //cout<<nr<<’\n’;
54
55 // daca am o singura poztie in sir in care a[i]!=b[i]
56 if (p==u)
57 {
58 g<<nr+1;
CAPITOLUL 19. ONI 2017 19.1. FALEZA - ONI 2017 231

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 }

Listing 19.1.5: falezaMN.cpp


1 #include <fstream>
2 #define DIM 200010
3
4 using namespace std;
5
6 ifstream fin ("faleza.in");
7 ofstream fout("faleza.out");
8
9 int a[DIM], b[DIM];
10 int n, sol, lena, lenb, lasta, lastb, i;
11 char x;
12
13 int main ()
14 {
15 fin>>n;
16 for (i=1;i<=n;i++)
17 {
18 fin>>x;
19 a[i] = x-’0’;
20 }
21 for (i=1;i<=n;i++)
22 {
23 fin>>x;
24 b[i] = x-’0’;
25 }
26
27 a[n+1] = b[n+1] = 1;
28 lena = lenb = 0;
29 lasta = lastb = 0;
30
31 for (i=1;i<=n+1;i++)
CAPITOLUL 19. ONI 2017 19.1. FALEZA - ONI 2017 232

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 }

Listing 19.1.6: RTfaleza nou.cpp


1 #include <fstream>
2 #include <iostream>
3
4 using namespace std;
5
6 ifstream f("faleza.in");
7 ofstream g("faleza.out");
8
9 int n, a[3][200002],b[3][200002];
CAPITOLUL 19. ONI 2017 19.1. FALEZA - ONI 2017 233

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 }

19.1.3 *Rezolvare detaliată

19.2 peste - ONI 2017


Problema 2 - peste 100 de puncte
Ursul: Bună, cumătră! Da cât peşte ai? Dă-mi şi mie, că tare mi-i poftă!
Vulpea: Ia mai pune-ţi pofta-n cui. Dacă vrei peşte, du-te şi-ţi ı̂nmoaie coada-n baltă şi vei
avea ce să mănânci.
Ursul: Învaţă-mă, te rog, cumătră, că eu nu ştiu cum se prinde peştele.
Vulpea: Alei, cumetre! da’ nu ştii că nevoia te-nvaţă ce nici nu gândeşti? Du-te deseară
la baltă şi bagă-ţi coada-n apă. Stai pe loc, fără să te mişti, până spre ziuă. Între timp, ia
foaia aceasta pe care am scris N numere naturale şi până dimineaţă trebuie să procedezi ı̂n felul
următor:
- elimini exact două cifre alăturate din fiecare număr scris
pe foaie, astfel ı̂ncât, celelalte cifre rămase după eliminare să
formeze, de la stânga la dreapta, cel mai mare număr posibil
(de exemplu, din numărul 7 7196, elimini cifrele 7 şi 1 pentru a
obţine cel mai mare număr posibil 796).
- toate cele N numere obţinute la pasul anterior, le lipeşti
unul după altul, ı̂n ce ordine vrei tu. Uitându-te de la stânga la
dreapta la cifrele numerelor lipite, observi că s-a format un nou
număr X. Ai grijă cum procedezi, căci până dimineaţă, atâta Figura 19.1: peste
peşte se va prinde de coada ta cât vei obţine tu valoarea lui X.
Ajutaţi-l pe urs să prindă cât mai mult peşte posibil.

Cerinţe

Scrieţi un program care citeşte N numere naturale şi determină:


1. Cel mai mare număr de eliminări efectuate cu aceleaşi două cifre alăturate.
2. Cel mai mare număr natural X determinat astfel ı̂ncât ursul să prindă cât mai mult peşte.

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.

Restricţii şi precizări

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.

Timp maxim de executare/test: 0.3 secunde


Memorie: total 8 MB
Dimensiune maximă a sursei: 10 KB

19.2.1 Indicaţii de rezolvare

prof. Cristina Iordaiche, Liceul Teoretic ”GrigoreMoisil” Timişoara

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).

19.2.2 Cod sursă

Listing 19.2.1: Marinel peste string.cpp


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 cerinta, n, nr[110], j;
10 char v[110][40], a[40], b[40], m[40];
11
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 236

12 void trans1(char m[40])


13 {
14 int l = strlen(m), i, x, y, a;
15 char mare[40], scos[3] = "", aux[40] = "";
16 strcpy(mare, "");
17
18 for (i = 0; i < l - 1; i++) //fac toate eliminarile posibile
19 {
20 strncpy(aux, m, i); //pun in aux prima parte
21 *(aux+i) = 0; //o inchei
22 strcat(aux, m + i + 2); //lipesc restul
23 if (strcmp(aux, mare) > 0) //vad daca e mai mare
24 {
25 strcpy(mare, aux); //daca DA, retin
26 strncpy(scos, m + i, 2); //si retin ce am scos
27 }
28 }
29
30 strcpy(v[j], mare); //retin in vector
31 x = scos[0] - ’0’; //formez numarul mai mic
32 y = scos[1] - ’0’;
33
34 if (x < y)
35 a = x * 10 + y;
36 else
37 a = y * 10 + x;
38 nr[a]++; //la numarul mai mic contorizez
39
40 }
41
42 int main()
43 {
44 int mare, i;
45 fin >> cerinta >> n; //cerinta si cate numere
46 fin.get();
47
48 for (j = 1; j <= n; ++j) //citeste numerele si transforma-le
49 {
50 fin.getline(m, 25);
51 trans1(m); //determina eliminarea optima
52 }
53
54 if (cerinta == 1) //cerinta 1
55 {
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 for(i = 1; i <= n; ++i) //afisez rezultatele concatenate
75 fout << v[i];
76 fout << ’\n’;
77 }
78
79 return 0;
80 }

Listing 19.2.2: Marius peste.cpp


1 #include <fstream>
2
3 using namespace std;
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 237

4 long long v[202], f[202];


5 long long n, x, y, c1, c2, cod, p, t, sol1, i, maxim, cf, aux, j;
6 long long r[40], s[40];
7
8 int compare(long long a, long long b)
9 {
10 long long n = 0, m = 0, i, j, aux, A = a, B = b;
11
12 while (a!=0)
13 {
14 r[++n] = a%10;
15 a /= 10;
16 }
17
18 while (b!=0)
19 {
20 r[++n] = b%10;
21 b /= 10;
22 }
23
24 while (B!=0)
25 {
26 s[++m] = B%10;
27 B /= 10;
28 }
29
30 while (A!=0)
31 {
32 s[++m] = A%10;
33 A /= 10;
34 }
35
36
37 i = 1; j = n;
38 while (i < j)
39 {
40 aux = r[i];
41 r[i] = r[j];
42 r[j] = aux;
43 i++;
44 j--;
45 }
46
47 i = 1; j = m;
48 while (i < j)
49 {
50 aux = s[i];
51 s[i] = s[j];
52 s[j] = aux;
53 i++;
54 j--;
55 }
56
57 i = 1;
58 while(r[i] == s[i] && i<=n) 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
77 p = 1;
78 maxim = 0;
79 while (x/p >= 10)
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 238

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 }

Listing 19.2.3: peste.cpp


1 #include<fstream>
2 #include<iostream>
3 #include<algorithm>
4
5 using namespace std;
6
7 ifstream fin("peste.in");
8 ofstream fout("peste.out");
9
10 int maxi;
11 char c;
12 short int v[102][20],f[105],cerinta,n,d[25];
13
14 int maimare(int k1, int k2)// daca linia k1 < linia k2 returneaza 1
15 {
16 short int N1=0,nr1[40],i;
17
18 for(i=1;i<=v[k1][0];i++)// lipesc k1k2 si obtin nr1
19 if(v[k1][i]!=-1)
20 nr1[++N1]=v[k1][i];
21
22 for(i=1;i<=v[k2][0];i++)
23 if(v[k2][i]!=-1)
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 239

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 }

Listing 19.2.4: peste Flavius.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("peste.in");
7 ofstream g("peste.out");
8
9 struct numere
10 {
11 int v[20]; //cifrele
12 int nrc;
13 } nr[102];
14
15 unsigned long long ap[102],nr_max,apmax,k;
16
17 void maxx(unsigned long long x)
18 {
19 unsigned long long a[20],i=0,cif=0,maxim,p,nrx,j,poz;
20 while(x) // scriu cifrele lui x intr-un vector
21 {
22 i++;
23 a[i]=x%10; // o sa fie in ordine inversa in vector
24 x/=10;
25 cif++; // numarul de cifre ale lui x
26 }
27
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 241

28 nr[k].nrc=cif-2; // retin cate cifre va avea numarul dupa ce elimin 2


29 maxim=0; // nr maxim ce se formeaza daca elimin 2 cifre consecutive
30
31 for(i=cif;i>1;i--)
32 {
33 p=1;
34 nrx=0;
35 for(j=1;j<=cif;j++)
36 {
37 if(j!=i && j!=i-1)
38 { // construiesc numerele fara cate 2 cifre consecutive
39 nrx=p*a[j]+nrx;
40 p*=10;
41 }
42 }
43
44 if(nrx>maxim)
45 {
46 maxim=nrx; // retin maximul
47 poz=i; // pozitia de pe care am eliminat cifrele
48 }
49 }
50
51 int t=1;
52 for(i=cif;i>=1;i--)
53 if(i!=poz && i!=poz-1)
54 {
55 nr[k].v[t]=a[i];
56 t++;
57 }
58
59 ap[a[poz]*10+a[poz-1]]++;
60 if(a[poz]*10+a[poz-1]==0)
61 apmax=max(apmax,ap[0]);
62 else
63 apmax=max(ap[a[poz]*10+a[poz-1]]+ap[a[poz-1]*10+a[poz]],apmax);
64 }
65
66 int main()
67 {
68 int p,n,i,j;
69 unsigned long long x;
70 f>>p;
71 f>>n;
72
73 for(i=1;i<=n;i++)
74 {
75 f>>x;
76 k++;
77 maxx(x);
78 }
79
80 if(p==1)
81 g<<apmax;
82 else
83 {
84 for(i=1;i<n;i++)
85 {
86 for(j=i+1;j<=n;j++)
87 {
88 int k1;
89 for(k1=1;k1<=min(nr[i].nrc,nr[j].nrc);k1++)
90 if(nr[i].v[k1]>nr[j].v[k1])// daca gasesc o cifra mai mare
91 {
92 swap(nr[i],nr[j]);
93 break;
94 }
95 else
96 if(nr[i].v[k1] < nr[j].v[k1])
97 break;
98
99 if(k1 > min(nr[i].nrc,nr[j].nrc)) // daca numerele sunt egale
100 // pana se termina cifrele unuia
101 if(nr[i].nrc > nr[j].nrc) // daca cel de pe pozitia i are
102 // mai multe cifre
103 {
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 242

104 if(nr[i].v[k1] > nr[j].v[1]) // daca urmatoarea cifra


105 // din i e mai mica decat prima cifra din j
106 swap(nr[i],nr[j]);
107 }
108 else
109 {
110 if(nr[j].nrc > nr[i].nrc) // daca cel de pe pozitia j
111 // are mai multe cifre
112 if(nr[j].v[k1] <= nr[i].v[1]) // daca urmatoarea
113 // cifra din i e mai mica decat prima cifra din j
114 swap(nr[i],nr[j]);
115 }
116 }
117
118 }
119
120 for(i=n;i>=1;i--)
121 for(j=1;j<=nr[i].nrc;j++)
122 g<<nr[i].v[j];
123 }
124
125 return 0;
126 }

Listing 19.2.5: peste int.cpp


1 #include<fstream>
2 #include<iostream>
3 #include<algorithm>
4
5 using namespace std;
6
7 ifstream fin("peste.in");
8 ofstream fout("peste.out");
9
10 int maxi;
11 char c;
12 short int v[102][20]={0},f[105],cerinta,n,d[25]={0};
13
14 int maimare(int k1, int k2)//daca linia k1< linia k2 returneaza 1
15 {
16 //lipesc k1 k2;
17 short int N1=0,nr1[40],i;
18 for(i=1;i<=v[k1][0];i++)
19 if(v[k1][i]!=-1)
20 nr1[++N1]=v[k1][i];
21
22 for(i=1;i<=v[k2][0];i++)
23 if(v[k2][i]!=-1)
24 nr1[++N1]=v[k2][i];
25
26 short int N2=0,nr2[40];
27
28 //lipesc k2k1
29 for(i=1;i<=v[k2][0];i++)
30 if(v[k2][i]!=-1)
31 nr2[++N2]=v[k2][i];
32
33 for(i=1;i<=v[k1][0];i++)
34 if(v[k1][i]!=-1)
35 nr2[++N2]=v[k1][i];
36
37 //comparam nr1 si nr2 cifra cu cifra de la stanga la dreapta
38 i=1;
39 while(i<=N1)
40 if(nr1[i]<nr2[i])
41 return 1;
42 else
43 if(nr1[i]>nr2[i])
44 return 0;
45 else i++;
46 return 0;
47 }
48
49 void schimb_linia(int k1,int k2)
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 243

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 }

Listing 19.2.6: peste Miana 100.cpp


1 #include <fstream>
2 //#include <iostream>
3 #include <algorithm>
4
5 using namespace std;
6
7 ifstream f ("peste.in");
8 ofstream g ("peste.out");
9
10 long long a[105];
11
12 bool compara (long long x, long long y)
13 {
14 if (x==y) return 1;
15 int xy[40], yx[40],i=0;
16 long long xx=x,yy=y;
17 while (xx)
18 {
19 yx[i++]=xx%10;
20 xx=xx/10;
21 }
22
23 while (yy)
24 {
25 yx[i++]=yy%10;
26 yy=yy/10;
27 }
28
29 i=0; xx=x;yy=y;
30
31 while (yy)
32 {
33 xy[i++]=yy%10;
34 yy=yy/10;
35 }
36
37 while (xx)
38 {
39 xy[i++]=xx%10;
40 xx=xx/10;
41 }
42
43 i--;
44 while (i>0)
45 {
46 if (xy[i]>yx[i]) return 1;
47 if (yx[i]>xy[i]) return 0;
48 i--;
49 }
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 245

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 }

Listing 19.2.7: peste MS.cpp


CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 246

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

77 strcat(b, v[i]); //"ba"


78 if (strcmp(a, b) < 0)
79 {
80 gasit = 1;
81 swap(v[i], v[i+1]);
82 }
83 }
84 }
85
86 for(i = 1; i <= n; ++i)
87 fout << v[i];
88
89 fout << ’\n’;
90 }
91
92 return 0;
93 }

Listing 19.2.8: peste MS ok2.cpp


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 cerinta, n, nr[110], j;
10 char v[110][30], a[30], b[30], m[30];
11
12 void trans1(char m[25])
13 {
14 int l = strlen(m), i, x, y, a;
15 char mare[30], scos[3] = "", aux[30] = "";
16 strcpy(mare, "");
17 for (i = 0; i < l - 1; i++) //fac toate eliminarile posibile
18 {
19 strncpy(aux, m, i); //pun in aux prima parte
20 *(aux+i) = 0; //o inchei
21 strcat(aux, m + i + 2); //lipesc restul
22
23 if (strcmp(aux, mare) > 0) //vad daca e mai mare
24 {
25 strcpy(mare, aux); //daca DA, retin
26 strncpy(scos, m + i, 2); //si retin ce am scos
27 }
28 }
29
30 strcpy(v[j], mare); //retin in vector
31 x = scos[0] - ’0’; //formez numarul mai mic
32 y = scos[1] - ’0’;
33
34 if (x < y)
35 a = x * 10 + y;
36 else
37 a = y * 10 + x;
38
39 nr[a]++; //la numarul mai mic contorizez
40 }
41
42 int main()
43 {
44 int mare, i;
45 fin >> cerinta >> n; //cerinta si cate numere
46 fin.get();
47
48 for (j = 1; j <= n; ++j) //citeste numerele si transforma-le
49 {
50 fin.getline(m, 30);
51 trans1(m); //determina eliminarea optima
52 }
53
54 if (cerinta == 1) //cerinta 1
55 {
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 248

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 }

Listing 19.2.9: pesteMN.cpp


1 #include <fstream>
2
3 using namespace std;
4 long long v[102], f[102];
5 long long n, x, y, c1, c2, cod, p, t, sol1, i, maxim, cf, aux, j;
6 long long r[20], s[20];
7
8 int compare(long long a, long long b)
9 {
10 long long n = 0, m = 0, i, j, aux, A = a, B = b;
11 while (a!=0)
12 {
13 r[++n] = a%10;
14 a /= 10;
15 }
16
17 while (b!=0)
18 {
19 r[++n] = b%10;
20 b /= 10;
21 }
22
23 while (B!=0)
24 {
25 s[++m] = B%10;
26 B /= 10;
27 }
28
29 while (A!=0)
30 {
31 s[++m] = A%10;
32 A /= 10;
33 }
34
35
36 i = 1; j = n;
37 while (i < j)
38 {
39 aux = r[i];
40 r[i] = r[j];
41 r[j] = aux;
42 i++;
43 j--;
44 }
45
46 i = 1; j = m;
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 249

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 }

Listing 19.2.10: RTpeste100.cpp


1 #include <iostream>
2 # include <fstream>
3 using namespace std;
4
5 ifstream f("peste.in");
6 ofstream g("peste.out");
7
8 int n,c, x[19],y[101],maxim=0;
9 long long a[101], z[101],nr,nr1,b;
10
11 void elimina()
12 {
13 int i,t,j,poz,k;
14 for (i=1;i<=n;i++)
15 {
16 b=a[i];
17 t=0;
18 while (b)
19 {
20 t++;
21 x[t]=b%10;
22 b=b/10;
23 }
24
25 poz=0;
26 for(j=t;j>=3;j--)
27 if (x[j]<x[j-2])
28 {
29 poz=j;
30 break;
31 }
32
33 if (poz==0) poz=2;
34
35 nr=0;
36 for(k=t;k>=1;k--)
37 if (k!=poz && k!=poz-1)
38 nr=nr*10+x[k];
39
40 if (x[poz]>x[poz-1])
41 nr1=x[poz-1]*10+x[poz];
42 else
43 nr1=x[poz]*10+x[poz-1];
44
45 y[nr1]++;
46 maxim=max(maxim,y[nr1]);
47 z[i]=nr;
48 }
49 }
50
51 int maimare(long long x, long long y)
52 {
53 int k1=0,k2=0,k3,k4,a[20],b[20],c[40],d[40],i,j;
54 while (x)
55 {
56 k1++;
57 a[k1]=x%10;
58 x=x/10;
59 }
60
61 while (y)
62 {
63 k2++;
CAPITOLUL 19. ONI 2017 19.2. PESTE - ONI 2017 251

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 }

19.2.3 *Rezolvare detaliată

19.3 soricel - ONI 2017


Problema 3 - soricel 100 de puncte
Şoricelul Remy doreşte să depoziteze cubuleţele de caşcaval pe care le-a adunat. El a construit
un depozit pe o suprafaţă dreptunghiulară şi l-a compartimentat ı̂n N ˜ M camere identice. În
fiecare cameră şoricelul a depozitat o cantitate de cubuleţe de caşcaval (ca ı̂n Figura A) şi a stabilit
că va mânca ı̂n fiecare zi câte un cubuleţ de caşcaval din fiecare cameră ı̂n care există caşcaval.
Planul său este stricat de John, şoricelul leneş din casa vecină, căruia nu-i place să-şi strângă
singur caşcaval, aşa că s-a hotărât să fure din depozitul lui Remy. Pentru că John este pasionat
de matematică s-a hotărât ca ı̂n fiecare seară, după ce vecinul său a terminat de mâncat, să se
plimbe prin depozit şi să fure tot caşcavalul din camerele ı̂n care găseşte un număr pătrat perfect
de cubuleţe de caşcaval.
John intră ı̂n depozit prin camera din colţul stânga sus, de coordonate (1,1), parcurge prima
linie de la prima la ultima coloană, apoi a doua linie de la ultima coloană, până la prima şi aşa
mai departe, până când termină de vizitat toate camerele (ca ı̂n Figura B).

Figura 19.2: soricel

Cerinţe

Scrieţi un program care să determine:


1. Numărul de zile ı̂n care se va goli depozitul lui Remy şi câte camere va goli John ı̂n ziua K.
2. Numărul maxim de camere consecutive golite de acesta ı̂ntr-o zi şi ziua ı̂n care se va ı̂ntâmpla
acest lucru.

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.

Restricţii şi precizări

a 1 & N & 200


a 1 & M & 200
a 0 & Cij & 10
8

a 1 & K & numărul de zile până când depozitul va fi gol;


a există cel puţin o cameră care conţine mai mult de un cubuleţ de caşcaval;
9
a numărul total de bucăţi de caşcaval furate din camere consecutive ı̂ntr-o zi nu va depăşi 10 ;
a ziua ı̂n care ı̂ncepe să mănânce Remy este considerată ziua 1;
a dacă există două sau mai multe zile ı̂n care John goleşte un număr egal de camere consecutive,
se va afişa ziua ı̂n care a mâncat cele mai multe cubuleţe de caşcaval, iar dacă şi aceste cantităţi
sunt egale, se va afişa numărul zilei cu valoarea cea mai mare;
a considerăm că liniile se numerotează de sus ı̂n jos ı̂ncepând cu 1, iar coloanele de la stânga
la dreapta ı̂ncepând cu 1;
a pentru rezolvarea corectă a cerinţei 1 se acordă 40 de puncte, iar dacă pentru fiecare test se
afişează corect doar prima valoare, se acordă jumătate din punctajul aferent testului respectiv;
a pentru prima cerinţă vor exista şi teste ı̂n valoare de 20 de puncte, pentru care 0 & Ci,j &
1000, iar N, M & 30;
a pentru rezolvarea corectă a cerinţei 2 se acordă 60 de puncte, iar dacă pentru fiecare test se
afişează corect doar prima valoare, se acordă două treimi din punctajul aferent testului respectiv.

Exemple

soricel.in soricel.out Explicaţii


1 19 5 La finalul primei zile, depozitul va arăta astfel:
541 0 5 0 0
2 6 5 10 24 15 0 0
25 16 0 5 99 0 66 2
100 17 67 3 19 103 7 12
20 104 8 13 52 12 54 46
53 13 55 47 deoarece Remy a mâncat câte un cubuleţ din fiecare cameră şi
apoi John a golit camerele ı̂n care numărul de cubuleţe rămase
era pătrat perfect.
Urmând aceleaşi etape, ı̂n fiecare zi Remy va putea să mănânce
timp de 19 zile din depozit (după 19 zile toate camerele sunt
goale deoarece toate numerele au ajuns să fie pătrate perfecte
sau valori nule).
În ziua 1 John va fura caşcavalul din 5 camere, cele care au
coordonatele: (1,1), (1,3), (1,4), (2,4), (3,2).
2 64 În ziua a 4-a John va goli 6 camere, cele cu coordonatele: (4,4),
541 (4,3), (4,2), (4,1), (5,1) şi (5,2). Aceasta este cea mai lungă
2 6 5 10 secvenţă de camere consecutive golite ı̂n aceeaşi zi.
25 16 0 5
100 17 67 3
20 104 8 13
53 13 55 47

Timp maxim de executare/test: 0.3 secunde


Memorie: total 8 MB
Dimensiune maximă a sursei: 10 KB
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 254

19.3.1 Indicaţii de rezolvare

prof. Flavius Boian, Colegiul Naţional ”Spiru Haret”, Târgu Jiu

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ă.

19.3.2 Cod sursă

Listing 19.3.1: RTsoricel100.cpp


1 #include <fstream>
2 #include <iostream>
3 #include <cmath>
4
5 using namespace std;
6
7 ifstream f("soricel.in");
8 ofstream g("soricel.out");
9
10
11 int a[503][503], b[503][503], maxim=0, nrmaxim,val,li,ci,max1=0,nr;
12 long long s;
13 int c,n, m, k;
14
15 int cauta_patrat(int x)
16 {
17 int y;
18 y=(int)sqrt(x);
19 return y*y;
20 }
21
22 void citeste()
23 {
24 int i,j,x,y;
25 f>>c>>m>>n>>k;
26
27 for (i=1;i<=m;i++)
28 for(j=1;j<=n;j++)
29 {
30 f>>a[i][j];
31 s=s+a[i][j];
32 max1=max(max1,a[i][j]);
33 }
34
35 for(i=1;i<=m;i++)
36 for(j=1;j<=n;j++)
37 {
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 255

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 }

Listing 19.3.2: soricel flavius.cpp


1 #include <iostream>
2 #include <fstream>
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 257

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 }

Listing 19.3.3: soricel Miana.cpp


1 #include<fstream>
2 #include<iostream>
3 #include <cmath>
4
5 using namespace std;
6
7 ifstream f ("soricel.in");
8 ofstream g ("soricel.out");
9
10 int a[205][205], v[250005];
11
12 int nrzile (int x) //in cate zile se mananca x
13 {
14 if (x<2) return x;
15 int rx=sqrt(x);
16 int dif=x-rx*rx;
17 if (dif!=0) return dif;
18 return x-(rx-1)*(rx-1);
19 }
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 259

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 }

Listing 19.3.4: soricelFB2.cpp


1 #include <iostream> // 100 p Flavius Boian
2 #include <fstream>
3 #include <cmath>
4 using namespace std;
5
6 ifstream f("soricel.in");
7 ofstream g("soricel.out");
8
9 int a[202][202],b[202][202];
10 int p,n,m,k,x,maxx,nrk,i,j;
11
12 int main()
13 {
14 f>>p; // citesc numarul cerintei
15 f>>n>>m>>k; // citesc datele de intrare
16 maxx=1; // consider ca in camara am cascaval doar in prima zi
17 for (i=1; i<=n; i++)
18 for(j=1; j<=m; j++)
19 {
20 f>>a[i][j];
21 if(a[i][j]!=0) // daca elementul este deja 0 nu mai lucrez cu el
22 {
23 if(a[i][j]==1) // daca elementul este initial 1, dupa ce
24 // primul soarece mananca in camara va ramane 0
25 b[i][j]=0;
26 else
27 if(sqrt(a[i][j])==int(sqrt(a[i][j]))) // daca elementul
28 // e deja patrat perfect
29 // retin diferenta pana la cel mai mare patrat perfect
30 // mai mic decat el
31 b[i][j]=a[i][j]-(sqrt(a[i][j])-1)*(sqrt(a[i][j])-1);
32 else ///altfel
33 //retin diferenta pana la cel mai mare patrat perfect
34 // mai mic decat el
35 b[i][j]=a[i][j]- (int(sqrt(a[i][j])))*(int(sqrt(a[i][j])));
36
37 maxx=max(maxx,b[i][j]); // retin maximul dintre diferente
38 if(b[i][j]==k) // daca diferenta e egala cu k <=> camera va fi
39 // golita in ziua k
40 nrk++;
41 }
42 }
43
44 if(p==1) // daca cerinta e 1
45 g<<maxx<<" "<<nrk; // afisez diferenta maxima care reprezinta numarul
46 // de zile in care mai exista ceva in camara
47 // afisez numarul de camere care vor fi golite in ziua k
48 else // daca cerinta e 2
49 {
50 int row,elem,lung,lung_max,sum,sum_max,zi;
51
52 zi=0;
53 elem=b[1][1];
54 lung=0;
55 lung_max=0;
56 sum=a[1][1]-b[1][1];
57 sum_max=0;
58
59 i=1;
60 while(i<=n) //parcurg matricea serpuit
61 {
62 if(i%2==1)
63 for(j=1; j<=m; j++) // parcurg liniile impare
64 {
65
66 if(b[i][j]==elem) // daca elementul pe care sunt este egal cu
67 // elementul din secventa curenta
68 {
69 lung++; // creste lungimea secventei
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 261

70 sum+=(a[i][j]-b[i][j]); // calculam si numarul de cuburi


71 // de cascaval care vor fi furate
72 }
73 else // daca elementul pe care sunt nu este egal cu elementul
74 { // din secventa curenta
75 if(elem!=0) // daca secventa e formata din 0
76 // nu ma intereseaza
77 if(lung > lung_max) // daca secventa curenta este mai
78 { // lunga decat lungimea maxima
79 lung_max=lung; // actualizam lungimea
80 sum_max=sum; // actualizam suma
81 zi=elem; // retinem ziua
82 }
83 else
84 // daca secventa curenta e de lungime maxima,
85 // dar are suma mai mare
86 if(lung == lung_max && sum>sum_max)
87 {
88 sum_max=sum; // actualizam suma
89 zi=elem; // retinem ziua
90 }
91 elem=b[i][j]; // elementul din noua secventa va fi cel
92 // gasit ca fiind diferit de secventa anterioara
93 lung=1; // lungime secventei noi va fi 1 initial
94 sum=a[i][j]-b[i][j];
95
96 }
97 }
98
99 if(i%2==0)
100 for(j=m; j>=1; j--) // parcurg liniile pare
101 {
102 if(b[i][j]==elem) // daca elementul pe care sunt este egal cu
103 // elementul din secventa curenta
104 {
105 lung++; // creste lungimea secventei
106 sum+=(a[i][j]-b[i][j]); // calculam si numarul de cuburi
107 // de cascaval care vor fi furate
108 }
109 else // daca elementul pe care sunt nu este egal cu elementul
110 // din secventa curenta
111 {
112 if(elem!=0) // daca secventa e formata din 0
113 // nu ma intereseaza
114 if(lung > lung_max) // daca secventa curenta este mai
115 // lunga decat lungimea maxima
116 {
117 lung_max=lung; // actualizam lungimea
118 sum_max=sum; // actualizam suma
119 zi=elem; // retinem ziua
120 }
121 else
122 // daca secventa curenta e de lungime maxima,
123 // dar are suma mai mare
124 if(lung == lung_max && sum>sum_max)
125 {
126 sum_max=sum; // actualizam suma
127 zi=elem; // retinem ziua
128 }
129 elem=b[i][j]; // elementul din noua secventa va fi cel
130 // gasit ca fiind diferit de secventa anterioara
131 lung=1; // lungime secventei noi va fi 1 initial
132 sum=a[i][j]-b[i][j];
133 }
134 }
135
136 i++;
137 }
138
139 if(elem!=0)
140 if(lung > lung_max) // mai facem o verificare la final pentru cazul
141 // in care secventa cea mai lunga se termina pe
142 // ultimul element din parcurgere
143 {
144 lung_max=lung;
145 sum_max=sum;
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 262

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 }

Listing 19.3.5: soricelMN.cpp


1 #include <fstream>
2 #include <iostream>
3
4 #define DIM 503
5
6 using namespace std;
7
8 int a[DIM][DIM], b[DIM][DIM], v[DIM*DIM], w[DIM*DIM];
9 int p[100010];
10 int n, m, i, j, r, st, dr, mid, maxim, max1, sol1, maxim2,
11 numar2, zi, t, k, d, c, L, suma;
12
13 void af(int a[DIM][DIM])
14 {
15 for (int i=1;i<=n;i++)
16 {
17 for (int j=1;j<=m;j++)
18 cout<<a[i][j]<<" ";
19
20 cout<<"\n";
21 }
22 }
23
24 int main ()
25 {
26 ifstream fin ("soricel.in");
27 ofstream fout("soricel.out");
28
29 fin>>t>>n>>m>>k;
30
31 for (i=1;i<=n;i++)
32 for (j=1;j<=m;j++)
33 {
34 fin>>a[i][j];
35
36 if (a[i][j] > maxim)
37 maxim = a[i][j];
38
39 b[i][j] = a[i][j];
40 }
41
42 for (r=1;r*r<=maxim;r++)
43 {
44 p[r] = r*r;
45 }
46
47 r--;
48 for (i=1;i<=n;i++)
49 for (j=1;j<=m;j++)
50 {
51 //if (a[i][j])
52 if (a[i][j] <= 1)
53 {
54 a[i][j] = -1;
55 continue;
56 }
CAPITOLUL 19. ONI 2017 19.3. SORICEL - ONI 2017 263

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 }

19.3.3 *Rezolvare detaliată


Capitolul 20

ONI 2016

20.1 cod - ONI 2016


Problema 1 - cod 100 de puncte
Ionel şi Georgel sunt colegi de clasă şi doresc să facă schimb de fişiere prin email. Fiecare
dintre ei ı̂şi arhivează fişierele cu câte o parolă. Fiecare copil ı̂şi construieşte parola pe baza unui
şir format din N numere naturale.
Numerele din şir care se folosesc efectiv pentru construirea parolelor sunt doar cele divizibile
cu numerele din mulţimea {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}. Copiii numără câte din
valorile din şir sunt divizibile cu fiecare din aceste numere.
Parola folosită de Ionel se obţine prin ı̂nsumarea numărului de valori din şir care sunt divizibile
cu numerele din mulţimea {2, 3, 4, 5, 6, 7, 8, 9}. Parola folosită de Georgel se obţine prin ı̂nsumarea
numărului de valori din şir care sunt divizibile cu numerele din mulţimea {10, 11, 12, 13, 14, 15}.

Cerinţe

Scrieţi un program care citeşte şirul celor N numere şi determină:


1) câte numere din şir nu se vor folosi ı̂n construirea parolelor celor doi copii;
2) parola construită de Ionel;
3) parola construită de Georgel.

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.

Restricţii şi precizări

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

Timp maxim de executare/test: 0.8 secunde


Memorie: total 4 MB
Dimensiune maximă a sursei: 15 KB

20.1.1 Indicaţii de rezolvare

??? = ???

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

20.1.2 Cod sursă

Listing 20.1.1: cod cpp.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 long cate=0;
6 long N,M,i,j;
7 char c;
8 int P,n,nr;
9 long v[300],gr_i[20],gr_g[20],g[20];
10
11 int selectie(long v[300], long m, long g[16])
12 {
13 int i,j;
14 long s=0;
15 for(i=0;i<=19;i++) g[i]=0;
16
17 //grupa 2,3,4,5,6,7,8,9,10,11,12,13,14,15
18 v[0]=0;
19 //2
20 if(v[m]%2==0) g[2]++;
21
22 //3
23 s=0;
24 for(i=1;i<=m;i++) s+=v[i];
25 if(s%3==0)g[3]++;
26
27 //4
28 if((v[m-1]*10+v[m])%4==0)g[4]++;
29
30 //5
31 if(v[m]%5==0)g[5]++;
32
33 //6
34 if(g[2]&&g[3]) g[6]++;
35
36 //7
37 int s1=0,s2=0,s3=0;
38 for(i=m;i>5;i=i-6)
39 {
40 s1=v[i-2]*100+v[i-1]*10+v[i];
41 s2=v[i-5]*100+v[i-4]*10+v[i-3];
42 s3+=s1-s2;
43 }
44 if(i==5)
45 {
46 s1=v[i-2]*100+v[i-1]*10+v[i];
47 s2=v[i-4]*10+v[i-3];
48 s3+=s1-s2;
49 }
50 if(i==4)
51 {
52 s1=v[i-2]*100+v[i-1]*10+v[i];
53 s2=v[i-3];
54 s3+=s1-s2;
55 }
56 if(i==3) s3+=v[i-2]*100+v[i-1]*10+v[i];
57 if(i==2) s3+=v[i-1]*10+v[i];
58 if(i==1) s3+=v[i];
59 if(s3<0) s3=-s3;
60 if(s3%7==0)g[7]++;
61
62 //8
63 if(m>=3&&(v[m-2]*100+v[m-1]*10+v[m])%8==0)g[8]++;
64 if(m==2&&(v[m-1]*10+v[m])%8==0)g[8]++;
65 if(m==1&&(v[m])%8==0)g[8]++;
66
67 //9
68 if(s%9==0)g[9]++;
69
70 //10
CAPITOLUL 20. ONI 2016 20.1. COD - ONI 2016 268

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 }

20.1.3 *Rezolvare detaliată


CAPITOLUL 20. ONI 2016 20.2. PERM - ONI 2016 269

20.2 perm - ONI 2016


Problema 2 - perm 100 de puncte
Considerând K un număr natural, vom numi permutare de mărime K o aranjare ı̂ntr-o ordine
oarecare a elementelor mulţimii r1, 2, ..., K x. Ana găseşte scris pe o foaie de hârtie, un şir de
numere naturale v v1 , v2 , v3 , ..., vN .
Plecând de la acest şir, Ana numeşte secvenţă a lui v, un subşir de numere care apar pe poziţii
consecutive ı̂n şirul iniţial. De exemplu, şirul 5 7 8 9 1 6 conţine secvenţa 8 9 1, secvenţa 7 8 9 1
6, dar nu conţine secvenţa 8 9 6.
Anei ı̂i vine ideea să ı̂ncerce să verifice dacă şirul de numere poate fi ı̂mpărţit ı̂n secvenţe care
reprezintă permutări de diferite mărimi. De exemplu, dacă Ana găseşte şirul v 2, 1, 4, 1, 3, 2,
atunci ea ı̂l poate ı̂mpărţi ı̂n două secvenţe de permutări astfel: secvenţa v[1], v[2] respectiv
secvenţa v[3], v[4], v[5], v[6].
Dacă Ana găseşte şirul v 1, 2, 2, 3 atunci nu va putea obţine o ı̂mpărţire ı̂n secvenţe de
permutări.

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.

Restricţii şi precizări

a 1 & N & 100000


a 1 & vi & 20000
a Pentru două şiruri de N numere a1 , a2 , ..., aN şi b1 , b2 , ..., bN spunem ca şirul a este mai mic
lexicografic decât şirul b, dacă există un indice j, cu 1 & j $ N , astfel ı̂ncât a1 b1 , a2 b2 , ...,
aj bj şi aj 1 $ bj 1

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

Timp maxim de executare/test: 0.3 secunde


Memorie: total 4 MB
Dimensiune maximă a sursei: 15 KB

20.2.1 Indicaţii de rezolvare

??? - ???
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.

20.2.2 Cod sursă

Listing 20.2.1: perm cpp.cpp


1 #include <cstdio>
2
3 using namespace std;
4
5 int a[100005], b[100005], c[100005],d[100005],i,n,j,max1, max2,p,nr, poz, k;
6 long long s;
7
8 int main()
9 {
10 freopen("perm.in", "r", stdin);
11 freopen("perm.out", "w", stdout);
12
13 scanf("%d\n",&n);
14 max1=0;
15
16 for (i=1;i<=n;i++)
17 {
18 scanf("%d",&a[i]);
19 b[a[i]]++;
20 if (a[i]>max1) max1=a[i];
21 }
22
23 for (i=1; i<max1;i++)
24 {
25 if (b[i]<b[i+1]) {printf("NU\n"); return 0;}
26 }
27
28 max2=0;
29 nr=0;
30 s=0;
31 for (i=1;i<=n;i++)
32 {
33 c[a[i]]++;
34 if (c[a[i]]==2)
35 {
36 if (s*2 == poz*(poz+1))
37 {
38 for (j=1;j<=poz;j++)
39 c[j]--;
40 poz=1;
41 nr++;
42 d[nr]=i-1;
43 s=a[i];
44 }
45 else
46 {
47 c[a[i]]--;
48 for (j=i-1;j>=1;j--)
49 {
50 s=s-a[j];
51 poz--;
52 if (s*2 == poz*(poz+1))
53 {
54 for (j=1;j<=poz;j++)
55 c[j]--;
56 s=a[poz+1];
57 i=poz+1;
58 nr++;
CAPITOLUL 20. ONI 2016 20.3. ROBOTEL - ONI 2016 271

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 }

20.2.3 *Rezolvare detaliată

20.3 robotel - ONI 2016


Problema 3 - robotel 100 de puncte
Tudor a primit un joc educaţional numit ”Roboţel” cu ajutorul căruia va ı̂nvăţa punctele
cardinale Nord, Est, Sud, Vest. Jocul constă dintr-un roboţel care se deplasează pe o tablă de
forma unei matrici pătratice, ı̂mpărţită ı̂n R linii şi R coloane. Fiecare căsuţă, aflată la intersecţia
dintre o linie şi o coloană, este fie căsuţă ”liberă”, fie căsuţă ”semnalizator”, caz ı̂n care este
etichetată cu una din literele N, E, S, V, reprezentând 4 sensuri posibile de deplasare. Când
roboţelul ajunge ı̂ntr-o ”căsuţă semnalizator”, el ı̂şi schimbă sensul de deplasare astfel:
- Dacă căsuţa este etichetată cu N atunci roboţelul se va deplasa ı̂n
continuare de jos ı̂n sus;
- Dacă căsuţa este etichetată cu E atunci roboţelul se va deplasa ı̂n
continuare de la stânga la dreapta;
- Dacă căsuţa este etichetată cu S atunci roboţelul se va deplasa ı̂n
continuare de sus ı̂n jos;
- Dacă căsuţa este etichetată cu V atunci roboţelul se va deplasa ı̂n
continuare de la dreapta la stânga.
Două căsuţe semnalizator formează o pereche ”blocantă” dacă:
- Se află pe aceeaşi linie şi conţin literele E şi V, căsuţa cu E are coloana Figura 20.1: robo-
mai mică decât a celei etichetate cu V şi ı̂ntre ele, pe aceeaşi linie nu existătel1 alte căsuţe semnal-
izatoare.
- Se află pe aceeaşi coloană şi conţin literele S şi N, căsuţa cu S are linia mai mică decât a celei
etichetate cu N şi ı̂ntre ele, pe aceeaşi coloană nu există alte căsuţe semnalizatoare.
În figura 1, de exemplu, sunt 2 perechi blocante: Perechea (1,2) (5.2) şi perechea (2,3) (2,5).
CAPITOLUL 20. ONI 2016 20.3. ROBOTEL - ONI 2016 272

Roboţelul porneşte din căsuţa (1,1), aflată pe prima linie


şi prima coloană şi dacă aceasta este liberă, se deplasează, ı̂n
cadrul primei linii, de la stânga la dreapta. În cazul ı̂n care
căsuţa de pornire (1,1) este semnalizator, atunci roboţelul se
va deplasa pe direcţia indicată de litera cu care este etichetată.
Considerând că roboţelul se deplasează pe tablă, el se opreşte
doar ı̂n următoarele situaţii:
- Roboţelul intră ı̂ntr-o căsuţă liberă aflată pe prima sau Figura 20.2: robotel2
ultima linie, respectiv prima sau ultima coloană, caz ı̂n care
dacă s-ar menţine sensul deplasării actuale roboţelul ar părăsi tabla;
- Roboţelul intră ı̂ntr-o ”căsuţă semnalizator” a unei perechi blocantă şi se va opri ı̂n cealaltă
căsuţă a perechii.
De exemplu, ı̂n Figura 2, roboţelul ajunge ı̂n căsuţa liberă (3,5) unde se opreşte. În Figura 3,
roboţelul se va opri ı̂n căsuţa (4,1) deoarece dacă ar schimba sensul spre Est, ar reveni ı̂n ultima
căsuţă semnalizator vizitată, (4,3).
Roboţelul ı̂naintează o căsuţă ı̂ntr-un pas, ı̂n sensul de deplasare.

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.

Restricţii şi precizări

a 2 & R & 200 şi 1 & K & R ˜ R


a Pentru rezolvarea corectă a fiecărei cerinţe se obţin câte 50 de puncte
a O căsuţă semnalizator conţine o singură literă
a Pentru cerinţa 2 se garantează că ı̂n toate testele deplasarea roboţelului se opreşte!

Exemple

robotel.in robotel.out Explicaţii


154 0 Nu există perechi blocante pe tablă care ar putea opri roboţelul.
13S
31E
51N
53V
CAPITOLUL 20. ONI 2016 20.3. ROBOTEL - ONI 2016 273

1 5 3 4143 Perechea blocantă este alcătuită din căsuţele (4,1) cu eticheta E


1 3 S şi (4,3) cu eticheta V. Dacă roboţelul ajunge ı̂n una dintre aceste
4 1 E căsuţe, atunci acesta se va opri ı̂n cealaltă căsuţă.
4 3 V
1 2555 Căsuţa semnalizator de pe linia 2, coloana 5 are eticheta S, iar
5 5 4143 căsuţa semnalizator de pe linia 5, coloana 5 are eticheta N. Dacă
1 3 S roboţelul ajunge ı̂n una dintre aceste căsuţe, atunci acesta se va
2 5 S opri ı̂n cealaltă căsuţă.
4 1 E Acelaşi lucru se ı̂ntâmplă pentru căsuţa cu litera E de pe linia 4,
4 3 V coloana 1 şi căsuţa cu litera V de pe linia 4, coloana 3.
5 5 N
1 1252 Prima pereche blocantă este (1,2) (5.2).
5 5 2325 A doua pereche blocantă este (2,3) (2,5). Perechea (2,1) (2,5) nu
1 2 S este validă deoarece conţine un alt semnalizator ı̂ntre ele (vezi figura
2 1 E 1).
2 3 E
2 5 V
5 2 N
2 0232 Numărul de paşi efectuaţi pe sensul:
5 3 Nord: 0 paşi
1 3S Est: 2 paşi ı̂n căsuţele (1,2), (1,3)
4 1E Sud: 3 paşi ı̂n căsuţele (2,3), (3,3) (4,3)
4 3V Vest: 2 paşi ı̂n căsuţele (4,2), (4,1)
2 2642 Numărul de paşi efectuaţi pe sensul:
5 4 Nord: 2 paşi ı̂n căsuţele (4,1), (3,1)
1 3 S Est: 6 paşi ı̂n căsuţele (1,2), (1,3), (3,2), (3,3), (3,4), (3,5)
3 1 E Sud: 4 paşi ı̂n căsuţele (2,3), (3,3) (4,3), (5,3)
5 1 N Vest: 2 paşi ı̂n căsuţele (5,2), (5,1)
5 3 V

Timp maxim de executare/test: 0.3 secunde


Memorie: total 2 MB
Dimensiune maximă a sursei: 15 KB

20.3.1 Indicaţii de rezolvare

??? - ???

a) Perechile blocante sunt de forma E  V , pe aceeaşi linie sau S  N pe aceeaşi coloană.


Pentru fiecare valoare E din matrice se caută pe aceeaşi linie, la stânga, prima casuţă semnal-
izator. Dacă are eticheta V , afişăm perechea găsită, altfel căutarea se opreşte.
Analog, pentru o căsuţă cu eticheta S, căutăm ı̂n jos, pe aceeaşi coloană prima căsuţă sem-
nalizator, dacă are eticheta N afişăm perechea găsită, altfel căutarea se opreşte.
b) Considerăm o variabilă x, cu valori posibile 0, pentru sensul Nord, 1 pentru sensul Est, 2
sensul Sud, 3 pentru sensul Vest.
Dacă ı̂n căsuţa (1,1) avem etichetele N sau V roboţelul se opreşte.
Deplasăm repetat roboţelul din linie 1 şi coloana 1 pe directia x 1, pentru ı̂nceput.
Pentru sensul ı̂n care se miscă roboţelul ı̂n mod curent, actualizăm noua căsuţă ı̂n care intră
şi incrementăm cu un vector de frecvenţă numărul de căsuţe parcurse pe directia x.
În funcţie de valoarea curentă din căsuţa (N , E, S, V ) schimbăm direcţia de deplasare.
Mişcarea roboţelului se termină ı̂n următoarele cazuri:
- a intrat ı̂ntr-o căsuţă fără literă din prima sau ultima linie, prima sau ultima coloană;
- a intrat ı̂ntr-o casuţă care are fie eticheta E şi x 3, fie eticheta S şi x 0.

20.3.2 Cod sursă


CAPITOLUL 20. ONI 2016 20.3. ROBOTEL - ONI 2016 274

Listing 20.3.1: robotel cpp.cpp


1 //prof. prop. Rotar Mircea
2 #include <fstream>
3
4 using namespace std;
5
6 char ch,a[202][202];
7 /**E V S N**/
8 int dx[]={0,0,1,-1},
9 dy[]={1,-1,0,0};
10
11 int P,n,K,lin,col,i,j,k,ok=0,depl[4],dir;
12
13 ifstream f("robotel.in");
14 ofstream g("robotel.out");
15
16 int main()
17 {
18 f>>P>>n>>K;
19 for(i=1;i<=K;i++)
20 {
21 f>>lin>>col>>ch;
22 if( ch == ’E’) a[lin][col] = 1;
23 if( ch == ’V’) a[lin][col] = 2;
24 if( ch == ’S’) a[lin][col] = 3;
25 if( ch == ’N’) a[lin][col] = 4;
26 }
27
28 if(P==1)
29 {
30 for(i=1;i<=n;i++)
31 for(j=1;j<=n;j++)
32 {
33 if(a[i][j]==1)//caut E-V
34 {
35 for(k=j+1;k<=n && a[i][k]==0;k++);
36 if(a[i][k]==2)
37 {
38 g<<i<<" "<<j<<" "<<i<<" "<<k<<’\n’;
39 ok++;
40 }
41 j=k-1; //sar peste spatii pentru urmatoarea cautare
42 }
43
44 if(a[i][j]==3)//caut S-N
45 {
46 for(k=i+1;k<=n && a[k][j]==0;k++);
47 if(a[k][j]==4)
48 {
49 g<<i<<" "<<j<<" "<<k<<" "<<j<<’\n’;
50 ok++;
51 }
52 }
53 }
54
55 if(ok==0) g<<ok<<’\n’;
56 return 0;
57 }
58 else
59 {
60 lin=1;col=1;
61 dir=0; //directia de deplasare E<-0, V<-1, S<-2, N<-3
62 ok=1;
63 if(a[1][1]!=0)
64 {
65 dir=a[1][1]-1;
66 }
67 if(dir==3 || dir==1) ok=0;
68
69 while(ok)
70 {
71 lin+=dx[dir];col+=dy[dir];
72 if(lin==0||lin==n+1||col==n+1||col==0){ok=0;}
73 if (ok) depl[dir]++;
74 if(a[lin][col]!=0){
CAPITOLUL 20. ONI 2016 20.3. ROBOTEL - ONI 2016 275

75 if ( (a[lin][col] + dir+1)%4==3 ) ok = 0; //N-S,E-V


76 dir=a[lin][col]-1;
77 }
78 }
79 g<<depl[3]<<" "<<depl[0]<<" "<<depl[2]<<" "<<depl[1]<<’\n’;
80 }
81 return 0;
82 }

20.3.3 *Rezolvare detaliată


Capitolul 21

ONI 2015

21.1 echer - ONI 2015


Problema 1 - echer 100 de puncte
Oli are un echer de forma unui triunghi dreptunghic, cu catetele de lungimi
L1 şi L2 unităţi, şi o foaie de caiet de matematică cu M rânduri şi N coloane
de pătrăţele având latura de o unitate.
Oli a poziţionat echerul ı̂n colţul din stânga sus al foii de hârtie, ca ı̂n
imaginea alăturată şi vrea să ı̂l mute astfel ı̂ncât să atingă colţul din dreapta Figura 21.1:
jos al foii de hârtie cu oricare din colţurile echerului, utilizând doar mutări de echer
forma:

Figura 21.2: echer

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

Fişierul de ieşire echer.out va conţine pe prima linie un număr natural K reprezentând


numărul minim de mutări dacă cerinţa a fost 1, respectiv K numere naturale separate prin câte
un spaţiu reprezentând mutările efectuate pentru a deplasa echerul din colţul din stânga sus al
foii de matematică până când un colţ al echerului atinge colţul din dreapta jos al foii, dacă cerinţa
a fost 2.
Restricţii şi precizări
a 1 & L1, L2 & 1000.
a 1 & M, N & 1000000.
a Se garantează că există soluţie pentru orice set de date de intrare.
a Pentru rezolvarea corectă a cerinţei 1 se obţine 30% din punctaj.
a Pentru rezolvarea corectă a cerinţei 2 se obţine 70% din punctaj.

Exemple

echer.in echer.out Explicaţii


12389 8 Sunt necesare 8 mutări,
ca ı̂n imaginea alăturată.

Figura 21.3:
echer
22389 12312314 Mutările sunt cele ilustrate ı̂n imaginea de mai
sus.
Tabelul 21.1: echer

Timp maxim de executare/test: 0.2 secunde


Memorie: total 1 MB din care pentru stivă 1 MB
Dimensiune maximă a sursei: 5 KB

21.1.1 Indicaţii de rezolvare

prof. Florentina Ungureanu, Colegiul Naţional de Informatică Piatra-Neamţ


Notăm:
X M ©L1
Y N ©L2
MI M IN X, Y 
MA M AX X, Y 
Determinăm:
~
„3 ˜ X  2, dacă X Y
„
„
„
„
„ ˜ M I  1,
3 dacă MA  MI 1
K ‚
„
„
„
„
3 ˜ M I  2  2 ˜ M A  M I , dacă MA  MI % 1 şi M A  M I %2 1
„
„3 ˜ M I  3  2 ˜ M A  M I ,
€ dacă MA  MI % 1 şi M A  M I %2 j 1
Afişăm K dacă cerinţa este 1.
Pentru cerinţa 2:
Prima mutare este ı̂ntotdeauna 1.
Afişăm de M I  1 ori mutările 2 3 1 (se mută echerul până se atinge marginea din dreapta sau
marginea de jos a foii, apoi:
- Dacă (X  Y 1) afişăm 4, iar dacă (Y  X 1) afişăm 2.
- Dacă (X  Y % 1) afişăm, cât timp nu se depăşeşte numărul total de mutări K, secvenţa de
mutări 4 6 3 1, iar dacă mai ramâne de afişat o mutare, aceasta este 4.
- Daca (Y  X % 1) afişăm cât timp nu se depăşeşte numărul total de mutări K secvenţa de
mutări 2 7 5 1, iar dacă mai ramâne de afişat o mutare, aceasta este 2.
CAPITOLUL 21. ONI 2015 21.1. ECHER - ONI 2015 278

21.1.2 Cod sursă

Listing 21.1.1: echer.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("echer.in");
6 ofstream g("echer.out");
7
8 int m,n,l1,l2,x,y,cer,k=0, mi, ma,i;
9
10 int main()
11 {
12 f>>cer>>l1>>l2>>m>>n;
13
14 x=m/l1;
15 y=n/l2;
16 mi=x>y?y:x;
17 ma=x+y-mi;
18
19 if(x==y)
20 k=3*x-2;
21 else
22 if(x-y==1)
23 k=3*y-1;
24 else
25 if(y-x==1)
26 k=3*x-1;
27 else
28 {
29 k=3*mi-2;
30 k+=2*(ma-mi);
31 if((ma-mi)%2)k--;
32 }
33
34 if(cer==1)
35 g<<k<<’\n’;
36 else
37 {
38 g<<1;
39 k--;
40 for(i=1;i<mi;i++)
41 {
42 g<<" 2 3 1";
43 k-=3;
44 }
45
46 if(x==y)
47 {
48 g<<’\n’;
49 return 0;
50 }
51 else
52 if(x-y==1)
53 {
54 g<<" 4\n";
55 k--;
56 return 0;
57 }
58 else
59 if(y-x==1)
60 {
61 g<<" 2\n";
62 k--;
63 return 0;
64 }
65
66 if(x-y>1)
67 {
68 while(k>=4)
69 {
70 g<<" 4 6 3 1";
CAPITOLUL 21. ONI 2015 21.1. ECHER - ONI 2015 279

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 }

Listing 21.1.2: echerCarmenMinca.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("echer.in");
7 ofstream g("echer.out");
8
9 int main()
10 {
11 int c1,c2,n,m,x,i,nr,p;
12
13 f>>p>>c1>>c2>>n>>m;
14 n=n/c1;
15 m=m/c2;
16 if(p==1)
17 {
18 if(n==m)nr=3*(n-1)+1;
19 else
20 if(n>m)
21 {
22 x=n-m;
23 nr=3*(m-1)+1+(x/2)*4+x%2;
24 }
25 else
26 {
27 x=m-n;
28 nr=3*(n-1)+1+(x/2)*4+x%2;
29 }
30
31 g<<nr<<’\n’;
32 }
33 else
34 {
35 g<<1;
36 if(n==m)
37 for(i=1;i<n;i++)
38 g<<" 2 3 1";
39 else
40 if(n>m)
41 {
42 x=n-m;
43 for(i=1;i<m;i++)
44 g<<" 2 3 1";
45 for(i=1;i<=x;i++)
46 if(i%2==0)
47 g<<" 6 3 1";
48 else
49 g<<" 4";
50 }
51 else
52 {
CAPITOLUL 21. ONI 2015 21.1. ECHER - ONI 2015 280

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 }

Listing 21.1.3: echerCristinaSichim.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("echer.in");
6 ofstream g("echer.out");
7
8 int c,l1,l2,m,n,Ox,Oy,k=1,a,b,i;
9
10 int main()
11 {
12 f>>c>>l1>>l2>>m>>n;
13 Ox=n/l2;
14 Oy=m/l1;
15
16 if(Ox<Oy)
17 a=Ox,b=Oy;
18 else
19 a=Oy,b=Ox;
20
21 if(c==1)
22 {
23 k+=3*(a-1);
24 b=b-a;
25 k+=4*(b/2)+b%2;
26 g<<k<<’\n’;
27 }
28 else
29 {
30 g<<"1";
31 b=(b-a)/2;
32 a--;
33 for(i=1;i<=a;++i)
34 g<<" 2 3 1";
35 if(Ox<=Oy)
36 {
37 for(i=1;i<=b;++i)
38 g<<" 4 6 3 1";
39 Oy=Oy-Ox;
40 if(Oy%2)
41 g<<" 4";
42 }
43 else
44 {
45 for(i=1;i<=b;++i)
46 g<<" 2 7 5 1";
47 Ox=Ox-Oy;
48 if(Ox%2)
49 g<<" 2";
50 }
51
52 g<<"\n";
53 }
54
55 f.close();
56 g.close();
57 return 0;
CAPITOLUL 21. ONI 2015 21.1. ECHER - ONI 2015 281

58 }

Listing 21.1.4: echerFlorentinaUngureanu.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("echer.in");
6 ofstream g("echer.out");
7
8 int m,n,l1,l2,x,y,cer,k=0, mi, ma,i;
9
10 int main()
11 {
12 f>>cer>>l1>>l2>>m>>n;
13 x=m/l1;y=n/l2;
14 mi=x>y?y:x;ma=x+y-mi;
15 if(x==y)
16 k=3*x-2;
17 else
18 if(x-y==1)
19 k=3*y-1;
20 else
21 if(y-x==1)
22 k=3*x-1;
23 else
24 {
25 k=3*mi-2;
26 k+=2*(ma-mi);
27 if((ma-mi)%2)k--;
28 }
29
30 if(cer==1)
31 g<<k<<’\n’;
32 else
33 {
34 g<<1;k--;
35 for(i=1;i<mi;i++)
36 {
37 g<<" 2 3 1";
38 k-=3;
39 }
40
41 if(x==y)
42 {
43 g<<’\n’;
44 return 0;
45 }
46 else
47 if(x-y==1)
48 {
49 g<<" 4\n";
50 k--;
51 return 0;
52 }
53 else
54 if(y-x==1)
55 {
56 g<<" 2\n";
57 k--;
58 return 0;
59 }
60
61 if(x-y>1)
62 {
63 while(k>=4)
64 {
65 g<<" 4 6 3 1";
66 k-=4;
67 }
68
69 if(k)
70 g<<" 4\n";
71 }
CAPITOLUL 21. ONI 2015 21.1. ECHER - ONI 2015 282

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 }

Listing 21.1.5: echerGinaBalacea.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("echer.in");
6 ofstream g("echer.out");
7
8 int m,n,l1,l2,c,nr_l1,nr_l2,min_l1_l2,max_l1_l2,nr_mutari,k,gata;
9
10 int main()
11 {
12 f>>c>>l1>>l2>>m>>n;
13
14 //Cerinta 1- calcul nr mutari
15 nr_l1=m/l1;
16 nr_l2=n/l2;
17 min_l1_l2=min(nr_l1,nr_l2);
18 max_l1_l2=max(nr_l1,nr_l2);
19
20 if(m/l1==n/l2)
21 nr_mutari=3*(m/l1)-2;
22 else
23 if(m/l1==n/l2+1)
24 nr_mutari=3*(n/l2)-1;
25 else
26 if(m/l1+1==n/l2)
27 nr_mutari=3*(m/l1)-1;
28 else
29 {
30 nr_mutari=min_l1_l2+2*(max_l1_l2-1);
31 if(((min_l1_l2%2==0) && (max_l1_l2%2==1)) ||
32 (( min_l1_l2%2)==1) && ((max_l1_l2%2)==0) )
33 nr_mutari--;
34 }
35 if(c==1)
36 {
37 g<<nr_mutari<<’\n’;
38 f.close();
39 g.close();
40 return 0;
41 }
42
43
44 //cerinta 2 afisare mutari
45 //Prima mutare este obligatoriu mutarea 1 .
46 // Se construiesc apoi cate 3 mutari : 2 3 1
47
48 g<<"1 ";// s-a executat o mutare. Prima mutare este mereu 1.
49 nr_mutari--;
50 for(k=1;k<min_l1_l2;k++)
51 {
52 nr_mutari=nr_mutari-3;
53 g<<"2 3 1 ";
54 }
55
56 if(m/l1==n/l2)
CAPITOLUL 21. ONI 2015 21.1. ECHER - ONI 2015 283

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 }

Listing 21.1.6: echerRoxanaTimplaru.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("echer.in");
6 ofstream g("echer.out");
7
8 int caz, l1,l2,minn,maxx,m,n,nr=0,dif,i;
9
10 int main()
11 {
12 f>>caz>>l1>>l2>>n>>m;
13
14 if(n/l1>m/l2)
15 {
16 minn=m/l2;
17 dif=n/l1-m/l2;
18 }
19 else
20 {
21 minn=n/l1;
22 dif=m/l2-n/l1;
23 }
24
CAPITOLUL 21. ONI 2015 21.2. LIGHTBOT - ONI 2015 284

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 }

21.1.3 *Rezolvare detaliată

21.2 lightbot - ONI 2015


Problema 2 - lightbot 100 de puncte
În acest an evenimentul ”Hour of Code” a ı̂nregistrat un
număr record de participanţi din ţara noastră. În cadrul acestui
eveniment una dintre cele mai accesate aplicaţii a fost Lightbot,
care a permis elevilor să-şi testeze abilităţile de programare.
Aplicaţia Lightbot are N nivele, numerotate consecutiv de la
1 la N , ı̂n ordinea strict crescătoare a complexităţii lor. Light-
bot a permis fiecărui participant să ı̂nceapă cu orice nivel strict
mai mic decât N  1 şi să sară peste un singur nivel, fără a final-
iza codul, trecând la nivelul următor celui sărit. La finalizarea
cu succes a codului corespunzător nivelului curent, participan- Figura 21.4: lightbot
tul este promovat la nivelul imediat următor. Fiecare participant a ı̂nceput scrierea codurilor la
un nivel P şi a sărit peste un nivel L (P $ L $ P  K), finalizând K nivele memorate ca o
succesiune de numere naturale de forma P , P  1, ..., L  1, L  1,..., P  K. Succesiunile de nivele
finalizate de participanţi au fost memorate ı̂n fişierul lightbot.in. Succesiunile corespunzătoare
participanţilor nu se intercalează ı̂n fişier.

Cerinţe
CAPITOLUL 21. ONI 2015 21.2. LIGHTBOT - ONI 2015 285

Scrieţi un program care citeşte succesiunile corespunzătoare nivelelor finalizate de participanţii


care au jucat Lightbot şi determină:
1. numărul total de participanţi;
2. numărul celui mai dificil nivel care a fost rezolvat de un număr maxim de participanţi;
3. pentru fiecare participant, numărul nivelului sărit de acesta.
Date de intrare
Fişierul de intrare lightbot.in conţine pe prima linie una dintre valorile 1 , 2 sau 3,
reprezentând cerinţa 1 dacă se cere determinarea numărului total de participanţi, cerinţa 2 dacă
se cere determinarea numărului celui mai dificil nivel care a fost rezolvat de un număr maxim de
participanţi, respectiv cerinţa 3, dacă se cere determinarea, pentru fiecare participant, a numărului
nivelului sărit de acesta.
A doua linie a fişierului conţine numărul natural N de nivele corespunzător aplicaţiei Lightbot,
iar pe a treia linie, succesiunile de numere naturale nenule corespunzătoare nivelelor finalizate de
participanţi, separate două câte două prin câte un spaţiu.
Date de ieşire
Fişierul de ieşire lightbot.out va conţine pe prima linie un număr natural M , reprezentând
numărul total de participanţi dacă cerinţa a fost 1, un număr natural reprezentând numărul celui
mai dificil nivel care a fost rezolvat de un număr maxim de participanţi, dacă cerinţa a fost 2,
respectiv, o secvenţă de M numere naturale separate prin câte un spaţiu ce reprezintă nivele sărite
de participanţi ı̂n ordinea succesiunilor memorate ı̂n fişier, dacă cerinţa a fost 3.
Restricţii şi precizări
a 3 & N & 200000.
a 1 & X & N , pentru orice număr X memorat pe a treia linie a fişierului lightbot.in.
a 1 & P $ L $ P  K & N , pentru orice succesiune de K nivele finalizate, corespunzătoare
unui participant, care a ı̂nceput scrierea codurilor la nivelul P şi a sărit peste nivelul L.
a O secvenţă de valori consecutive aparţine unui singur participant.
a A treia linie a fişierului de intrare conţine cel mult 400000 de numere.
a Pentru rezolvarea corectă a cerinţei 1 se obţine 20% din punctaj.
a Pentru rezolvarea corectă a cerinţei 2 se obţine 40% din punctaj.
a Pentru rezolvarea corectă a cerinţei 3 se obţine 40% din punctaj.

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

21.2.1 Indicaţii de rezolvare

prof. Florentina Ungureanu, Colegiul Naţional de Informatică Piatra-Neamţ


Utilizând un vector de tip frecvenţă determinăm pentru fiecare nivel numărul de participanţi
care au finalizat nivelul respectiv, numărul maxim de participanţi care au finalizat un nivel şi
numărul celui mai greu nivel care a fost rezolvat de un număr maxim de participanţi.
Pentru fiecare secvenţă se reţine nivelul care lipseşte, iar la ı̂ntâlnirea primului nivel core-
spunzător altui participant se incrementează numărul de participanţi şi se reţine nivelul sărit de
participantul anterior.
CAPITOLUL 21. ONI 2015 21.2. LIGHTBOT - ONI 2015 286

21.2.2 Cod sursă

Listing 21.2.1: lightbot.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("lightbot.in");
6 ofstream g("lightbot.out");
7
8 int n, fr[200010],P[200010],np,cer;
9
10 int main()
11 {
12 int a, b,l=0,maxim,nm,i;
13 f>>cer>>n>>a;
14 fr[a]++;
15 maxim=1;
16 nm=a;
17 np=0;
18 while (f>>b)
19 {
20 fr[b]++;
21 if(fr[b]>maxim)
22 {
23 maxim=fr[b];
24 nm=b;
25 }
26 else
27 if(fr[b]==maxim&&b>nm)
28 nm=b;
29
30 if(l==0&&b-a==2)
31 l=b-1;
32 else
33 if(b-a!=1)
34 {
35 P[++np]=l;
36 l=0;
37 }
38 a=b;
39 }
40
41 P[++np]=l;
42 if(cer==1)
43 g<<np<<’\n’;
44 else
45 if (cer==2)
46 g<<nm<<’\n’;
47 else
48 {
49 for(i=1;i<np;i++)
50 g<<P[i]<<’ ’;
51
52 g<<P[np]<<’\n’;
53 }
54
55 return 0;
56 }

Listing 21.2.2: lightbotCarmenMinca.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f ("lightbot.in");
7 ofstream g ("lightbot.out");
8
9 const int NMAX = 200000 + 1;
10
CAPITOLUL 21. ONI 2015 21.2. LIGHTBOT - ONI 2015 287

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 }

Listing 21.2.3: lightbotCristinaSichim.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("lightbot.in");
6 ofstream g("lightbot.out");
7
8 int v[100001],m[200001],n,x,y,nr=1,k,i,l,niv,c;
9
10 int main()
11 {
12 f>>c;
13 f>>n>>x;
14 l=1;
15 m[x]=1;
16 while(f>>y)
17 {
18 m[y]++;
19 l++;
20 if(x+2==y && l>1)
21 {
22 v[++k]=x+1;
23 l=0;
24 }
25
26 x=y;
27 }
28
29 niv=1;
30 if(c==1)
31 g<<k<<’\n’;
32 else
33 if(c==2)
34 {
35 for(i=1;i<=n;i++)
36 if(m[i]>=m[niv])
37 niv=i;
38
39 g<<niv<<’\n’;
40 }
41 else
42 {
43 for(i=1;i<=k;i++)
44 g<<v[i]<<’ ’;
45 g<<’\n’;
CAPITOLUL 21. ONI 2015 21.2. LIGHTBOT - ONI 2015 289

46 }
47
48 f.close();
49 g.close();
50 return 0;
51 }

Listing 21.2.4: lightbotFlorentinaUngureanu.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("lightbot.in");
6 ofstream g("lightbot.out");
7
8 int n, fr[200010],P[200010],np,cer;
9
10 int main()
11 {
12 int a, b,l=0,maxim,nm,i;
13 f>>cer>>n>>a;
14 fr[a]++;
15 maxim=1;
16 nm=a;
17 np=0;
18 while (f>>b)
19 {
20 fr[b]++;
21 if(fr[b]>maxim)
22 {
23 maxim=fr[b];
24 nm=b;
25 }
26 else
27 if(fr[b]==maxim&&b>nm)
28 nm=b;
29
30 if(l==0&&b-a==2)
31 l=b-1;
32 else
33 if(b-a!=1)
34 {
35 P[++np]=l;
36 l=0;
37 }
38
39 a=b;
40 }
41
42 P[++np]=l;
43 if(cer==1)
44 g<<np<<’\n’;
45 else
46 if (cer==2)
47 g<<nm<<’\n’;
48 else
49 {
50 for(i=1;i<np;i++)
51 g<<P[i]<<’ ’;
52 g<<P[np]<<’\n’;
53 }
54
55 return 0;
56 }

Listing 21.2.5: lightbotLiliChira.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("lightbot.in");
6 ofstream g("lightbot.out");
CAPITOLUL 21. ONI 2015 21.2. LIGHTBOT - ONI 2015 290

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 }

Listing 21.2.6: lightbotRoxanaTimplaru.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("lightbot.in");
7 ofstream g("lightbot.out");
8
9 int n, x[200001],nr,t,y[200001],val,caz,k;
10
CAPITOLUL 21. ONI 2015 21.2. LIGHTBOT - ONI 2015 291

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 }

21.2.3 *Rezolvare detaliată


CAPITOLUL 21. ONI 2015 21.3. TEREN - ONI 2015 292

21.3 teren - ONI 2015


Problema 3 - teren 100 de puncte
În satul vecin există un teren agricol de formă dreptunghiulară ı̂mpărţit ı̂n N ˜ M pătrate
elementare identice, dispuse alăturat câte M pe fiecare rând şi câte N pe fiecare coloană. Rândurile
sunt numerotate de la 1 la N , iar coloanele de la 1 la M . Un pătrat elementar situat ı̂n teren pe
rândul R şi coloana C este identificat prin coordonatele R, C .
Suprafeţe dreptunghiulare din teren (formate fiecare din unul sau mai multe pătrate elementare
alăturate) sunt revendicate de T fermieri din sat, ı̂n calitate de moştenitori, pe baza actelor primite
de la strămoşii lor. Pentru că au apărut şi acte false, s-a constat că pot exista mai mulţi fermieri
care revendică aceleaşi pătrate elementare.
În cele T acte ale fermierilor, suprafeţele dreptunghiulare sunt precizate fiecare prin câte două
perechi de numere X, Y  şi Z, U , reprezentând coordonatele primului pătrat elementar din
colţul stânga-sus al suprafeţei (rândul X şi coloana Y ), respectiv coordonatele ultimului pătrat
elementar situat ı̂n colţul dreapta-jos al suprafeţei (rândul Z şi coloana U ).

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.

Restricţii şi precizări

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

teren.in teren.out Explicaţii


1 2 Pătratul elementar cu coordonatele
35322 R 2 şi C 2 este revendicat de 2
2323 fermieri
1233
2123

Figura 21.5: teren


2 3 Pătratul elementar cu coordonatele (2,3) este revendicat de 3 fermieri
3 5 3 22 (numărul maxim de revendicări).
2 3 2 3
1 2 3 3
2 1 2 3
3 4 Sunt două suprafeţe pătratice nerevendicate de niciun fermier, for-
3 5 3 22 mate fiecare din numărul maxim de patru pătrate elementare. Aces-
2 3 2 3 tea au coordonatele: (1,4) şi (2,5) respectiv (2,4) şi (3,5).
1 2 3 3
2 1 2 3

Timp maxim de executare/test: 0.2 secunde


Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 5 KB

21.3.1 Indicaţii de rezolvare

prof. Carmen Mincă, Colegiul Naţional de Informatică ”Tudor Vianu”, Bucureşti

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 ).

Figura 21.6: teren


CAPITOLUL 21. ONI 2015 21.3. TEREN - ONI 2015 294

21.3.2 Cod sursă

Listing 21.3.1: terenCarmenMinca.cpp


1 //autor Carmen Minca - 100p
2
3 #include <iostream>
4 #include <fstream>
5
6 using namespace std;
7
8 int a[185][185];
9
10 ifstream f("teren.in");
11 ofstream g("teren.out");
12
13 int main()
14 {
15 int n,t,m, r,c,i,j,p,nrb=0,nrc=0,x,y,z,u,k,lat,ok,nr;
16
17 f>>p>>n>>m>>t>>r>>c;
18
19 for(k=1;k<=t;k++)
20 {
21 f>>x>>y>>z>>u;
22 for(i=x;i<=z;i++)
23 for(j=y;j<=u;j++)
24 {
25 a[i][j]++;
26 nrb=max(nrb,a[i][j]);
27 }
28 }
29
30 if(p==1)
31 g<<a[r][c]<<’\n’;//cerinta a0
32 else
33 if(p==2)g<<nrb<<’\n’; //cerinta b)
34 else
35 {
36 //cerinta c
37 for(i=1;i<=n-nrc; i++)
38 for(j=1;j<=m-nrc;j++)
39 if(a[i][j]==0)
40 {
41 lat=1;
42 ok=1;
43 while(ok)
44 {
45 x=z=lat+i;
46 y=u=lat+j;
47 if(x>n || y>m)
48 ok=0;
49
50 while(z>=i && ok )
51 {
52 if(a[x][u]+a[z][y]==0)
53 {
54 u--;
55 z--;
56 }
57 else
58 ok=0;
59 }
60
61 if(ok)
62 lat++;
63 }
64
65 nrc=max(lat, nrc);
66 }
67
68 g<<nrc*nrc<<’\n’;
69 }
70
CAPITOLUL 21. ONI 2015 21.3. TEREN - ONI 2015 295

71 return 0;
72 }

Listing 21.3.2: terenCristinaSichim.cpp


1 //prof Cristina Sichim - 100p
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("teren.in");
7 ofstream g("teren.out");
8
9 int a[185][185],N,M,T,R,C,i,j,x,y,z,u,t,l,P;
10
11 void patrat(int i,int j, int &l)
12 {
13 int i1=i,j1=j,k;
14 l=0;
15 while(a[i][j1]==0 && a[i1][j]==0)
16 {
17 for(k=i;k<=i1;k++)
18 if(a[k][j1])
19 return;
20
21 for(k=j;k<=j1;k++)
22 if(a[i1][k])
23 return;
24
25 l++;
26 i1++;
27 j1++;
28 }
29 }
30
31 int main()
32 {
33 f>>P>>N>>M>>T>>R>>C;
34
35 for(t=1;t<=T;++t)
36 {
37 f>>x>>y>>z>>u;
38 for(i=x;i<=z;i++)
39 for(j=y;j<=u;j++)
40 a[i][j]++;
41 }
42
43 if(P==1)
44 g<<a[R][C]<<’\n’;
45 else
46 if(P==2)
47 {
48 t=0;
49 for(i=1;i<=N;++i)
50 for(j=1;j<=M;++j)
51 t=max(t,a[i][j]);
52
53 g<<t<<’\n’;
54 }
55 else
56 {
57 for(i=1;i<=M;++i)
58 a[0][i]=a[N+1][i]=1;
59
60 for(i=1;i<=N;i++)
61 a[i][M+1]=1;
62
63 t=0;
64 for(i=1;i<=N-t;++i)
65 for(j=1;j<=M-t;++j)
66 if(a[i][j]==0)
67 {
68 patrat(i,j,l);
69 t=max(t,l);
70 }
CAPITOLUL 21. ONI 2015 21.3. TEREN - ONI 2015 296

71
72 g<<t*t<<’\n’;}
73 f.close();g.close();
74 return 0;
75 }

Listing 21.3.3: terenGinaBalacea.cpp


1 //prof Gina Balacea - 100p
2 #include<fstream>
3 #include <cmath>
4
5 using namespace std;
6
7 ifstream f("teren.in");
8 ofstream g("teren.out");
9
10 int n,m,T,R,C,P;
11 int X1,Y1,Z1,U1,t[200][200],maxt,max_nerevendicat,L,ok;
12
13 int main()
14 {
15 f>>P>>n>>m>>T>>R>>C;
16 for(int i=1; i<=T; i++)
17 {
18 f>>X1>>Y1>>Z1>>U1;
19 for(int l=X1; l<=Z1; l++)
20 for(int c=Y1; c<=U1; c++)
21 t[l][c]++;
22 }
23
24 //rezolvare punct a
25 if(P==1) g<<t[R][C]<<’\n’;
26 //rezolvare punct b
27 else
28 if(P==2)
29 {for(int l=1; l<=n; l++)
30 for(int c=1; c<=m; c++)
31 maxt=max(maxt,t[l][c]);
32
33 g<<maxt<<’\n’;}
34 //rezolvare punct c
35 else{
36 for(int l=1; l<=n-max_nerevendicat; l++)
37 for(int c=1; c<=m-max_nerevendicat; c++)
38 if(!t[l][c])
39 { for(L=ok=1;ok;L+=ok)
40 { X1=Z1=L+l;
41 Y1=U1=L+c;
42 if(X1>n ||Y1>m) ok=0;
43 while(Z1*ok>=l )
44 if(t[X1][U1]+t[Z1][Y1]==0)
45 { U1--; Z1--;} else ok=0;
46 }
47 max_nerevendicat=max(max_nerevendicat,L);
48 }
49
50 g<<pow(max_nerevendicat,2)<<’\n’;
51 }
52 f.close(); g.close();
53 return 0;
54 }

Listing 21.3.4: terenMarinelSerban.cpp


1 //Marinel Serban - aprilie 2015 - 100p
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream fin("teren.in");
7 ofstream fout("teren.out");
8
9 #define DIMMAX 200
CAPITOLUL 21. ONI 2015 21.3. TEREN - ONI 2015 297

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 }

Listing 21.3.5: terenRoxanaTimplaru.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("teren.in");
7 ofstream g("teren.out");
8
9 int caz,n,m,r,c,a[181][181], b[181][181],t,i,j,k,p,x,y,z,u,maxx,minn;
10
11 int main()
12 {
13 f>>caz>>n>>m>>t>>r>>c;
14 maxx=0;
15 for (p=1;p<=t;p++)
CAPITOLUL 21. ONI 2015 21.3. TEREN - ONI 2015 298

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 }

21.3.3 *Rezolvare detaliată


Capitolul 22

ONI 2014

22.1 betisoare - ONI 2014


Problema 1 - betisoare 100 de puncte
Se presupune că unele dintre primele instrumente de calcul au fost beţişoarele de socotit. În
problema noastră vom considera un număr ca fiind o succesiune de unul sau mai multe beţişoare,
un beţişor fiind reprezentat de litera I. Într-o expresie, ı̂ntre oricare două numere există semnul +
sau semnul *. Exemple:

Figura 22.1: betisoare

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

Timp maxim de executare/test: 1.0 secunde


Memorie: total 2 MB din care pentru stivă 1 MB
Dimensiune maximă a sursei: 10 KB

22.1.1 Indicaţii de rezolvare

prof. Marinel Şerban, CN Emil Racoviţă, Iaşi


Solutia I 100 puncte
O expresie se evaluează astfel:
- citirea se face caracter cu caracter, deci nu se utilizează nici un vector
- se separă primul factor (care se termină cu ’\n’, ’+’, ’*’)
- caracterul separator este operatorul următor ı̂n expresie (eventual final)
- se prelucrează ı̂n buclă până la detectarea caracterului ’\n’
` ı̂n cazul ı̂n care s-a detectat ’+’ sau ’\n’
- se ı̂nmulţeşte factorul calculat la termen
- se adună la suma totală
- se iniţializează termenul următor cu 1
` dacă s-a detectat ’*’
- se ı̂nmulţeşte doar factorul la termen
` se reiniţializează factorul
` se determină valoarea acestuia (se termina cu ’+’, ’*’ sau \’n’ care se reţine
ca operaţie următoare)
- la terminarea citirii expresiei
` dacă suma calculată până aici este 0 (adică nu a existat niciun termen)
- suma devine = termen * ultimul factor calculat
` dacă au mai existat termeni
- la sumă se adună (ultimul termen * ultimul factor)

Solutia II 100 puncte


Se utilizează funcţii standard din biblioteca cstring pentru prelucrarea şirurilor de caractere.
O expresie se evaluează astfel:
- citirea se face cu getline ı̂n şirul de caractere ’expresie’
- se determina lungimea expresiei
- se detectează operaţia următoare (’\0’, ’+’, ’*’)
- utilizându-se funcţia standard strtok se separă câte un factor din expresie
` factorul este chiar lungimea token-ului separat
` ı̂n cazul ı̂n care operaţia următoare este ’+’ sau ’\0’
- se ı̂nmulţeşte factorul calculat la ternmen
- se adună la suma totală
- se iniţializează termenul următor cu 1
` dacă s-a detectat ’*’
- se ı̂nmulţeşte doar factorul la termen
` se detectează operaţia următoare
- ı̂n final dacă suma calculată până atunci este 0 (nu a existat niciun termen)
ultimul termen calculat este chiar rezultatul

22.1.2 Cod sursă

Listing 22.1.1: betisoare OK.cpp


1 //Marinel Serban - martie 2014
2 //citire caracter cu caracter
3 //nu utilizeaza nici o biblioteca, doar tipuri standard
4
5 #include <fstream>
6
7 #define NMAX 1000010
8
9 using namespace std;
10
CAPITOLUL 22. ONI 2014 22.1. BETISOARE - ONI 2014 301

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 }

Listing 22.1.2: betisoare CristinaI.cpp


1 # include <fstream>
2 using namespace std;
3
4 ifstream fin("betisoare.in");
5 ofstream fout("betisoare.out");
6
7 long long numar[100000],S;
8 int nr_elem;
9
10 void evaluare_linie()
11 { int i;
12 for(i=1;i<nr_elem;i=i+2)
13 {
14 if(numar[i]==-2)
15 {
16 numar[i+1]=numar[i-1]*numar[i+1];
17 numar[i]=0;
18 }
19 else
20 if (numar[i]==0)
CAPITOLUL 22. ONI 2014 22.1. BETISOARE - ONI 2014 302

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 }

Listing 22.1.3: betisoare nistor.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 int main()
6 {int n,i;
7 long long j,lung,nr,term,rez;
8 string s;
9
10 ifstream fi("betisoare.in");
11 ofstream fo("betisoare.out");
12
13 fi>>n;
14 for (i=0;i<n;i++)
15 {
16 fi>>s;
17 lung=s.length();
18 rez=0;
19 term=1;
20 nr=0;
21 for (j=0;j<=lung;j++)
22 {
23 if (j==lung || s[j]==’+’)
24 {term *= nr; rez += term; nr=0; term=1;}
25 else if (s[j]==’*’)
26 { term *= nr; nr=0;}
CAPITOLUL 22. ONI 2014 22.1. BETISOARE - ONI 2014 303

27 else nr++;
28 }
29 fo<<rez<<"\n";
30 }
31 return 0;
32 }

Listing 22.1.4: betisoare ovidiu 1.cpp


1 #include <stdio.h>
2 #include<fstream>
3
4 using namespace std;
5
6 long long val,rez,st[10000],vf=0,vfop,k,nr_curent,nr_stea,n;
7 char c;
8 ofstream g("betisoare.out");
9
10 int main()
11 { freopen("betisoare.in","r",stdin); //freopen(".out","w",stdout);
12 scanf("%d",&n);scanf("%c",&c);
13
14 for(int i=1;i<=n;i++)
15 { vf=0;rez=0;
16 scanf("%c",&c);
17 while(c!=’\n’)
18 { nr_curent=0;
19 while(c==’I’) {nr_curent++; scanf("%c",&c); }
20
21 if(nr_stea) {st[vf]=st[vf]*nr_curent;nr_stea--;}
22 else st[++vf]=nr_curent;
23
24 if(c==’*’) nr_stea++;
25 if(c!=’\n’)scanf("%c",&c);
26 }
27 for(k=1;k<=vf;k++)rez=rez + st[k]; g<<rez<<’\n’;
28 }
29 return 0;
30 }

Listing 22.1.5: betisoare ovidiu 2.cpp


1 #include <stdio.h>
2 #include<fstream>
3
4 using namespace std;
5
6 long long val,rez,st[10000],vf=0,vfop,k,nr_curent,nr_stea,n;
7 char c;
8 FILE *f=fopen("betisoare.in","r");
9 ofstream g("betisoare.out");
10
11 int main()
12 {
13 fscanf(f,"%d",&n);
14 fscanf(f,"%c",&c);
15
16 for(int i=1;i<=n;i++)
17 { vf=0;rez=0;
18 fscanf(f,"%c",&c);
19
20 while(c!=’\n’)
21 { nr_curent=0;
22 while(c==’I’) {nr_curent++; fscanf(f,"%c",&c); }
23
24 if(nr_stea) {st[vf]=st[vf]*nr_curent;nr_stea--;}
25 else st[++vf]=nr_curent;
26
27 if(c==’*’) nr_stea++;
28 if(c!=’\n’) fscanf(f,"%c",&c);
29 }
30
31 for(k=1;k<=vf;k++)
32 rez=rez + st[k];
CAPITOLUL 22. ONI 2014 22.1. BETISOARE - ONI 2014 304

33 g<<rez<<’\n’;
34 }
35 return 0;
36 }

Listing 22.1.6: betisoare ovidiu 3.cpp


1 #include <stdio.h>
2 #include<fstream>
3
4 using namespace std;
5
6 long long val,rez,st[4],nr_curent;
7 int vf,k,nr_stea,n;
8 char c;
9
10 FILE *f=fopen("betisoare.in","r");
11 ofstream g("betisoare.out");
12
13 int main()
14 {
15 fscanf(f,"%d",&n);
16 fscanf(f,"%c",&c);
17 for(int i=1;i<=n;i++)
18 { vf=0;rez=0;
19 fscanf(f,"%c",&c);
20 while(c!=’\n’)
21 { nr_curent=0;
22 while(c==’I’) {nr_curent++; fscanf(f,"%c",&c); }
23
24 if(nr_stea) {st[vf]=st[vf]*nr_curent;nr_stea--;}
25 else st[++vf]=nr_curent;
26
27 if(c==’*’) {nr_stea++;fscanf(f,"%c",&c);}
28 else
29 if(c==’+’)
30 {if(vf==2){st[vf-1]=st[vf-1]+st[vf];vf--;}
31 fscanf(f,"%c",&c);
32 }
33
34 }
35
36 for(k=1;k<=vf;k++)rez=rez + st[k];
37 //fprintf(g,"%lld\n",rez);
38
39 g<<rez<<’\n’;
40 }
41 return 0;
42 }

Listing 22.1.7: betisoare r.cpp


1 #include <iostream>
2 #include <fstream>
3 #include <string>
4 #include<stdlib.h>
5 #include<stdio.h>
6
7 using namespace std;
8
9 ifstream f("betisoare.in");
10 ofstream g("betisoare.out");
11
12 long long stiva[200002], n,i;
13 long long k,x,t,j;
14
15 int main()
16 {
17 char ch, op;
18
19 f>>n;
20 f.get(ch);
21
22 for(i=1;i<=n;i++)
CAPITOLUL 22. ONI 2014 22.1. BETISOARE - ONI 2014 305

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 }

Listing 22.1.8: betisoare sanda.cpp


1 #include <iostream>
2 #include <fstream>
3 #include <cstring>
4
5 using namespace std;
6
7 ifstream f("betisoare.in");
8 ofstream g("betisoare.out");
9
10 char a[1000000000];
11 int i,m,n,ok,nr,x,j,k;
12
13 int main()
14 {
15 f>>n; //citire numar total de secvente
16
17 for(k=1;k<=n;k++)
18 {
19 nr=0;
20 f>>a; //citire secventa
CAPITOLUL 22. ONI 2014 22.1. BETISOARE - ONI 2014 306

21 m=strlen(a); // aflare dimensiune secventa


22
23 for(i=0;i<m;i++)
24 { //parcurgere secventa pe caractere
25 x=1; // nr pt inmultire
26 if(a[i]==’I’ && a[i+1]==’+’)
27 nr=nr+1; // cazul cand e I+
28 if(a[i-1]==’+’ && a[i]==’I’ && a[i+1]==’\0’)
29 nr=nr+1; // cazul cand e +I
30 if(a[i]==’I’ && a[i+1]==’*’){if(nr==0)
31 nr=1; nr=nr*x; } //cazul cand e I*
32 if(a[i]==’I’ && a[i+1]==’I’)
33 { //cazul cand e II
34 x=0; //pentru a calcula valoarea de I
35 j=i; //pozitia de plecare
36 while(a[j]==’I’ && j<m)
37 { //conditia pana cand numara
38 x=x+1; //numara cati de I sunt succesiv
39 j++;
40 }
41
42 if(a[j]==’*’){ if(nr==0) nr=1;
43 nr=nr*x;} //cazul cand III..*
44
45 if(a[i-1]==’*’ && a[j]==’+’)
46 nr=nr*x; //cazul *II..+
47 else
48 if(a[j]==’+’)
49 nr=nr+x; //cazul III..+
50
51 i=i+x; //mutarea i-ului peste x pozitii in secventa
52 }
53 }
54
55 g<<nr; //afisare numar
56 g<<’\n’;
57 }
58
59 return 0;
60 }

Listing 22.1.9: betisoare strtok.cpp


1 //Marinel Serban martie 2014
2 //utilizeaza functii standard pentru siruri de caractere
3
4 #include <fstream>
5 #include <cstring>
6
7 #define NMAX 1000010
8 using namespace std;
9
10 ifstream fin("betisoare.in");
11 ofstream fout("betisoare.out");
12
13 int n, i, j, l;
14 long long factor, valoare, termen, suma;
15 char expresie[NMAX], *psemn, semn_urmator;
16
17 int main()
18 {
19 fin >> n;
20 fin.get();
21 for (i = 1; i <= n; i++)
22 {
23 //calculeaza cea de-a i-a expresie
24 strcpy(expresie, "");
25 fin.getline(expresie, NMAX); //citesc expresia
26 l = strlen(expresie);
27 suma = 0; //initializez suma
28 termen = 1;
29 j = 0; //cu j caut pozitia semnului urmator
30 while (expresie[j] != ’+’ && expresie[j] != ’*’) j++;
31 semn_urmator = expresie[j]; //retin semnul urmator
32 psemn = strtok(expresie, "+*");//separ primul termen
CAPITOLUL 22. ONI 2014 22.1. BETISOARE - ONI 2014 307

33 while (psemn) //cat timp mai am termeni sau factori


34 {
35 factor = strlen(psemn);
36 if (semn_urmator == ’+’|| semn_urmator == ’\0’)
37 {
38 termen *= factor;
39 suma += termen;
40 termen = 1;
41 }
42 else
43 termen *= factor;
44 while (expresie[j] != ’+’ &&
45 expresie[j] != ’*’ && j < l) j++; //urmatorul semn
46 semn_urmator = expresie[j]; //il retin
47 psemn = strtok(NULL, "+*"); //separ termenul urmator
48 }
49 if (suma == 0)
50 suma = termen;
51 fout << suma << ’\n’; //afisez rezultat
52 }
53 fout.close();
54 return 0;
55 }

Listing 22.1.10: sursa1 Lili.cpp


1 #include<cstdio>
2
3 using namespace std;
4
5 typedef long long int lld;
6 const int NMAX = 1000000+5;
7
8 int N,L;
9 lld sol;
10
11 int main()
12 {
13 lld nr,ok;
14 char c;
15
16 freopen("betisoare.in","r",stdin);
17 freopen("betisoare.out","w",stdout);
18
19 scanf("%d\n",&N);
20
21 for(; N; --N)
22 {
23 nr=0;
24 ok=1;
25 sol=0;
26 for(scanf("%c",&c); c!=’\n’; scanf("%c",&c))
27 {
28 if(c==’I’) nr++;
29 else if(c==’+’)
30 {
31 ok*=nr;
32 nr=0;
33 sol+=ok;
34 ok=1;
35 }
36 else
37 {
38 ok*=nr;
39 nr=0;
40 }
41 }
42 ok*=nr;
43 sol+=ok;
44 printf("%lld\n",sol);
45 }
46
47 return 0;
48 }
CAPITOLUL 22. ONI 2014 22.1. BETISOARE - ONI 2014 308

Listing 22.1.11: sursa2 Lili.cpp


1 #include<fstream>
2 #include<cstring>
3
4 using namespace std;
5
6 typedef long long int lld;
7 const int NMAX = 1000000+5;
8
9 int N,L;
10 lld sol;
11 char S[NMAX];
12
13 int main()
14 {
15 int i;
16 lld nr,ok;
17
18 ifstream fin("betisoare.in");
19 ofstream fout("betisoare.out");
20
21 fin>>N;
22
23 for(; N; --N)
24 {
25 fin>>S+1;
26 L=strlen(S+1);
27 S[++L]=’+’;
28 nr=0;
29 ok=1;
30 sol=0;
31 for(i=1; i<=L; i++)
32 {
33 if(S[i]==’I’) nr++;
34 else if(S[i]==’+’)
35 {
36 ok*=nr;
37 nr=0;
38 sol+=ok;
39 ok=1;
40 }
41 else
42 {
43 ok*=nr;
44 nr=0;
45 }
46 }
47 fout<<sol<<’\n’;
48 }
49
50 return 0;
51 }

Listing 22.1.12: sursa3 Lili.cpp


1 #include<cstdio>
2
3 using namespace std;
4
5 int T;
6 char s[1000005],*p;
7
8 long long e(),t(),f();
9
10 int main()
11 {
12 freopen("betisoare.in","r",stdin);
13 freopen("betisoare.out","w",stdout);
14 for(scanf("%d",&T);T;T--)
15 {
16 scanf("%s",s); p=s;
17 printf("%lld\n",e());
18 }
19 return 0;
CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 309

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 }

22.1.3 *Rezolvare detaliată

22.2 praslea - ONI 2014


Problema 2 - praslea 100 de puncte
A fost odată ca niciodată un ı̂mpărat puternic care avea o grădină min-
unată, situată pe un teren de formă dreptunghiulară din jurul palatului.
În grădină creştea un măr cu mere de aur, dar ı̂mpăratul nu a putut să se
bucure vreodată de merele din pom deoarece grădina a fost mereu atacată de
tâlhari şi merele au fost furate. Cu toate că aceasta a fost păzită zi şi noapte
de cei mai viteji ostaşi din ı̂mpărăţie, ei nu au putut face faţă tâlhăriilor.
Deznădăjduit, ı̂mpăratul şi-a pus ı̂n gând să taie pomul cu mere de aur,
dar fiul său cel mic, Prâslea, l-a rugat să-l lase şi pe el să-şi ı̂ncerce norocul.
Prâslea a cugetat foarte bine la cele ı̂ntâmplate şi a procedat astfel: Figura 22.2:
praslea

Figura 22.3: praslea

- 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

Fişierul de intrare praslea.in conţine


CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 310

- 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).

Restricţii şi precizări

a 1 & N & 500000 şi 1 & M & 10000 şi M $ N ;


a 1 & L, Li & 4000000000;
a Nicio parcelă dintre cele M nu are lăţimea egală cu L;
a Dacă D este exact pe linia ce desparte două parcele alăturate se consideră că pomul e situat
ı̂n parcela din stânga
a Pentru rezolvarea corectă a cerinţei a) se acordă 20% din punctajul fiecărui test, iar pentru
rezolvarea corectă a cerinţei b) se acordă 80% din punctajul fiecărui test.

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.

Timp maxim de executare/test: 0.5 secunde


Memorie: total 4 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 10 KB

22.2.1 Indicaţii de rezolvare

Soluţia 1 - 100 puncte

prof. Cristina Iordaiche, Liceul Teoretic ”Grigore Moisil” Timişoara

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.

Soluţia 2 - 100 puncte

prof. Roxana Tı̂mplaru, Colegiul ”Ştefan Odobleja”, Craiova


CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 311

a la citirea valorilor Pi şi Li de pe cele M linii, se memorează ı̂n v Pi  Li ;


a determinăm numărul de ordine cel mai mare dintre cele M parcele, fie acesta max;
a determinăm pentru primele max parcele, numărul maxim de parcele vecine, de lăţime L şi
calculăm distanţa de la pomul cu merele de aur, reţinând numărul de ordine al parcelei pentru
care distanţa până la ea este mai mare sau egală cu distanţa D precizată ı̂n enunţ;
a determinăm numărul de parcele rămase după primele max parcele, actualizând numărul
maxim de parcele vecine de lăţime L, respectiv numărul de ordine al parcelei (ı̂n cazul ı̂n care
distanţa până la primele max parcele este mai mica decât distanţa D).

22.2.2 Cod sursă

Listing 22.2.1: praslea.cpp


1 //prof. Iordaiche Cristina
2 #include <fstream>
3 #include <cmath>
4 #include <algorithm>
5
6 using namespace std;
7
8 struct parcela
9 {
10 unsigned int indice, latime;
11 } C[10002];
12
13
14 ifstream fin("praslea.in");
15 ofstream fout("praslea.out");
16
17 long long N,L,M,P,indice_precedent,alaturate,max_parcele,Pom;
18
19 bool cmp(parcela a,parcela b)
20 {
21 return a.indice<b.indice;
22 }
23
24 int main()
25 {
26 int i,ok=0;
27 fin>>N>>M>>L;
28 float x;
29
30 //citirea datelor
31 for(i=0;i<M;++i)
32 fin>>C[i].indice>>C[i].latime;
33
34 M++;
35 C[M].indice=N+1;
36 C[M].latime=0;
37 fin>>P;
38
39 //sortarea parcelelor in functie de indice
40 sort(C,C+M,cmp);
41
42 max_parcele=N-C[M-1].indice;
43 i=0;
44 while(i<M)
45 {
46 alaturate=C[i].indice-indice_precedent-1;
47 max_parcele=max(max_parcele,alaturate); //rezolvare cerinta a)
48
49 if(!ok && P<=(alaturate*L))
50 {
51 Pom=indice_precedent+ceil((double)P/L);
52 ok=1;
53 } // pomul e inaintea parcelei curente
54 else
55 {
56 if (alaturate>0)
57 P=P-(alaturate)*L;
58 if(!ok && P<=C[i].latime) //pomul e in parcela curenta
CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 312

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 }

Listing 22.2.2: praslea Cristina quicksort.cpp


1 #include <fstream>
2 # include <math.h>
3
4 using namespace std;
5
6 ifstream fin("praslea.in");
7 ofstream fout("praslea.out");
8
9 unsigned int indice[10002], latime[10002];
10 long long N,L,M,P,indice_precedent,alaturate,max_parcele,Pom;
11
12 int poz(int p,int u)
13 {
14 int piv,M;
15 long long aux;
16 piv=indice[p];
17 while (p<u)
18 {
19 if (indice[p]>indice[u])
20 {
21 aux=indice[p];
22 indice[p]=indice[u];
23 indice[u]=aux;
24 aux=latime[p];
25 latime[p]=latime[u];
26 latime[u]=aux;
27 }
28
29 if (indice[p]==piv)
30 u--;
31 else
32 p++;
33 }
34
35 M=p;
36 return M;
37 }
38
39 void quick(int p,int u)
40 {
41 int M;
42 if (p<u)
43 {
44 M=poz(p,u);
45 quick(p,M-1);
46 quick(M+1,u);
47 }
48 }
49
50 int main()
51 {
52 int i,ok=0;
CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 313

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 }

Listing 22.2.3: praslea Cristina sortare simpla.cpp


1 #include <fstream>
2 # include <math.h>
3
4 using namespace std;
5
6 unsigned int C_indice[10002], C_latime[10002];
7
8 ifstream fin("praslea.in");
9 ofstream fout("praslea.out");
10
11 long long n,l,k,P,indice_precedent,alaturate,max_parcele,Pom;
12
13 void sortare()
14 {
15 long long aux;
16 int i,j;
17
18 for(i=0;i<k-1;i++)
19 for(j=i+1;j<k;j++)
CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 314

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 }

Listing 22.2.4: praslea Lili.cpp


1 //prof. Liliana Chira - Colegiul National M i h a i Eminescu Botosani
2 #include<cstdio>
3 #include<algorithm>
4
5 using namespace std;
CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 315

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 }

Listing 22.2.5: praslea marinel.cpp


1 //Marinel Serban - aprilie 2014
2 //utilizare sort STL
3 //utilizare struct
4 #include <fstream>
5 #include <algorithm>
6 #include <iostream>
7
8 using namespace std;
9
10 #define MMAX 10010
11
12 ifstream fin("praslea.in");
13 ofstream fout("praslea.out");
14
15 struct lot
16 {
17 int nr;
18 unsigned long L;
19 } P[MMAX];
20
21 unsigned long long L, D, Sli = 0, Lungime, S, l;
22 int nr_max_loturi = 0, M, N;
23
24 int criteriu(lot a, lot b)
25 {
26 return a.nr < b.nr;
27 }
28
29 void citire()
30 {
31 int i, pi;
32 unsigned int li;
33 fin >> N >> M >> L;
CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 316

34 for (i = 1; i <= M; ++i)


35 {
36 fin >> pi >> li;
37 //if (i != M-pi+1) cout << " LIPSA " << M-pi+1 << ’\n’;
38 P[i].nr = pi;
39 P[i].L = li;
40 Sli += li;
41 }
42 fin >> D;
43 }
44
45 int main()
46 {
47 int i, j;
48 citire();
49 sort(P+1, P+M+1, criteriu);
50 //a
51 if (P[1].nr - 1 > nr_max_loturi)
52 nr_max_loturi = P[1].nr - 1;
53 for (i = 1; i < M; ++i)
54 if (P[i+1].nr - P[i].nr > nr_max_loturi)
55 nr_max_loturi = P[i+1].nr - P[i].nr - 1;
56 if (N - P[M].nr > nr_max_loturi)
57 nr_max_loturi = N - P[M].nr;
58 fout << nr_max_loturi << ’\n’;
59 //b
60 i = 1; j = 1;
61 S = 0;
62 if (i < P[j].nr)
63 l = L;
64 else
65 {
66 l = P[j].L;
67 ++j;
68 }
69 while (S + l <= D)
70 {
71 S += l;
72 ++i;
73 if (i < P[j].nr)
74 l = L;
75 else
76 {
77 l = P[j].L;
78 ++j;
79 }
80 }
81 fout << i << ’\n’;
82 fout.close();
83 return 0;
84 }

Listing 22.2.6: praslea mot.cpp


1 // Eu - Praslea O(n)
2 #include <fstream>
3
4 using namespace std;
5
6 unsigned int p[500002];
7
8 int main()
9 {
10 unsigned int n,m,i,L,d,y,z;
11 ifstream fi("praslea.in");
12 ofstream fo("praslea.out");
13
14 fi>>n>>m>>L;
15 for (i=1;i<=n;i++) p[i]=L; p[n+1]=0;
16 for (i=1;i<=m;i++)
17 {
18 fi>>y>>z;
19 p[y]=z;
20 }
21
CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 317

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 }

Listing 22.2.7: praslea ovidiu.cpp


1 // complexitate M*log M
2
3 #include <fstream>
4 #include <cstdio>
5 #include <algorithm>
6
7 using namespace std;
8
9 FILE *f=fopen("praslea.in","r");
10 ofstream g("praslea.out");
11
12 struct parcela
13 {
14 long long nr_parc,lat_parc;
15 };
16
17 long long n,m,l,i,nr_parcele,dist,locatie,gasit,k,nextt,maxim,coun=1;
18 parcela x[10002];
19
20 bool cmp(parcela a,parcela b)
21 {
22 return a.nr_parc<b.nr_parc;
23 }
24
25 int main()
26 {
27 fscanf(f,"%d%d%d",&n,&m,&l);
28 for(i=1;i<=m;i++)
29 fscanf(f,"%d%d",&x[i].nr_parc,&x[i].lat_parc);
30
31 sort(x+1,x+m+1,cmp);
32
33 x[m+1].nr_parc=n+1;
34 fscanf(f,"%d",&dist);
35 if(x[1].nr_parc>1)
36 {
37 nr_parcele=(x[1].nr_parc-1);
38 dist-=nr_parcele*l;
39 }
40
41 for(i=1;i<=m;i++)
42 {
43 if(x[i].lat_parc==x[i-1].lat_parc)
44 coun++;
45 else
46 {
47 maxim=max(maxim,coun);
48 coun=1;
CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 318

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 }

Listing 22.2.8: praslea roxana.cpp


1 #include <fstream>
2 #include <iostream>
3
4 using namespace std;
5
6 ifstream f("praslea.in");
7 ofstream g("praslea.out");
8
9 int m,n;
10 long long v[500001],l,d,d1,x,y;
11 int main()
12 {
13 int i, max,max1,t,r;
14 f>>n>>m>>l;
15 max=0;
16 for (i=1;i<=m;i++)
17 {
18 f>>x>>y;
19 if (max<x) max=x;
20 v[x]=y;
21 }
22
23 f>>d;
24 // cout<<max;
25 t=0;
26 max1=0;
27 d1=0;
28 r=0;
29 for(i=1;i<=max;i++)
30 {
31 if(v[i]==0)
32 {
33 t++;
34 v[i]=l;
CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 319

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 }

Listing 22.2.9: praslea roxana1.cpp


1 #include <fstream>
2 #include <iostream>
3
4 using namespace std;
5
6 ifstream f("praslea.in");
7 ofstream g("praslea.out");
8
9 int m,n;
10 unsigned long v[500001],l,d,d1,x,y;
11
12 int main()
13 {
14 int i, max,max1,t,r;
15 f>>n>>m>>l;
16 max=0;
17 for (i=1;i<=m;i++)
18 {
19 f>>x>>y;
20 if (max<x)
21 max=x;
22 v[x]=y;
23 }
24
25 f>>d;
26 // cout<<max;
27 t=0;
28 max1=0;
29 d1=0;
30 r=0;
31 for(i=1;i<=max;i++)
32 {
33 if(v[i]==0)
34 {
35 t++;
36 v[i]=l;
37 }
38 else
39 {
40 if (max1<t) max1=t;
CAPITOLUL 22. ONI 2014 22.2. PRASLEA - ONI 2014 320

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 }

Listing 22.2.10: praslea sanda.cpp


1 #include <iostream>
2 #include <fstream>
3 #include <algorithm>
4
5 using namespace std;
6
7 ifstream f("praslea.in");
8 ofstream g("praslea.out");
9
10 int a[500001], n,m,mar,x,y,i,j,ok,k,nr,v,aparitii[500001],s,h;
11 long l;
12
13 int main()
14 {
15 f>>n>>m>>l;//citire dimensiune vector, dimensiune parcele si latime parcele
16
17 for(i=1;i<=n;i++) a[i]=l; //toate pe latimea l
18
19 for(i=1;i<=m;i++)
20 { //citire dimensiuni parcele vecini si marcarea in vector
21 f>>x>>y;
22 a[x]=y;
23 }
24
25 f>>mar; //citire pozitie mar
26
27 // k pt vectorul aparitii si s pentru a calcula suma unde se afla marul
28 k=1;
29 s=0;
30 for(i=1;i<=n;i++)
31 { // parcurgem vectorul cu parcele
32 s=s+a[i]; // adunam sa vedem unde e marul
33 if(s==mar) v=i;
34 if(s>mar && h==0) {v=i;h=1;}
35
36 j=i; // plecam de la i sa vedem dublurile de l
37 ok=0; // ok sa ne orpim cand nu mai avem dublura
38 nr=0; // salvez numarul de dubluri de l
39
40 while(ok==0)
41 { // caut dublurile
42 if(a[j]!=a[j+1]) ok=1;
43 j++;
44 nr++;
45 }
CAPITOLUL 22. ONI 2014 22.3. TINTA - ONI 2014 321

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 }

22.2.3 *Rezolvare detaliată

22.3 tinta - ONI 2014


Problema 3 - tinta 100 de puncte
Alex are o pasiune pentru trasul la ţintă. Jucându-se cu numere,
visează la o nouă tablă pentru pasiunea sa. Tabla visată este de
formă pătrată cu n linii şi n coloane, iar numerele, de la 1 la n ˜ n,
le poziţionează ı̂n ţintă, ca ı̂n imaginea alăturată.
Alex, fiind un foarte bun ţintaş, nu nimereşte niciodată pe
pătrăţelele de pe contur. Când ţinteşte o pătrăţică din interior, el
obţine drept punctaj suma valorilor din cele opt pătrăţele vecine.

Cerinţe Figura 22.4: tinta

Cunoscând n numărul de linii şi de coloane ale ţintei:


a. Ajutaţi-l pe Alex să construiască ţinta visată.
b. Câte punctaje distincte poate să obţină Alex dacă are o singură săgeată?
c. Afişaţi punctajele distincte găsite.

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.

Restricţii şi precizări

a3 & n & 1000


aPentru prima cerinţă afişată corect se va acorda 40% din punctaj; pentru a doua cerinţă se
va acorda 20% din punctaj; pentru cea de-a treia cerinţă se va acorda 40% din punctaj.

Exemple
CAPITOLUL 22. ONI 2014 22.3. TINTA - ONI 2014 322

tinta.in tinta.out Explicaţii


3 126 Alex poate ţinti doar ı̂n pătrăţelul interior (cel pe care avem 5),
357 deci obţine un singur punctaj, iar suma este 40.
489
1
40
4 1267 Alex poate ţinti doar pătrăţelele 5, 8, 9 sau 12.
3 5 8 13
4 9 12 14
10 11 15 16
3
45 68 91

Timp maxim de executare/test: 1.0 secunde


Memorie: total 8 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 10 KB

22.3.1 Indicaţii de rezolvare

prof. Liliana Chira, Colegiul Naţional ”Mihai Eminescu” Botoşani

Soluţia 1 - 100 puncte


Se citeşte din fişier numărul n (dimensiunea ţintei).
a Soluţia problemei se bazează pe observaţia ca ţinta este pătrată, deci poate fi văzută ca o
matrice ı̂n care poziţia fiecărui pătrăţel este de forma i, j . Se poate deduce valoarea lui k ı̂n
functie de i şi j. Pentru rezolvarea problemei vom parcurge matricea pe linii şi coloane. Vom
utiliza, de exemplu, variabila i pentru deplasarea pe linii şi j pentru deplasarea pe coloane.

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ă.

Figura 22.5: tinta

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.

Soluţia 2 - 100 puncte

prof. Roxana Tı̂mplaru, Colegiul ”Ştefan Odobleja”, Craiova

a Se construieşte ţinta ı̂n matricea a, ı̂ncepând cu prima diagonală paralelă cu diagonala


secundară, se continuă cu a doua, ş.a.m.d. până la diagonala secundară. Se procedează la fel
pentru diagonalele paralele cu diagonala secundară, diagonale aflate sub aceasta;
a Se calculeză ı̂ntr-o matrice b toate valorile care s-ar obţine dacă Alex ţinteşte elementul aflat
pe aceeaşi poziţie ı̂n a:

bij  ai1j 1ai1j ai1j 1ai1j 1ai1j ai1j 1aij 1aij 1

a Rezultatul la cerinţa b) se calculează ı̂nsumând numărul de diagonale paralele cu diagonala


secundară, exceptând diagonalele pe care se află doar elemente de pe conturul matricei, adică
n  2  n  3;
a Pentru cerinţa c) se vor afişa din matricea b elementele de pe linia 2, ı̂ncepând din coloana
2, până ı̂n coloana n  2 şi elementele de pe linia n  1, coloanele 2, 3, ...,n  1.

22.3.2 Cod sursă

Listing 22.3.1: tinta.cpp


1 //prof.Liliana Chira
2 #include <cstdio>
3 #include<time.h>
4 int n,i,j,k,u,v,x,y,a[4][1001],b[1001][4],s;
5
6 int main()
7 {
8 freopen("tinta.in","r",stdin);
9 freopen("tinta.out","w",stdout);
10
11 scanf("%d",&n); // citesc datele de intrare
12
13 // generez matricea
14 for(i=1;i<=n;i++)
15 {
16 for(j=1;j<=n;j++)
17 {
18 if(i+j<=n+1)
19 {
20 if((i+j)%2==0) k=(i+j-1)*(i+j-2)/2+j;
21 else k=(i+j-1)*(i+j-2)/2+i;
22 }
23 else
24 {
25 u=n+1-i;
26 v=n+1-j;
27 if((i+j)%2==0) k=n*n+1-(u+v-1)*(u+v-2)/2-v;
28 else k=n*n+1-(u+v-1)*(u+v-2)/2-u;
29 }
30 printf("%d ",k);
31 if(i<=3 ) a[i][j]=k;
32 if(j>=n-2 ) b[i][n+1-j]=k;
33 }
34 printf("\n");
35 }
36
37 printf("%d\n",2*(n-2)-1);
38
39 for(j=2;j<n;j++)
40 {
41 s=0;
42 for(i=1;i<=3;i++)
43 for(k=j-1;k<=j+1;k++)
44 s+=a[i][k];
45
CAPITOLUL 22. ONI 2014 22.3. TINTA - ONI 2014 324

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 }

Listing 22.3.2: tinta marinel 4M.cpp


1 //prof.Marinel Serban
2 #include <fstream>
3 #include <algorithm>
4
5 using namespace std;
6
7 #define DIM 1001
8 ifstream fin("tinta.in");
9 ofstream fout("tinta.out");
10
11 int n, M[DIM][DIM], i, j, x, k, dir, X, p, u, m;
12 bool gasit;
13
14 int S[2 * DIM];
15 int dx[9] = {0, -1, -1, 0, 1, 1, 1, 0, -1};
16 int dy[9] = {0, 0, 1, 1, 1, 0, -1, -1, -1};
17
18 int main()
19 {
20 fin >> n;
21 M[1][1] = 1;
22 i = 1; j = 2; x = 2;
23 M[i][j] = x++;
24 if (n % 2 == 0) //daca n este impar
25 {
26 do
27 {
28 while (j > 1)
29 {
30 i++; j--; M[i][j] = x++;
31 }
32 if (i < n)
33 {
34 i++; M[i][j] = x++;
35 while (i > 1)
36 {
37 i--; j++; M[i][j] = x++;
38 }
39 j++; M[i][j] = x++;
40 }
41 } while (i != n);
42
43 //acum sub diagonala secundara
44 while (i != n || j != n)
45 {
46 j++; M[i][j] = x++;
47 while (j < n)
48 {
49 i--; j++; M[i][j] = x++;
50 }
51 if (i < n || j < n)
52 {
53 i++; M[i][j] = x++;
54 while (i < n)
55 {
56 i++; j--; M[i][j] = x++;
57 }
58 }
CAPITOLUL 22. ONI 2014 22.3. TINTA - ONI 2014 325

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 }

Listing 22.3.3: tinta marinel 8M.cpp


1 //prof. Marinel Serban
2 #include <fstream>
3 #include <algorithm>
4
5 using namespace std;
6
7 #define DIM 1001
8 ifstream fin("tinta.in");
9 ofstream fout("tinta.out");
10
11 int n, M[DIM][DIM], i, j, x, k, dir;
12 int S[DIM * DIM];
13
14 int dx[9] = {0, -1, -1, 0, 1, 1, 1, 0, -1};
15 int dy[9] = {0, 0, 1, 1, 1, 0, -1, -1, -1};
16
17 int main()
18 {
19 fin >> n;
20 M[1][1] = 1;
21 i = 1; j = 2; x = 2;
22 M[i][j] = x++;
23 if (n % 2 == 0) //daca n este impar
24 {
25 do
26 {
27 while (j > 1)
28 {
29 i++; j--; M[i][j] = x++;
30 }
31 if (i < n)
32 {
33 i++; M[i][j] = x++;
34 while (i > 1)
35 {
36 i--; j++; M[i][j] = x++;
37 }
38 j++; M[i][j] = x++;
39 }
40 } while (i != n);
41
42 //acum sub diagonala secundara
43 while (i != n || j != n)
44 {
45 j++; M[i][j] = x++;
46 while (j < n)
47 {
48 i--; j++; M[i][j] = x++;
49 }
50 if (i < n || j < n)
51 {
52 i++; M[i][j] = x++;
53 while (i < n)
54 {
55 i++; j--; M[i][j] = x++;
56 }
57 }
58 }
59 }
60 else //daca este par
61 {
CAPITOLUL 22. ONI 2014 22.3. TINTA - ONI 2014 327

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 }

Listing 22.3.4: tinta roxana.cpp


1 //prof.Timplaru Roxana
2 #include <iostream>
3 #include <fstream>
4 #include <iomanip>
5
6 using namespace std;
7 ifstream f("tinta.in");
8 ofstream g("tinta.out");
9
10 int a[1001][1001],b[1001][1001],n,i,j,x,l,c;
11
12 int main()
13 {
14 f>>n;
15 x=1;
16
17 for(i=1;i<=n;i++)
18 if (i%2==0)
19 { l=1;c=i;
20 for(j=1;j<=i;j++)
21 {
22 a[l][c]=x;
23 x=x+1;
24 l++;
25 c--;
26 }
27 }
28 else
29 {
30 l=i;c=1;
31 for(j=1;j<=i;j++)
32 {
33 a[l][c]=x;
34 x=x+1;
35 l--;
36 c++;
37 }
38 }
39
40 if (n%2==0)
41 for (i=2;i<=n;i++)
42 {
43 if(i%2==0)
44 {l=n;c=i;}
45 else
46 {
47 l=i;c=n;
48 }
49
50 for(j=1;j<=n-i+1;j++)
51 {
52 a[l][c]=x;
53 x++;
54 if(i%2==0) {l--;c++;}
55 else {l++;c--;}
56 }
57 }
58 else
59 for (i=2;i<=n;i++)
60 {
61 if (i%2==0) {l=i;c=n;}
62 else {l=n;c=i;}
63 for(j=1;j<=n-i+1;j++)
64 {
65 a[l][c]=x;
66 x++;
67 if (i%2==0) {l++;c--;}
68 else {l--;c++;}
69 }
70 }
CAPITOLUL 22. ONI 2014 22.3. TINTA - ONI 2014 329

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 }

22.3.3 *Rezolvare detaliată


Capitolul 23

ONI 2013

23.1 divizori - ONI 2013


Problema 1 - divizori 100 de puncte
Mihai a primit ı̂n dar un calculator care poate determina numărul de divizori ai unui număr
natural.
Singura problemă este că afişajul calculatorului ı̂i permite să lucreze numai cu numere formate
din cel mult K cifre. Pentru că la şcoală se lucrează cu numere naturale mari, adică numere
care au foarte multe cifre, Mihai s-a hotărât ca pentru un număr mare să procedeze astfel: află
numărul de divizori al numărului format doar din primele K cifre ale numărului dat. Numărul
afişat ca rezultat ı̂l completează alipind la dreapta sa următoarele cifre din numărul iniţial, până
ajunge iar la un număr format din K cifre. Acestui nou număr, ı̂i află numărul de divizori şi
repetă procedeul până la epuizarea cifrelor numărului iniţial.
Chiar dacă la un moment dat nu mai are cifre pentru a completa numărul afişat ca rezultat,
Mihai foloseşte ı̂n continuare calculatorul şi determină numărul divizorilor acestuia, continuând
până ajunge la un număr care este egal cu numărul divizorilor săi.

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

Fişierul de ieşire divizori.out va conţine trei linii:


- pe prima linie se va scrie un singur număr natural reprezentând numărul de aplicări succesive
ale procedeului de aflare a numărului de divizori descris mai sus;
- pe a doua linie sa va scrie un singur număr natural reprezentând numărul maxim de divizori;
- pe a treia linie se va scrie un singur număr natural reprezentând cel mai mic număr ce
are proprietatea că numărul său de divizori este egal cu numărul maxim de divizori determinat
anterior.

Restricţii şi precizări

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

Timp maxim de executare/test: 1.0 secunde


Memorie: total 3 MB din care pentru stivă 1 MB
Dimensiune maximă a sursei: 5 KB

23.1.1 *Indicaţii de rezolvare

23.1.2 *Cod sursă

23.1.3 *Rezolvare detaliată

23.2 remi - ONI 2013


Problema 2 - remi 100 de puncte
Andrei şi prietenii săi s-au hotărât să joace Remi. Acest joc conţine mai multe piese de aceeaşi
dimensiune, pe fiecare piesă fiind scrisă o cifră de la 0 la 9.
La ı̂nceputul jocului toate piesele se află ı̂ntr-un săculeţ de
unde fiecare jucător va extrage pe rând piesele astfel: prima
piesă extrasă o va numi ”Jolly Joker” şi o va păstra pentru a
o aşeza ulterior pe tabla de joc. Acelaşi jucător extrage apoi,
una câte una, ı̂ncă N piese din săculeţ pe care le aranjează
de la stânga la dreapta pe tabla lui de joc, ı̂n ordinea ı̂n care
le-a extras. După ce toţi jucătorii şi-au aranjat piesele, ı̂ncepe Figura 23.1: remi
jocul ı̂n care se vor respecta următoarele reguli:
a piesa ”Jolly Joker” poate fi aşezată oricând şi oriunde pe tabla jucătorului care a extras-o;
a cel mult una dintre cele N piese extrase după ”Jolly Joker” şi aşezate pe tabla de joc, poate
fi mutată de la locul ei şi aşezată ı̂n alt loc pe aceeaşi tablă.
Câştigătorul jocului este desemnat cel care poate forma, respectând regulile jocului, cel mai
mare număr, citit de la stânga la dreapta cu cifrele scrise pe cele N+1 piese aşezate pe tabla sa
de joc.

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

Fişierul de intrare remi.in conţine:


- pe prima linie o singură cifră reprezentând piesa ”Jolly Joker” extrasă de Andrei;
- pe cea de-a doua linie numărul natural N , reprezentând numărul pieselor extrase ı̂n contin-
uare, de Andrei;
- pe cea de-a treia linie, N cifre despărţite prin câte un spaţiu, reprezentând cifrele scrise pe
piesele lui Andrei, ı̂n ordinea extragerii lor şi aşezării acestora pe tabla de joc.
Date de ieşire
Fişierul de ieşire remi.out va conţine pe prima linie un singur număr natural, reprezentând
cel mai mare număr format cu cele N  1 piese de joc ale lui Andrei, respectând regulile jocului.
Restricţii şi precizări
a 1&N & 10000
Exemple
remi.in remi.out Explicaţii
3 743204 Piesa ”Jolly Joker” are cifra 3
5 Andrei a extras alte 5 piese din săculeţ ı̂n următoarea ordine: 4, 2, 7, 0
42704 şi 4.
Din cele cinci piese extrase, piesa care ı̂şi schimbă locul este cea care
conţine cifra 7.
Cel mai mare număr construit de Andrei ı̂n jocul de remi este: 74 3 204
Timp maxim de executare/test: 1.0 secunde
Memorie: total 3 MB din care pentru stivă 1 MB
Dimensiune maximă a sursei: 5 KB

23.2.1 *Indicaţii de rezolvare

23.2.2 *Cod sursă

23.2.3 *Rezolvare detaliată

23.3 tetris - ONI 2013


Problema 3 - tetris 100 de puncte
Gigel are instalat pe calculator un joc numit Tetris, ı̂n care pe o zonă dreptunghiulară cade
pe rând câte o piesă dintr-un şir de piese. Zona de joc este codificată sub forma unei table cu
N linii şi M coloane. Liniile le considerăm numerotate de la 1 la N de jos ı̂n sus, iar coloanele
de la 1 la M şi de la stânga la dreapta. Toate piesele sunt de forma unor pătrate. Ele intră ı̂n
zona de joc ı̂ncepând cu linia N şi cad către linia 1, deplasarea făcându-se pe verticală ı̂n cadrul
aceloraşi coloane. Dacă ı̂n cădere ı̂ntâlneşte o piesă introdusă anterior ı̂n joc atunci ea se va opri
exact deasupra ei, deci ı̂ncepând cu linia imediat următoare.
O piesa intră ı̂n joc doar dacă poate fi
introdusă complet pe zona delimitată de
cele N linii şi M coloane.
În desenul alăturat zona de joc are 7
linii şi 8 coloane şi ı̂n joc au intrat pe rând
zece piese, numerotate de la 1 la 10, ı̂n
ordinea introducerii lor pe tablă.
Un joc Tetris se termină când toate
piesele din i̧r s-au aşezat pe tablă sau când
piesa care urmează nu poate fi introdusă
ı̂n joc.
Figura 23.2: tetris
CAPITOLUL 23. ONI 2013 23.3. TETRIS - ONI 2013 333

Cerinţe

Realizaţi un program care identifică:


a) Numărul maxim de ordine al unei linii ocupată de o piesă;
b) Determinaţi numărul maxim de coloane alăturate ocupate de piese, ı̂n cadrul liniei deter-
minate la punctul a).

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.

Restricţii şi precizări

a 1 & toate numerele din fişierul de intrare & 1000


a Se asigură că pentru toate testele cel puţin prima piesă poate fi aşezată pe tablă
a Se asigură că numărul de ordine al coloanei pe care se ı̂ncearcă plasarea laturii stângi a piesei
este & M
a Se acordă 60% din punctajul unui test, dacă pe prima linie a fişierului de ieşire se află un
singur număr şi el reprezintă răspunsul corect la prima cerinţă. Dacă fişierul de ieşire conţine două
linii şi pe a doua linie se află un singur număr ce reprezintă răspunsul corect la a doua cerinţă se
obţine 40% din punctajul testului.

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

Timp maxim de executare/test: 2.0 secunde


Memorie: total 4 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 15 KB

23.3.1 *Indicaţii de rezolvare

23.3.2 *Cod sursă

23.3.3 *Rezolvare detaliată


Capitolul 24

ONI 2012

24.1 cartier - ONI 2012


Problema 1 - cartier 100 de puncte
Victor este un băiat deştept şi simpatic, dar care se
plictiseşte foarte uşor. Tatăl său trebuie să născocească ı̂n
permanenţă noi jocuri care să ı̂l stimuleze. Ultimul joc,
cartier, are trei niveluri şi se joacă utilizând o mulţime de
cuburi gri, toate de aceeaşi dimensiune.
La primul nivel, Victor trebuie să construiască un bloc de
formă dreptunghiulară format din m cuburi astfel ı̂ncât suma
dintre ı̂nălţimea blocului (H) şi lăţimea sa (L) să fie minimă
şi L & H. De exemplu, pentru n 6 se pot construi patru
blocuri ca ı̂n imagine, dar doar primul bloc (B1 ) respectă
condiţiile cerute. Figura 24.1: cartier
Pentru a finaliza cel de-al doilea nivel al jocului, Victor trebuie să construiască un cartier,
având la dispoziţie un număr dat de cuburi pentru fiecare bloc care formează cartierul. Pentru
construcţia fiecărui bloc se respectă cerinţele de la primul nivel al jocului. ı̂n interiorul cartierului,
blocurile sunt aşezate, ı̂n ordinea obţinerii lor, lipite unul de celălalt.
La al treilea nivel, Victor trebuie să determine un număr maxim de blocuri alăturate, astfel
ı̂ncât ı̂nălţimea primului bloc din şir şi ı̂nălţimea ultimului bloc din şir să nu fie numere prime
ı̂ntre ele.
Ajutaţi-l pe Victor să finalizeze nivelurile doi şi trei ale jocului cartier.

Cerinţe

Scrieţi un program care determină următoarele numere:


a) x, ce reprezintă numărul blocurilor de ı̂nălţime maximă construite la nivelul al doilea;
b) y, ce reprezintă suma lăţimilor blocurilor din cartierul construit la nivelul al doilea;
c) z, ce reprezintă numărul de blocuri din şirul determinat la nivelul al treilea.

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.

Restricţii şi precizări

a Numerele naturale citite aparţin intervalului 1, 100000


a Pentru rezolvarea corectă a cerinţei a) se obţine 30% din punctaj. Pentru rezolvarea corectă
a cerinţei b) se obţine 30% din punctaj. Pentru rezolvarea corectă a cerinţei c) se obţine 40% din
punctaj.

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

Timp maxim de executare/test: 0.5 secunde


Memorie: total 2 MB din care pentru stivă 1 MB
Dimensiune maximă a sursei: 5 KB

24.1.1 Indicaţii de rezolvare

prof. Ana Întuneric - Colegiul Naţional ”Ferdinand I” Bacău

Rezolvarea punctului a) presupune determinarea divizorilor numărului curent citit de pe a


doua linie a fişierului, divizori care vor constitui lăţimea şi ı̂nălţimea unui bloc. Perechea de valori
căutată are produsul egal cu numărul respectiv şi suma minimă. Ó
Se poate observa că aceşti divizori sunt cei mai apropiaţi de  numărul citit . După deter-
minarea perechii de divizori, divizorul ce reprezintă ı̂nălţimea blocului se va compara cu ı̂nălţimea
maximă şi se actualizează numărul blocurilor de ı̂nălţime maximă.
Rezolvarea punctului b) presupune adunarea lăţimilor blocurilor construite.
Rezolvarea punctului c) constă ı̂n determinarea, pentru fiecare bloc Bi a blocului-pereche Bj
cel mai apropiat de capătul din dreapta al cartierului, cu proprietatea că:
cmmdc(ı̂nălţimea blocului Bi , ı̂nălţimea blocului Bj ) j 1.

24.1.2 Cod sursă

Listing 24.1.1: cartier.cpp


1 #include <fstream>
2 #include <math.h>
3
4 using namespace std;
5
6 ifstream f("cartier.in");
7 ofstream g("cartier.out");
8
9 int n,H[100001],L,Hmax,Ltotal,nrmax,i,d,x,nec,a,b,incep,sf,sfp,Max,j;
10
11 int main()
12 {
13 f>>n;Ltotal=0;Hmax=0;
14
15 for(i=1;i<=n;i++)
16 {
17 f>>x;
18 d=(int)sqrt((double)x);
19 while(x%d!=0) d--;
20
21 if(d>x/d)
22 {
CAPITOLUL 24. ONI 2012 24.2. MEDALION - ONI 2012 336

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 }

24.1.3 *Rezolvare detaliată

24.2 medalion - ONI 2012


Problema 2 - medalion 100 de puncte
Rapunzel, frumoasa prinţesă cu păr blond, lung şi magic, se pregăteşte pentru
nunta sa cu legendarul Flynn Rider. Cu ocazia acestui eveniment, el ı̂i va dărui
prinţesei un medalion unic pe care aceasta ı̂l va purta ı̂n ziua nunţii.
Comanda pentru confecţionarea medalionului este preluată de un renumit biju-
tier al regatului care primeşte de la Flynn k cutii (numerotate de la 1 la k), fiecare
cutie conţinând foarte multe cristale, identice ca valoare. Astfel, toate cristalele din
prima cutie au valoarea 1, toate cristalele din cea de-a doua cutie au valoarea 2 şi
aşa mai departe, astfel ı̂ncât toate cristalele din ultima cutie au valoarea k.
Bijutierul va monta cristalele pe o plachetă de aur de formă pătratică
cu n rânduri de cristale, pe fiecare rând fiind montate n cristale unul
lângă altul. Acesta ia pe rând câte un cristal din fiecare cutie, ı̂n ordinea:
CAPITOLUL 24. ONI 2012 24.2. MEDALION - ONI 2012 337

1, 2, 3, ..., k, 1, 2, 3, ..., k, 1, 2, 3... şi le aşează pe placheta de aur ı̂n formă


de spirală.
Spirala porneşte din centrul medalionului unde se montează primul
cristal. Al doilea cristal se montează ı̂n dreapta primului, iar următorul
cristal, mai jos, pe rândul imediat următor. Montarea cristalelor se con-
tinuă pe acelaşi rând, mergând spre stânga, apoi ı̂n sus până la rândul
situat deasupra rândului pe care se montează primul cristal. Se pro-
cedează ı̂n continuare la fel, respectând regula de construire a spiralei:
dreapta, jos, stânga, sus şi aşa mai departe. De exemplu, pentru k 5,
cristalele se montează pe medalion ca ı̂n desenul alăturat.

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).

Restricţii şi precizări

a 2 & k & 20 , 3 & n & 301 şi 1 & p & 500000;


a numărul de cristale din fiecare cutie este suficient de mare pentru construirea medalionului;
a pentru rezolvarea corectă a cerinţei a) se acordă 40% din punctajul fiecărui test, iar pentru
rezolvarea corectă a cerinţei b) se acordă 60% din punctajul fiecărui test.

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.

Timp maxim de executare/test: 1.0 secunde


Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 5 KB

24.2.1 Indicaţii de rezolvare

prof. Cristina Iordaiche - Liceul ”Grigore Moisil” Timişoara


CAPITOLUL 24. ONI 2012 24.2. MEDALION - ONI 2012 338

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.

Numărul total de elemente situate pe primele p+1 ”spire” este egal cu


1  8  16  24  8p 1  8 ˜ p ˜ p  1©2 1  4p p  1
a elementul căutat se va afla pe ce-a de-a p  1 ”spiră”, deasupra elemen-
tului din centrul medalionului şi pentru determinarea numărului de ordine
al acestui element nu vom lua ı̂n calcul ultimele p elemente ele spirei pe care
el este situat.

24.2.2 Cod sursă

Listing 24.2.1: medalion.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream fin("medalion.in");
6 ofstream fout("medalion.out");
7
8 int a[321][321];
9 long long n,m,p,k;
10
11 void calcul()
12 {
13 long long s,max=0;
14 for(int i=1;i<=n;i++)
15 {
16 s=0;
17 for(int j=1;j<=n;j++)
18 s+=a[i][j];
19
20 if(s>max)
21 max=s;
22 }
23
24 fout<<max<<endl;
25 }
26
CAPITOLUL 24. ONI 2012 24.3. NUMAR - ONI 2012 339

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 }

24.2.3 *Rezolvare detaliată

24.3 numar - ONI 2012


Problema 3 - numar 100 de puncte
Pentru un număr dat cu k cifre c1 c2 ...ck , se numeşte algoritm de deplasare circulară spre
dreapta de la o cifră iniţială ci , la o cifră finală cj , deplasarea din cifră ı̂n cifră spre dreapta de
ci ori (1 & i, j & k). Dacă pe parcursul deplasării s-a ajuns la cifra ck , se continuă deplasarea
circulară spre dreapta cu cifra c1 .
Un număr cu k cifre se numeşte număr ”circular” dacă ı̂ndeplineşte următoarele două cerinţe:
- toate cifrele sunt nenule;
- pornind de la cifra c1 , aplicând algoritmul de deplasare circulară spre dreapta de exact k ori,
se ajunge din nou la c1 , fiecare dintre cifrele numărului fiind exact o singură dată cifră iniţială.
De exemplu, numărul 2396 este un număr ”circular”, pentru că are doar cifre nenule şi algo-
ritmul de deplasare circulară spre dreapta se aplică astfel:
CAPITOLUL 24. ONI 2012 24.3. NUMAR - ONI 2012 340

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.

Restricţii şi precizări

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.

Timp maxim de executare/test: 1.0 secunde


Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 5 KB
CAPITOLUL 24. ONI 2012 24.3. NUMAR - ONI 2012 341

24.3.1 Indicaţii de rezolvare

prof. Roxana Tı̂mplaru - ISJ Dolj

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.

24.3.2 Cod sursă

Listing 24.3.1: numar.cpp


1 #include <iostream>
2 #include <fstream>
3
4 using namespace std;
5
6 ifstream f("numar.in");
7 ofstream g("numar.out");
8
9 long a[10000];
10 int n;
11
12 void date()
13 {
14 int i;
15 f>>n;
16 for(i=0;i<n;i++)
17 f>>a[i];
18 f.close();
19 }
20
21 int cifre_repetate(long x)
22 {
23 int a[10],i;
24
25 for(i=0;i<=9;i++)
26 a[i]=0;
27
28 while(x)
29 if(a[x%10]!=0)
30 return 1;
31 else
32 {
33 a[x%10]=1;
34 x=x/10;
35 }
36
37 return 0;
38 }
39
40 long max()
41 {
42 int i; long max1,max2;
43
CAPITOLUL 24. ONI 2012 24.3. NUMAR - ONI 2012 342

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 }

24.3.3 *Rezolvare detaliată


Capitolul 25

ONI 2011

25.1 joc - ONI 2011


Problema 1 - joc 100 de puncte
Rareş şi Bogdan vor să facă mişcare ı̂n aer liber aşa că s-au
gândit la un nou joc.
Pe terenul de fotbal, ei au desenat o pistă circulară şi au
ı̂mpărţit-o ı̂n n sectoare egale, ca ı̂n desenul alăturat (unde n 16).
Ei au etichetat cele n sectoare cu numerele distincte de la 1 la n,
ı̂n sensul acelor de ceasornic.
Au stabilit ca jocul să se desfăşoare astfel:
a Se vor aşeza amândoi ı̂n sectorul numerotat cu 1, spate ı̂n
spate, astfel ı̂ncât Bogdan se va deplasa ı̂n sensul acelor de ceasor-
nic, iar Rareş ı̂n sens contrar. Figura 25.1: joc
a Prin sărituri executate simultan ı̂n anumite sectoare, copiii se vor deplasa pe pistă ı̂n sensuri
contrare şi vor executa un număr egal de sărituri.
a O săritură a lui Bogdan are ca efect deplasarea acestuia din sectorul curent, ı̂n sensul acelor
de ceasornic, avansând cu x sectoare pe pistă. De exemplu, dacă n 16 şi x 2 atunci, pornind
din sectorul 1, Bogdan se va deplasa sărind succesiv, ı̂n această ordine, ı̂n sectoarele etichetate cu:
3, 5, 7, 9, ...
a O săritură a lui Rareş are ca efect deplasarea acestuia din sectorul curent, ı̂n sens contrar
acelor de ceasornic, avansând cu y sectoare pe pistă. De exemplu, dacă n 16 şi y 3 atunci,
pornind din sectorul 1, Rareş se va deplasa sărind succesiv, ı̂n această ordine, ı̂n sectoarele: 14,
11, 8, 5, ...
a Jocul se termină când cei doi copii ajung ı̂n urma săriturilor ı̂ntr-un acelaşi sector de pe pistă
sau dacă unul dintre cei doi copii ajunge pentru a doua oară ı̂ntr-un acelaşi sector.

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ţ.

Restricţii şi precizări

344
CAPITOLUL 25. ONI 2011 25.1. JOC - ONI 2011 345

a 16 & n & 40000; 1 & x $ n; 1 & y $ n


a pentru rezolvarea corectă a primei cerinţe se acordă 20% din punctaj, pentru rezolvarea
corectă a celei de a doua cerinţe 40% din punctaj şi pentru rezolvarea corectă a celei de a treia
cerinţe 40% din punctaj (20% pentru determinarea corectă a valorii b, respectiv 20% pentru
determinarea corectă a valorii r).

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.

Timp maxim de executare/test: 1.0 secunde

25.1.1 Indicaţii de rezolvare

prof. Mincă Carmen, Colegiul Naţional de Informatică ”Tudor Vianu”, Bucureşti

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

25.1.2 Cod sursă

Listing 25.1.1: joc100 cm.CPP


1 // prof Carmen Minca // sursa 100p
2
3 #include <fstream>
4
5 using namespace std;
6
7 char v[40001];
8 long n,x,y;
9
10 ifstream f("joc.in");
11 ofstream g("joc.out");
12
13 int main()
14 { long t=0,s=0,b,r,i;
15
16 f>>n>>x>>y;
17
18 v[1]=11;
19 b=r=1;
20 t=n-1;
21
22 do
23 { s++;
24 b+=x; r-=y;
25 if(r<1)r+=n;
26 if(b>n)b-=n;
27 if(v[b]==0)t--;
28 if((v[r]==0)&&(b!=r))t--;
29 v[b]++;
30 v[r]+=10;
31 }while((b!=r)&&(v[r]/10!=2)&&(v[b]%10!=2));
32
33 g<<t<<’ ’<<s<<’ ’<<b<<’ ’<<r<<endl;
34
35 f.close();
36 g.close();
37 return 0;
38 }

Listing 25.1.2: joc100p cs.cpp


CAPITOLUL 25. ONI 2011 25.1. JOC - ONI 2011 347

1 //prof. Cristina Sichim //sursa 100p


2
3 #include <fstream>
4
5 using namespace std;
6
7 ifstream f("joc.in");
8 ofstream g("joc.out");
9
10 char s[60001];
11 long n,x,y,salt,r,b,sf,i;
12
13 int main()
14 {
15 f>>n>>x>>y;
16
17 for(i=1;i<=n;i++)
18 s[i]=’a’;
19
20 r=b=1;
21 s[1]=’x’;
22 do
23 {
24 b=b+x;
25
26 if(b>n)
27 b=b-n;
28
29 if(s[b]==’b’||s[b]==’x’)
30 sf=1;
31
32 r=r-y;
33 if(r<=0)
34 r=n+r;
35
36 if(s[r]==’r’||s[r]==’x’)
37 sf=1;
38
39 if(s[b]==’r’)
40 s[b]=’x’;
41 else
42 if(s[b]==’a’)
43 s[b]=’b’;
44
45 if(s[r]==’b’)
46 s[r]=’x’;
47 else
48 if(s[r]==’a’)
49 s[r]=’r’;
50
51 salt++;
52 } while(r!=b && !sf);
53
54 x=0;
55 for(i=1;i<=n;i++)
56 if(s[i]==’a’)
57 x++;
58
59 g<<x<<’ ’<<salt<<’ ’<<b<<’ ’<<r<<’\n’;
60 f.close();
61 g.close();
62 return 0;
63 }

Listing 25.1.3: JOC100p om.CPP


1 // prof.Ovidiu Marcu // sursa 100p
2
3 #include<stdio.h>
4
5 char a[60000];
6 long n,x,y,t,s,i,g,p1,p2;
7
8 void joc()
9 {
CAPITOLUL 25. ONI 2011 25.2. TALENT - ONI 2011 348

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 }

25.1.3 *Rezolvare detaliată

25.2 talent - ONI 2011


Problema 2 - talent 100 de puncte
Românii au talent! Atraşi de marele premiu oferit de organizatorii concursului ”Românii au
talent”, la preselecţia organizată la Piatra Neamţ au venit foarte mulţi români să demonstreze că
au talent.
La ı̂nscriere, fiecare participant a primit câte un număr de concurs, reprezentat de un număr
natural nenul. Unii dintre participanţi pot avea statut special, fiind admişi direct ı̂n semifinale,
ca urmare a rezultatelor deosebite obţinute la ediţiile anterioare, numărul de concurs primit de
aceştia având proprietatea că toate cifrele lui pot fi aranjate astfel ı̂ncăt să formeze un număr
palindrom.
Printre numerele de concurs primite de participanţii cu statut special, există numere care au
ı̂n scrierea lor zecimală un număr maxim de cifre distincte. Cel mai mic dintre aceste numere
reprezintă numărul de concurs al participantului VIP.

Cerinţe

Scrieţi un program care citeşte numărul natural n (reprezentând numărul de participanţi


ı̂nscrişi la concurs), n numere naturale (reprezentând numerele de concurs ale celor n participanţi)
şi determină:
a) numărul x de participanţi admişi direct ı̂n semifinale;
CAPITOLUL 25. ONI 2011 25.2. TALENT - ONI 2011 349

b) numărul y de concurs al participantului VIP, dacă există un astfel de participant printre


cei ı̂nscrişi.

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.

Restricţii şi precizări

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

Timp maxim de executare/test: 1.0 secunde

25.2.1 Indicaţii de rezolvare

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

25.2.2 Cod sursă

Listing 25.2.1: t cs.cpp


1 #include <fstream>
2
3 using namespace std;
4
5 ifstream f("talent.in");
6 ofstream g("talent.out");
7
8 long x,vip,p,c[10],n,maxd,d;
9
10 int pali(long x)
11 {
12 int i,k=0,nen=0;
13
14 d=0;
15 for(i=0;i<=9;i++)
16 c[i]=0;
17 while(x)
18 c[x%10]++, nen+=(x%10!=0), x=x/10;
19 for(i=0;i<=9;i++)
20 {
21 k+=(c[i]%2!=0);
22 d+=(c[i]!=0);
23 }
24 if(nen==1 && c[0]!=0)
25 return 0;
26 return (k<2);
27 }
28
29 int main()
30 {
31 f>>n;
32 while(n--)
CAPITOLUL 25. ONI 2011 25.3. XY - ONI 2011 351

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 }

25.2.3 *Rezolvare detaliată

25.3 xy - ONI 2011


Problema 3 - xy 100 de puncte
Una dintre pasiunile celor doi fraţi Rareş şi Bogdan este de a
inventa jocuri. Cel mai recent joc inventat de ei se numeşte xy şi
se joacă de către doi jucători ce completează pătrate alternativ pe
o suprafaţă dreptunghiulară ı̂mpărţită ı̂n n  m pătrate identice, ca
ı̂n figurile alăturate.
Se consideră că pătratul din colţul stânga-sus al suprafeţei este
poziţionat pe linia 1 şi coloana 1, iar pătratul din colţul dreapta-jos
este poziţionat pe linia n şi coloana m.
Se consideră mutare, etapa ı̂n care unul dintre jucători com-
pletează cel puţin un pătrat de pe suprafaţa dreptunghiulară.
Mutările se execută alternativ, astfel:
a Primul jucător alege un pătrat, ı̂l completează cu caracterul
x şi ı̂ncearcă să traseze un X cât mai mare cu centrul ı̂n pătratul Figura 25.2: xy
ales, ca ı̂n figura 3, ı̂n care pătratul ales este poziţionat pe linia 3 şi coloana 3.
a Cel de-al doilea jucător alege şi el un pătrat, ı̂l completează cu caracterul y şi ı̂ncearcă să
traseze un Y cât mai mare cu centrul ı̂n pătratul ales, ca ı̂n figura 4, ı̂n care pătratul ales este
poziţionat pe linia 3 şi coloana 3.
Tabla de joc din figurile alăturate conţine 6  5 pătrate poziţionate pe 6 linii şi 5 coloane. Cel
mai mic X, respectiv cel mai mare, care poate fi trasat pe această tablă de joc este cel din figura
1, respectiv cel din figura 3, prin completarea cu caracterul x a pătratelor necompletate, putând
fi trasat ı̂n orice loc corespunzător de pe tabla de joc.
Cel mai mic Y , respectiv cel mai mare, care poate fi trasat pe această tablă de joc prin
completarea cu caracterul y a pătratelor necompletate, este cel din figura 2, respectiv cel din
figura 4, putând fi trasat ı̂n orice loc corespunzător de pe tabla de joc.
Jocul se ı̂ncheie dacă se ajunge ı̂ntr-una dintre următoarele situaţii:
- unul dintre jucători alege ca centru un pătrat completat de oricare jucător la o mutare
anterioară;
- jucătorul ce trebuie să efectueze mutarea, completează pe tabla de joc doar pătratul ales ca
centru şi nu poate trasa X-ul sau Y -ul;
- s-au efectuat toate mutările propuse.
Pentru că cei doi copii sunt fraţi, nu-i interesează cine câştigă.

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

a numărul maxim c de pătrate completate care formează o suprafaţă dreptunghiulară pe tabla


de joc la finalul jocului.

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ţ.

Restricţii şi precizări

a 0 $ n, m, i, j $ 101 ; 0 $ i & n; 0 $ j & m; 0 $ k $ 10000;


a n, m, i, j, k sunt numere naturale;
a iniţial, toate pătratele de pe tabla de joc sunt necompletate;
a completarea unui pătrat se realizează prin scrierea caracterului x sau y ı̂n acesta, primul
jucător completând doar cu caracterul x, iar al doilea jucător doar cu caracterul y;
a fiecare jucător completează pe tablă mai ı̂ntâi pătratul ales ca centru şi apoi ı̂ncearcă trasarea
semnului său;
a ı̂n timpul unei mutări, la trasarea unui X, respectiv Y , jucătorii pot utiliza pătrate completate
ı̂ntr-o mutare anterioară, fără să le numere la această mutare;
a o suprafaţă dreptunghiulară formată din pătrate completate de pe tabla de joc poate fi
constituită din:
` cel puţin un pătrat completat
` mai multe pătrate completate situate pe o aceeaşi linie şi coloane consecutive
` mai multe pătrate completate situate pe o aceeaşi coloană şi linii consecutive
` mai multe pătrate completate situate pe linii şi coloane consecutive
a pentru rezolvarea corectă a primei cerinţei se acordă 40% din punctaj, pentru rezolvarea
corectă a celei de a doua cerinţe 30% din punctaj şi pentru rezolvarea corectă a celei de a treia
cerinţe 30% din punctaj.

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 .

A cincea mutare propusă nu se efectuează ı̂ntrucât jocul s-a ı̂ncheiat.

Timp maxim de executare/test: 0=1.0 secunde


CAPITOLUL 25. ONI 2011 25.3. XY - ONI 2011 353

25.3.1 Indicaţii de rezolvare

prof. Cristina Sichim, Colegiul Naţional ”Ferdinand I”Bacău

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

25.3.2 Cod sursă

Listing 25.3.1: XY.CPP


1 # include <fstream>
2
3 using namespace std;
4
5 ifstream f("xy.in");
6 ofstream g("xy.out");
7
8 int n,m,i,j,k,r,a[101][101],jucator=1,maxx,s,x,y,M;
9
10 int marcheaza(int jucator, int x, int y)
11 {
12 if(a[x][y]!=0) return 0;
13 int xs,xj,ys,yd,c=1;
14
15 if(jucator==1) // trasez un X
16 { a[x][y]=1;
17 xs=x-1;xj=x+1;ys=y-1;yd=y+1;
18 while(xs>0 && xj<n+1 && ys>0 && yd<m+1 && a[xs][ys]!=2 &&
19 a[xs][yd]!=2 && a[xj][ys]!=2 && a[xj][yd]!=2)
20 { c+= (a[xs][ys]==0)+(a[xs][yd]==0)+(a[xj][ys]==0)+(a[xj][yd]==0);
21 a[xs][ys]=a[xs][yd]=a[xj][ys]=a[xj][yd]=1;
22 xs--,xj++,ys--,yd++;
23 }
24 }
25 else // trasez un Y
26 {a[x][y]=2;
27 xs=x-1;xj=x+1;ys=y-1;yd=y+1;
28 while(xs>0 && xj<n+1 && ys>0 && yd<m+1 && a[xs][ys]!=1 &&
29 a[xs][yd]!=1 && a[xj][y]!=1)
30 { c+= (a[xs][ys]==0)+(a[xs][yd]==0)+(a[xj][y]==0);
CAPITOLUL 25. ONI 2011 25.3. XY - ONI 2011 354

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 }

Listing 25.3.2: XY 1.CPP


1 #include<fstream>
2
3 using namespace std;
4
5 ifstream f("xy.in");
6 ofstream g("xy.out");
7
8 int a[101][101],m,n,k;
9 int noi,total,maxim,pmax;
10 int p1,q1,p2,q2;
11
12 void pune1(int u,int v)
13 {int k,gata;
14 a[u][v]=1;
15 noi=1;
16 k=1,gata=0;
17 do
18 {if(u-k<1 ||u+k>n || v-k<1 ||v+k>m) gata=1;
19 else
20 if(a[u-k][v-k]==2||a[u-k][v+k]==2||a[u+k][v-k]==2||
21 a[u+k][v+k]==2) gata=1;
22 else {noi=noi+4-a[u-k][v-k]-a[u-k][v+k]-a[u+k][v-k]-a[u+k][v+k];
23 a[u-k][v-k]=a[u-k][v+k]=a[u+k][v-k]=a[u+k][v+k]=1;
24 k++;
25 }
26
27 }while(!gata);
28 total+=noi;
29 }
30
31 void pune2(int u,int v)
32 {int k,gata;
CAPITOLUL 25. ONI 2011 25.3. XY - ONI 2011 355

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 }

Listing 25.3.3: XY 2.CPP


1 #include<fstream>
2 #include<stdio.h>
3
4 using namespace std;
5
6 int a[101][101],m,n,k;
7 int noi,total,maxim,pmax;
8 int p1,q1,p2,q2;
CAPITOLUL 25. ONI 2011 25.3. XY - ONI 2011 356

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 }

25.3.3 *Rezolvare detaliată


Capitolul 26

ONI 2010

26.1 control - ONI 2010


Problema 1 - control 100 de puncte
Cifra de control a unui număr natural se obţine prin adunarea cifrelor numărului; dacă
rezultatul obţinut este o cifră, aceea este cifra de control a numărului dat; ı̂n caz contrar, se
calculează suma cifrelor rezultatului obţinut, aplicând ı̂n mod repetat acest procedeu până când
se obţine un rezultat de o singură cifră.
De exemplu cifra de control a numărului 998979 este 6, deoarece:
9+9+8+9+7+9 = 51, apoi
5+1 = 6

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.

Restricţii şi precizări

a 1 & a & b & 2000000000


a 1&c&9

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

Timp maxim de executare/test: 1.0 secunde

358
CAPITOLUL 26. ONI 2010 26.1. CONTROL - ONI 2010 359

26.1.1 Indicaţii de rezolvare

prof. Marinel Şerban, L. Informatică ”Gr. Moisil” Iaşi

Problema admite două tipuri de soluţii:


1. parcurgerea tuturor numerelor din intervalul a, b şi calcularea cifrei de control. (30% din
punctaj) (Sursa CONTROL2.PAS)
2. utilizarea unei formule: se observă faptul că cifra de control ae o aparitie ciclică, din 9 ı̂n 9
numere: acest lucru permite:
a) detectarea primului număr care are cifra de control cerută, apoi parcurgerea restului inter-
valului cu pasul 9 (50% din punctaj, funcţie de implementare) (Sursa CONTROL1.PAS)
b) detectarea primului număr care are cifra de control cerută, apoi utilizarea unei formule
(100% din punctaj) (Sursele CONTROL.PAS şi CONTROLD.PAS)

26.1.2 Cod sursă

Listing 26.1.1: control.cpp


1 // Implementare Robert Simoiu, 100 pct. - Tradus din Pascal in C++
2 #include <cstdio>
3
4 const char FIN[] = "control.in";
5 const char FOU[] = "control.out";
6
7 int a, b, c, Nr, cc, n;
8
9 int main()
10 {
11 freopen(FIN,"r",stdin);
12 freopen(FOU,"w",stdout);
13
14 scanf("%d %d %d", &a, &b, &c); // citesc datele de intrare
15
16 if (c > b)
17 printf("0");
18 else
19 {
20 // caut primul, apoi aplic formula
21 Nr = a - 1;
22 do
23 {
24 cc = ++Nr; // salvez numarul in cc = cifra de control
25 do
26 {
27 n = cc; // pastrez vechea cifra de control pentru lucru
28 cc = 0; // o reinitializez cu 0 - aici calculez suma cifrelor
29 while ( n )
30 {
31 cc += n % 10; // aduna ultima cifra
32 n /= 10; // scapa de ea
33 }
34 }
35 while ( cc >= 10 );// pana cand am obtinut o cifra de control < 10
36 }
37 while ( cc != c ); // pana cand am gasit primul
38
39 printf ("%d",(b - Nr) / 9 + 1 );
40 }
41
42 return 0;
43 }

26.1.3 *Rezolvare detaliată


CAPITOLUL 26. ONI 2010 26.2. FIGURA - ONI 2010 360

26.2 figura - ONI 2010


Problema 2 - figura 100 de puncte
Dintr-o foaie de matematică pe care se află D  D pătrăţele aranjate ı̂n D linii şi D coloane
a fost decupată o figură. Figura decupată este compactă (nu are găuri) şi este formată din N
pătrăţele de pe foaie.

Cerinţe

Scrieţi un program care să determine perimetrul figurii decupate.

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.

Restricţii şi precizări

a 1 & D & 20
a 1&N &D˜D
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

Timp maxim de executare/test: 1.0 secunde

26.2.1 Indicaţii de rezolvare

prof. Emanuela Cerchez, L. Informatică ”Gr. Moisil” Iaşi

Idee 1 (Em. Cerchez)


Vom reţine pătrăţele decupate (prin coordonatele lor: linie, coloană) ı̂ntr-un vector. Astfel,
fiecare pătrăţel poate fi identificat printr-un număr de la 1 la n (poziţia sa ı̂n vector).
Considerăm iniţial că perimetrul figurii este 4n (n pătrăţele cu câte 4 laturi).
Analizăm apoi toate perechile distincte i, j  de pătrăţele (1 & i $ j & n). Dacă pătrăţelul i
şi pătrăţelul j au o latură comună (sunt vecine, adică se află pe aceeaşi linie pe poziţii alăturate,
sau pe aceeaşi coloană pe poziţii alăturate) din perimetru scădem 2 (lungimile celor 2 laturi, care
sunt interioare).
Idee 2 (Dana Lica)
Într-o matrice cu elemente logice (true-false) codificăm cu false pătrăţele decupate.
Pentru a determina perimetrul vom traversa matricea atât pe linii cât şi pe coloane.
La traversarea pe linii vom proceda ı̂n felul următor: pentru fiecare linie determinăm numărul
s de secvenţe compacte de elemente egale cu false. Valoarea perimetrului creşte cu s ˜ 2.
În mod identic vom proceda pentru coloane.
Idee 3 (Marinel şerban)
CAPITOLUL 26. ONI 2010 26.3. JOC - ONI 2010 361

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.

26.2.2 Cod sursă

Listing 26.2.1: FIGURA.CPP


1 //Em. Cerchez
2 #include <stdio.h>
3
4 #define DMAX 101
5 #define ABS(x) (((x)>=0)?(x):(-(x)))
6
7 int n, P, D;
8 int L[DMAX*DMAX], C[DMAX*DMAX];
9
10 int vecin(int i, int j);
11
12 int main()
13 {
14 int i, j;
15
16 freopen("figura.in", "rt", stdin);
17 freopen("figura.out", "wt", stdout);
18
19 scanf("%d", &D);
20 scanf("%d", &n);
21 for (i = 0; i < n; ++i)
22 scanf("%d %d", &L[i], &C[i]);
23
24 P=4*n;
25
26 //elimin din perimetru laturile interioare
27 for (i=0; i<n; ++i)
28 for (j=i+1; j<n; ++j)
29 if (vecin(i,j)) P-=2;
30
31 printf("%d\n", P);
32 return 0;
33 }
34
35 int vecin(int i, int j)
36 {
37 if (L[i]==L[j] && ABS(C[i]-C[j])==1) return 1;
38 if (C[i]==C[j] && ABS(L[i]-L[j])==1) return 1;
39 return 0;
40 }

26.2.3 *Rezolvare detaliată

26.3 joc - ONI 2010


Problema 3 - joc 100 de puncte
Când Andrei rămâne acasă cu bunicul lui, acesta ı̂i aduce o cutie de jetoane din plastic, de
diferite culori.
CAPITOLUL 26. ONI 2010 26.3. JOC - ONI 2010 362

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ţ.

Restricţii şi precizări

a 1 & N & 60000


a Nu există două culori pentru care jetoanele să fie ı̂n număr egal.
a Se acordă 30% din punctaj pentru determinarea corectă a numărului de culori. Se acordă
50% din punctaj pentru determinarea corectă a numărului de culori, precum şi a dimensiunii
maxime a laturii pătratului format. Se acordă punctajul integral pentru rezolvarea tuturor celor
3 cerinţe.

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

Timp maxim de executare/test: 1.0 secunde

26.3.1 Indicaţii de rezolvare

prof. Liliana Ursache, C. N. ”Ferdinand I” Bacău


CAPITOLUL 26. ONI 2010 26.3. JOC - ONI 2010 363

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).

26.3.2 Cod sursă

Listing 26.3.1: JOC EM.CPP


1 //Em. Cerchez
2
3 #include <fstream>
4 #include <math.h>
5
6 using namespace std;
7
8 unsigned int uz[10];
9 int co[10];
10 int c;
11 unsigned int n, maxx;
12
13 int main()
14 {
15 unsigned int i, j, k, x, aux;
16
17 ifstream fin("joc.in");
18 ofstream fout("joc.out");
19
20 fin>>n;
21 for (i=0; i<n; i++)
22 {
23 fin>>x;
24 uz[x]++;
25 }
26 for (i=1; i<10; i++)
27 if (uz[i]) c++;
28 fout<<c<<’\n’;
29
30 maxx=sqrt(n);
31 fout<<maxx<<’\n’;
32
33 for (i=1; i<=9; i++) co[i]=i;
34 for (i=1; i<9; i++)
35 for (j=i+1; j<=9; j++)
36 if (uz[co[i]]<uz[co[j]])
37 {aux=co[i]; co[i]=co[j]; co[j]=aux;}
38
39 k=1;
40 for (i=0; i<maxx; i++)
41 {
42 for (j=0; j<maxx; )
43 if (uz[co[k]])
44 {fout<<co[k]; uz[co[k]]--; j++;}
45 else
46 k++;
47 fout<<’\n’;
48 }
49
50 fout.close();
51 return 0;
52 }

Listing 26.3.2: joc liliana.cpp


1 //L. Ursache
CAPITOLUL 26. ONI 2010 26.3. JOC - ONI 2010 364

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

26.3.3 *Rezolvare detaliată


366
Appendix A

”Instalare” C++

Ca să putem ”lucra” cu C++ avem nevoie de

ˆ un compilator pentru C++, şi

ˆ un IDE (Integrated Development Enviroment) pentru C++.

A.1 Kit OJI 2017


Poate că cel mai uşor este să se descarce fişierul
http://www.cnlr.ro/resurse/download/Kit_OJI_2017.rar
https://cdn.kilonova.ro/p/WXbRLG/Kit_OJI_2017.rar
http://olimpiada.info/oji2018/Kit_OJI_2017.rar
https://www.liis.ro/Documents/download/Kit_OJI_2017.rar
folosit de către elevi la şcoală şi la olimpiade.

Fişierele din arhivă sunt:

Figura A.1: Fişierele din Kit OJI 2017

Se lansează ı̂n execuţie fişierul OJIkit 2017.exe.

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

Există numeroase alternative la CodeBlocks: Dev-C++, Microsoft Visual Studio, Eclipse,


NetBeans, CodeLite, CLion, KDevelop, etc.

367
APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 368

Kitul Kit_OJI_2017 se instalează implicit pe C:¯OJI¯


26
t IDE-ul Code::Blocks ,
t compilatorul pentru C: gcc.exe,
27
t compilatorul pentru C++: g++.exe
t make.exe
t gdb.exe
t şi... altele!

La sfârşitul instalării apar pe ecran două link-uri:

Figura A.2: CodeBlocks & C++ Reference

Figura A.3: Ce conţine C:¯ OJI ¯

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

A.1.2 Folder de lucru

Figura A.4: Folder de lucru

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.

Acum, să intrăm ı̂n folderul Programe C++.

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

Figura A.5: New -¿ Text document

Figura A.6: Schimbare nume fişier şi nume extensie fişier


APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 371

Figura A.7: Confirmare schimbare extensie ı̂n .cpp

Figura A.8: Pregătit pentru Code::Blocks

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.

A.1.3 Utilizare Code::Blocks

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

Figura A.10: Primul cod de program C++ ı̂n Code::Blocks

Figura A.11: Build - compilare


APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 373

Figura A.12: 0 error(s), 0 warning(s)

Figura A.13: Run - execuţie


APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 374

Figura A.14: Executat corect: a făcut “nimic”

A.1.4 Setări Code::Blocks


De preferat este să lăsăm setările implicite (sunt stabilite totuşi de nişte specialişti!) dar, dacă
vrem, putem să umblăm şi noi prin setări!

Figura A.15: Settings  % Compiler


APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 375

Figura A.16: Toolchain executables

Figura A.17: Unde sunt acele programe


APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 376

A.1.5 Multe surse ı̂n Code Blocks


Settings Environment: pe calculatorul meu setările sunt:

Figura A.18: Multe surse ı̂n Code Blocks - setări

Dacă avem fişierele p01.cpp, ..., p05.cpp, ı̂n folderul nostru de lucru, şi facem dublu-click pe
fiecare ... vor apărea toate ...

Figura A.19: Multe surse in Code Blocks - exemple


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 377

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

Se dezarhivează şi se mută folderul mingw64 pe C: sau D: sau ...


Eu l-am dezarhivat pe cel mai mic şi l-am pus pe D:

Figura A.20: mingw64 pe D:

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

Figura A.21: search path

Apare fereastra “System properties”:

Figura A.22: System properties –¿ Advanced

Fereastra este poziţionată pe tab-ul “Advanced”. Se selectează “Environment Variables”.


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 379

Figura A.23: Environment Variables

Se selecteaza “Path” şi click pe “Edit”. Apare fereastra “Edit Environment Variables”

Figura A.24: Edit Environment Variables –¿ New

Se selectează “New”, se scrie calea D:¯mingw64¯bin şi se finalizează cu click pe “OK”,


“OK”, ..., “OK” până la sfârşit!
Se verifică calea şi versiunea pentru “gcc”:

ˆ C:¯path

ˆ C:¯gcc –version (Atentie! sunt 2 caractere - consecutive)


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 380

Figura A.25: Calea şi versiunea pentru gcc

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).

Observatie: Pentru Windows 11

"Setting the path and variables in Windows 11

In the System > About window,


click the Advanced system settings link
at the bottom of the Device specifications section.

In the System Properties window,


click the Advanced tab,
then click the Environment Variables button
near the bottom of that tab."

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

Figura A.26: Settings –¿ Compiler

Figura A.27: Toolchain executables –¿ Auto-detect


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 382

Figura A.28: New –¿ Text Document

Figura A.29: New text Document.txt

Figura A.30: Schimbare nume şi extensie


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 383

Figura A.31: Moore apps

Figura A.32: Look for another app


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 384

Figura A.33: Cale pentru codeblocks.exe

Figura A.34: Selectare codeblocks.exe


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 385

Figura A.35: Editare test01.cpp

Figura A.36: Compilare test01


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 386

Figura A.37: Mesaje după compilare

Figura A.38: Execuţie test01


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 387

Figura A.39: Rezultat execuţie test01

Figura A.40: Fişiere apărute după compilare!

Figura A.41: Creare test02.cpp gol! + ¡dublu click¿ sau ¡Enter¿


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 388

Figura A.42: Lista programelor de utilizat

Figura A.43: Selectare Code::Blocks IDE pentru fişierele .cpp

Figura A.44: Editare+Compilare+Execuţie pentru test02


APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 389

Figura A.45: Selectare tab ce conţine test01.cpp


Appendix B

Exponenţiere rapidă

B.1 Analogie baza 2 cu baza 10

Figura B.1: Analogie B2 cu B10

Î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

B.2 Notaţii, relaţii şi formule


234 1˜1281˜641˜320˜161˜80˜41˜20˜1
a a
1˜128 1˜64 1˜32 0˜16 1˜8 0˜4 1˜2 0˜1
a ˜ a ˜ a ˜ a ˜ a ˜ a ˜ a ˜ a
128 1 64 1 32 1 16 0 8 1 4 0 2 1 1 0
a  ˜ a  ˜ a  ˜ a  ˜ a  ˜ a  ˜ a  ˜ a  .
k
2
Dacă notăm ak a atunci
234 1 1 1 0 1 0 1 0
a a7  ˜ a6  ˜ a5  ˜ a4  ˜ a3  ˜ a2  ˜ a1  ˜ a0  .
2
Şirul a0 , a1 , a2 , ... se obţine uşor prin ridicări la putere ak ak1 .

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:

ek nk %2 , (restul ı̂mpărţirii!) k '0


ek 1 0
Dacă notăm şi produsul parţial pk ak  ˜ ... ˜ a1  ˜ a0 
obţinem ı̂n final relaţiile:

~
„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.3 Pregătire pentru scrierea codului!


Relaţia nk nk1 ©2 ı̂nseamnă că nnou nvechi ©2 (sunt explicaţii pentru ı̂ncepători ... nu pentru
avansaţi!) şi se poate programa sub forma n=n/2;
2 2
Relaţia ak ak1 ı̂nseamnă că anou avechi şi se poate programa sub forma a=a*a;
Relaţia pk pk1 ˜ ak ı̂nseamnă că pnou pvechi ˜ anou şi se poate programa sub forma p=p*a;
Relaţia pk pk1 ı̂nseamnă că pnou pvechi şi se poate programa sub forma p=p; care
ı̂nseamnă că nu se schimbă p, deci ... mai bine nu mai scriem nicio instrucţiune!
APPENDIX B. EXPONENŢIERE RAPIDĂ B.4. CODUL 392

B.4 Codul
Codul pentru relaţiile (B.2.1) devine:

Listing B.4.1: exponentiere rapida1.cpp


1 #include<iostream> // actualizare p dupa actualizare a si n
2
3 using namespace std;
4
5 int exponentiere_rapida(int a, int n) // p=aˆn
6 {
7 int nk1, nk;
8 int ak1, ak;
9 int ek1, ek;
10 int pk1, pk;
11
12 int k=0;
13 nk1=n;
14 ak1=a;
15 ek1=nk1%2;
16 if(ek1==1)
17 pk1=ak1;
18 else
19 pk1=1;
20
21 while(nk1>1)
22 {
23 k++;
24 nk=nk1/2;
25 ak=ak1*ak1;
26 ek=nk%2;
27 if(ek==1)
28 pk=pk1*ak;
29 else
30 pk=pk1;
31
32 // devin valori "vechi" inainte de noua actualizare
33 nk1=nk;
34 ak1=ak;
35 ek1=ek;
36 pk1=pk;
37 }
38
39 return pk;
40 }
41
42 int main()
43 {
44 int a=2;
45 //int n=234; // aˆn = prea mare !!!
46 //int n=30;
47 //int n=6; // par: 2ˆ6 = 64 ... usor de verificat!
48 int n=5; // impar: 2ˆ5 = 32 ... usor de verificat!
49
50 int rez=exponentiere_rapida(a,n);
51
52 cout<<a<<"ˆ"<<n<<" = "<<rez<<"\n";
53
54 return 0;
55 }
56 /*
57 2ˆ30 = 1073741824
58
59 Process returned 0 (0x0) execution time : 0.076 s
60 Press any key to continue.
61 */

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

Listing B.4.2: exponentiere rapida2.cpp


1 #include<iostream> // actualizare p inainte de actualizare a si n
2
3 using namespace std;
4
5 int exponentiere_rapida(int a, int n) // p=aˆn
6 {
7 int nk1, nk;
8 int ak1, ak;
9 int ek1, ek;
10 int pk1, pk;
11
12 nk1=n;
13 ak1=a;
14 pk1=1;
15
16 while(nk1>0)
17 {
18 ek=nk1%2;
19 if(ek==1)
20 pk=pk1*ak1;
21 else
22 pk=pk1;
23 ak=ak1*ak1;
24 nk=nk1/2;
25
26 // devin valori "vechi" inainte de noua actualizare
27 nk1=nk;
28 ak1=ak;
29 pk1=pk;
30 }
31
32 return pk;
33 }
34
35 int main()
36 {
37 int a=2;
38 //int n=234; // aˆn = prea mare !!!
39 //int n=30;
40 int n=6; // par: 2ˆ6 = 64 ... usor de verificat!
41 //int n=5; // impar: 2ˆ5 = 32 ... usor de verificat!
42
43 int rez=exponentiere_rapida(a,n);
44
45 cout<<a<<"ˆ"<<n<<" = "<<rez<<"\n";
46
47 return 0;
48 }
49 /*
50 2ˆ30 = 1073741824
51
52 Process returned 0 (0x0) execution time : 0.076 s
53 Press any key to continue.
54 */

~
„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:

Listing B.4.3: exponentiere rapida3.cpp


1 #include<iostream> // actualizare p inainte de actualizare a si n
2 // ... si simplificarea codului ...
3
4 using namespace std;
5
6 int exponentiere_rapida(int a, int n) // p=aˆn
7 {
8 int nk;
9 int ak;
10 int ek;
11 int pk;
12
13 nk=n;
14 ak=a;
15 pk=1;
16
17 while(nk>0)
18 {
19 ek=nk%2;
20 if(ek==1)
21 pk=pk*ak;
22 else
23 pk=pk; // nu are rost ... !!!
24 ak=ak*ak;
25 nk=nk/2;
26 }
27
28 return pk;
29 }
30
31 int main()
32 {
33 int a=2;
34 //int n=234; // aˆn = prea mare !!!
35 //int n=30;
36 int n=6; // par: 2ˆ6 = 64 ... usor de verificat!
37 //int n=5; // impar: 2ˆ5 = 32 ... usor de verificat!
38
39 int rez=exponentiere_rapida(a,n);
40
41 cout<<a<<"ˆ"<<n<<" = "<<rez<<"\n";
42
43 return 0;
44 }
45 /*
46 2ˆ30 = 1073741824
47
48 Process returned 0 (0x0) execution time : 0.076 s
49 Press any key to continue.
50 */

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:

Listing B.4.4: exponentiere rapida MOD.cpp


1 #include<iostream>
2
3 using namespace std;
4
5 int MOD=1000;
6 int nropr; // numar operatii (inmultiri) la exponentiere rapida
7
8 int exponentiere_rapida(int a, int n) // p=aˆn
9 {
10 int p = 1;
11 while(n>0)
12 {
13 if(n % 2 == 1) p = (p * a)%MOD;
APPENDIX B. EXPONENŢIERE RAPIDĂ B.5. CHIAR ESTE RAPIDĂ? 395

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 */

B.5 Chiar este rapidă?


De ce se numeşte ”rapidă”?
1 000 000 000
Să presupunem că vrem să calculăm 1234 şi pentru că rezultatul are foarte multe
cifre ... ne vom mulţumi, la fiecare calcul, cu ultimele 3 cifre!
Aceasta este metoda ”naivă”:

Listing B.5.1: exponentiere naiva MOD.cpp


1 #include<iostream>
2
3 using namespace std;
4
5 int MOD=1000;
6 int nropn=0; // numar operatii (inmultiri) la exponentiere naiva
7
8 int exponentiere_naiva(int a, int n) // p=aˆn
9 {
10 int p = 1;
11 for(int k=1; k<=n; k++)
12 {
13 p=(p*a)%MOD;
14 nropn=nropn+1;
15 }
16 return p;
17 }
18
19 int main()
20 {
21 int a=1234;
22 int n=1e+9; // 10ˆ9
23 int rezn; // rezultat exponentiere naiva
24
25 rezn=exponentiere_naiva(a,n);
26
27 cout<<"rezn = "<<rezn<<" nropn = "<<nropn<<"\n";
28
29 return 0;
30 }
31 /*
32 rezn = 376 nropn = 2000000000
33
34 Process returned 0 (0x0) execution time : 21.239 s
35 Press any key to continue.
36 */
APPENDIX B. EXPONENŢIERE RAPIDĂ B.6. REZUMAT INTUITIV! 396

Iar aceasta este metoda ”rapidă”:

Listing B.5.2: exponentiere rapida MOD.cpp


1 #include<iostream>
2
3 using namespace std;
4
5 int MOD=1000;
6 int nropr; // numar operatii (inmultiri) la exponentiere rapida
7
8 int exponentiere_rapida(int a, int n) // p=aˆn
9 {
10 int p = 1;
11 while(n>0)
12 {
13 if(n % 2 == 1) p = (p * a)%MOD;
14 a = (a * a)%MOD;
15 n = n / 2;
16 nropr=nropr+6; // n%2, p*a, ..%MODa*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.*/

Numărul de operaţii:
ˆ cu metoda naivă acest număr este 2 000 000 000
ˆ cu metoda rapidă este 180.

Timpul de execuţie (pe calculatorul pe care am testat eu!):


ˆ cu metoda naivă este 21.239 secunde
ˆ cu metoda rapidă este 0.021 secunde

deci ... cam de 1000 de ori mai rapidă!

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)!

B.6 Rezumat intuitiv!


Revenind la relaţia
234 128 1 64 1 32 1 16 0 8 1 4 0 2 1 1 0
a a  ˜ a  ˜ a  ˜ a  ˜ a  ˜ a  ˜ a  ˜ a 

să privim cu atenţie ce este aici!


Putem calcula uşor acest produs de la dreapta spre stânga!
2 4 8 16 32 64 128
Secvenţa a , a , a , a , a , a , a se poate genera cu instrucţiunea a=a*a;
Puterile expresiilor (marcate cu roşu, cele care sunt ı̂ntre paranteze) se obţin (tot de la dreapta
spre stânga) prin ı̂mpărţiri succesive ale lui n la 2 şi preluând restul. Dacă restul este 0 atunci
0
puterea respectivă este 0 iar ... 1 ... deci, nu mai apare ı̂n produs!
APPENDIX B. EXPONENŢIERE RAPIDĂ B.6. REZUMAT INTUITIV! 397

Asta este tot!


Deci, secvenţa de cod este:

Listing B.6.1: secventa cod.cpp


1 int p = 1;
2 while(n>0)
3 {
4 if(n % 2 == 1) p = (p * a);
5 a = a * a;
6 n = n / 2;
7 }

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

[6] Calude C.; Teoria algoritmilor, Ed. Universităţii Bucureşti, 1987


[7] Cerchez, E., Şerban, M.; Informatică - manual pentru clasa a X-a., Ed. Polirom, 2000
[8] Cerchez, E.; Informatică - Culegere de probleme pentru liceu, Ed. Polirom, 2002
[9] Cerchez, E., Şerban, M.; Programarea ı̂n limbajul C/C++ pentru liceu, Ed. Polirom, 2005
[10] Cori, R.; Lévy, J.J.; Algorithmes et Programmation, Polycopié, version 1.6;
http://w3.edu.polytechnique.fr/informatique/
[11] Cormen, T.H., Leiserson C.E., Rivest, R.L.; Introducere ı̂n Algoritmi, Ed Agora, 2000
[12] Cormen, T.H., Leiserson C.E., Rivest, R.L.; Pseudo-Code Language, 1994
[13] Cristea, V.; Giumale, C.; Kalisz, E.; Paunoiu, Al.; Limbajul C standard, Ed. Teora, Bucureşti,
1992
[14] Erickson J.; Combinatorial Algorithms; http://www.uiuc.edu/˜jeffe/
[15] Flanagan, D.; Java in a Nutshell, O’Reilly, 1997.
[16] Giumale C., Negreanu L., Călinoiu S.; Proiectarea şi analiza algoritmilor. Algoritmi de
sortare, Ed. All, 1997
[17] Halim S., Halim F., Competitive programming, 2013
[18] Knuth, D.E.; Arta programării calculatoarelor, vol. 1: Algoritmi fundamentali, Ed. Teora,
1999.
[19] Knuth, D.E.; Arta programarii calculatoarelor, vol. 2: Algoritmi seminumerici, Ed. Teora,
2000.
[20] Knuth, D.E.; Arta programarii calculatoarelor, vol. 3: Sortare şi căutare, Ed. Teora, 2001.

[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

[31] Răbâea, A.; https://math.univ-ovidius.ro/Doc/Admitere/CentruPregatire


/2007/Info/Rezolvari_C10.pdf
[32] Răbâea, A.; https://math.univ-ovidius.ro/Doc/Admitere/CentruPregatire
/2007/Info/Rezolvari_C11.pdf

[33] Răbâea, A.; https://math.univ-ovidius.ro/Doc/Admitere/CentruPregatire


/2007/Info/Rezolvari_Baraj.pdf
[34] Skiena S.S., Revilla M.A.; Programming challenges - The Programming Contest Training
Manual, Springer, 2003
[35] Tomescu, I.; Probleme de combinatorică şi teoria grafurilor, Editura Didactică şi Pedagogică,
Bucureşti, 1981
[36] Tomescu, I.; Leu, A.; Matematică aplicată ı̂n tehnica de calcul, Editura Didactică şi Peda-
gogică, Bucureşti, 1982
[37] Tudor, S.; Informatică - profilul real intensiv, varianta C++; Editura L&S, Bucureşti, 2004
[38] Tudor, S.; Hutanu, V,; Informatică intensiv; Editura L&S, Bucureşti, 2006
[39] Văduva, C.M.; Programarea in JAVA. Microinformatica, 1999
[40] Vişinescu, R.; Vişinescu, V.; Programare dinamică - teorie şi aplicaţii; GInfo nr. 15/4 2005
[41] Vlada, M.; Conceptul de algoritm - abordare modernă, GInfo, 13/2,3 2003
[42] Vlada, M.; Grafuri neorientate şi aplicaţii. Gazeta de Informatică, 1993
[43] Vlada, M.; Gândirea Algoritmică - O Filosofie Modernă a Matematicii şi Informaticii, CNIV-
2003, Editura Universităţii din Bucureşti, 2003
[44] Weis, M.A.; Data structures and Algorithm Analysis, Ed. The Benjamin/Cummings Pub-
lishing Company. Inc., Redwoods City, California, 1995.
[45] Winston, P.H., Narasimhan, S.; On to JAVA, Addison-Wesley, 1996
[46] Wirth N.; Algorithms + Data Structures = Programs, Prentice Hall, Inc 1976
[47] *** - Gazeta de Informatică, Editura Libris, 1991-2005
[48] *** - https://github.com/DinuCr/CS/blob/master/Info/stuff%20stuff/Re
zolvari_C09.pdf
[49] *** - https://dokumen.tips/documents/rezolvaric09.html
[50] *** - https://www.scribd.com/doc/266218102/Rezolvari-C09
[51] *** - https://www.scribd.com/document/396362669/Rezolvari-C10
[52] *** - https://www.scribd.com/document/344769195/Rezolvari-C11
[53] *** - https://www.scribd.com/document/364077679/Rezolvari-C11-pdf

[54] *** - https://needoc.net/rezolvari-c11-pdf


BIBLIOGRAFIE BIBLIOGRAFIE 401

[55] *** - https://vdocumente.com/algoritmi-i-structuri-de-date.html


[56] *** - https://pdfslide.net/documents/algoritmi-si-structuri-de-dat
e-1-note-de-cuprins-1-oji-2002-clasa-a-ix-a-1-11.html
[57] *** - https://www.infoarena.ro/ciorna

[58] *** - https://infoarena.ro/olimpici


[59] *** - https://www.infogim.ro/
[60] *** - https://www.pbinfo.ro/

[61] *** - http://www.cplusplus.com/


[62] *** - http://www.cplusplus.com/doc/tutorial/operators/
[63] *** - http://www.info1cup.com/
[64] *** - http://www.olimpiada.info/

[65] *** - http://www.usaco.org/


[66] *** - http://algopedia.ro/
[67] *** - http://campion.edu.ro/
[68] *** - http://varena.ro/
[69] *** - http://rmi.lbi.ro/rmi_2019/
[70] *** - https://codeforces.com/
[71] *** - https://cpbook.net/
[72] *** - https://csacademy.com/
[73] *** - https://gazeta.info.ro/revigoram-ginfo/
[74] *** - https://oj.uz/problems/source/22
[75] *** - https://profs.info.uaic.ro/˜infogim/2019/index.html
[76] *** - https://wandbox.org/
[77] *** - https://en.cppreference.com/w/cpp/language/operator_alternative
[78] *** - https://en.cppreference.com/w/cpp/algorithm
[79] *** - https://www.ejoi2019.si/
[80] *** - https://en.wikipedia.org/wiki/Algorithm
[81] *** - https://en.wikipedia.org/wiki/List_of_algorithms
[82] *** - https://en.wikipedia.org/wiki/List_of_data_structures
[83] *** - https://cs.pub.ro/images/NewsLabsImages/Teste-admitere-informa
tica-UPB-2020.pdf
Lista autorilor
problemelor şi indicaţiilor

Adrian Niţă, 200 Gheorghe Dodescu, vi


Ana Întuneric, 335
Ana-Maria Arişanu, 8, 64, 84, 196 Ion Văduva, vi
Arişanu Miana, 219
Liliana Chira, 322
Cardas Cerasela Daniela, 107 Liliana Ursache, 362
Carmen Mincă, 293, 345
Constantin Tudor, vi Marinel Şerban, 117, 190, 219, 300, 359
Cristina Iordaiche, 13, 32, 69, 235, 310, 337 Marius Nicoli, 150, 225
Cristina Sichim, 110, 353
Raluca Costineanu, 22
Daniela Lica, 193 Rodica Pintea, 211
Roxana Tı̂mplaru, 96, 133, 223, 341
Emanuela Cerchez, 219, 360
Eugen Nodea, 215 Septimiu Sorin Groza, 349
Susana Gălăţan, 159
Flavius Boian, 206, 254
Florentina Ungureanu, 277 Violeta Grecea, 42, 205

402
What’s the next?
ORNL’s Frontier First to Break the Exaflop Ceiling

H T T P S :// E N . W I K I P E D I A . O R G / W I K I /F R O N T I E R _( S U P E R C O M P U T E R )#/ M E D I A /F I L E :F R O N T I E R _S U P E R C O M P U T E R _(2). J P G

Over time
the following steps
will lead you to the value
you seek for yourself
now!

S-ar putea să vă placă și