You are on page 1of 447

Informatică

Olimpiada - cls5

2023-10
PROBLEME DE INFORMATICĂ
date la olimpiade

OJI + ONI
ı̂n

**** 2023 2022 2021 2020


2019 2018 2017 2016 2015
2014 2013 2012 2011 2010

Dacă ştii să rezolvi problemele date ı̂n ultimii 10-20 de ani
atunci vei şti să rezolvi problemele care se vor da ı̂n acest an!

... draft (ciornă) ...


*** Nobody is perfect ***

Adrian Răbâea, Ph.D.

https://www.scribd.com/user/552245048/Adi-Rabaea (sprijin financiar![ 19 ])

13:15 happy birthday 2023-10-10


Figura 1: Descompunerea canonică a lui f

”O imagine valorează
cât 1000 de cuvinte!” 1

x1 x1
x3 x3
x2 x2
elevii f = aleg ”şeful” elevi
ı̂n clasă ı̂n clasă
fac echipe echipei
y1 y1
y3 y3
y2 y2

p : proiecţia canonică (se fac listele) i : injecţia canonică


(şefii revin)
(ı̂n clasă)
xr x1

liste cu elevi f¯ = predau lista şefi de echipe


”şefului” echipei Im f 
yr y1

Figura 2: Un desen ... i ` f¯ ` p f

1
I.d.k.: ”I don’t know who the author is.”
Dedication

I would like to dedicate this book ...

a ”to myself” ...


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

a to people impacted by the book


a to my nephew Adam.

( in ascending order! )

2
https://www.femalefirst.co.uk/books/carol-lynne-fighter-1034048.html
3
https://otiliaromea.bandcamp.com/track/dor-de-el
4
https://en.wikipedia.org/wiki/To_be,_or_not_to_be
5
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!.
6
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
7 8
dificilă! :-) Vezi, de exemplu, IOI2020 şi IOI2019 , IOI2015 . (Numai GCC a fost mereu!)
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
9
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
10
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!).


6
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’ ...
7
IOI2019 şi IOI2020 au a permis utilizarea limbajelor de programare C++ şi Java
8
IOI2015 a permis utilizarea limbajelor de programare C++, Java, Pascal, Python şi Ruby
9
Vezi cele 5 secunde pentru Timp maxim de executare/test din problema ”avârcolaci” - ONI2014 clasa a 11-a
10
https://en.wikipedia.org/wiki/Computer

iii
În perioada 2017-2020 cele mai puternice calculatoare din lume au fost: ı̂n noiembrie 2017
11
ı̂n China, ı̂n noiembrie 2019 ı̂n SUA şi ı̂n iunie 2020 ı̂n Japonia. În iunie 2022 ”Frontier”
12
depăşeşte pragul ”exascale”! (1.102 Exaflop/s). ”Peta” a fost depăşit ı̂n 2008, ”tera” ı̂n 1997,
13
”giga” ı̂n 1972. . Pentru ce a fost mai ı̂nainte, vezi https://en.wikipedia.org/wiki/Li
st_of_fastest_computers.
14
O mică observaţie: ı̂n 2017 a fost prima ediţie a olimpiadei EJOI ı̂n Bulgaria şi ... tot
15
ı̂n Bulgaria a fost şi prima ediţie a olimpiadei IOI ı̂n 1989. Dar ... prima ediţie a olimpiadei
16
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ă ”ı̂ncepătorilor” interesaţi de aceste teme! Nu se
adresează ”avansaţilor” şi nici cârcotaşilor! Sunt evidente sursele
”de pe net” (şi locurile ı̂n care au fost folosite); cred că nu sunt
necesare ”ghilimele anti-plagiat” şi precizări la fiecare pas!
Şi un ultim gând: criticile şi sfaturile sunt utile dacă au valoare
reală! Dacă sunt numai aşa ... cum critică lumea la un meci de
fotbal ... sau cum, pe bancă ı̂n parc, unul ”ı̂şi dă cu părerea”
despre rezolvarea problemelor economice ale ţării ... atunci ... !!!
17
”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-Rabaea
https://www.scribd.com/user/552245048/Adi-Rabaea
https://drive.google.com/drive/folders/1hC5PZuslCdS95sl37SW46H-qy59GRDGZ

Bistriţa, 10th October 2023 Adrian Răbâea

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

”I want to thank God most of all because


without God
I wouldn’t be able to do any of this.” 18

and

I thank everyone for their support 19

and/or
suggestions!

18
I.d.k.: ”I don’t know who the author is.”
19
donation/donaţie:
. name: RABAEA AUREL ADRIAN, IBAN: RO22BRDE060SV11538970600, SWIFT: BRDEROBUXXX

v
Despre autor

20
nume: Răbâea Aurel-Adrian, 18.03.1953 - ...

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


email: adrian1803@gmail.com skype: adrian.r53
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://dmi.cunbm.utcluj.ro/
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;
21
Titlul tezei: Algoritmi paraleli şi aplicaţii pe maşini virtual paralele
22
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
23
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ă
24
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-
25
matică, Departamentul de Informatică
26
- (1992-1979) Centrul de Informatică şi organizare CINOR, Bucureşti
27
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)
20
https://dmi.cunbm.utcluj.ro/?page_id=2
21
http://opac.biblioteca.ase.ro/opac/bibliographic_view/149021
22
http://www.ionivan.ro/2015-PERSONALITATI/Dodescu.htm
23
http://old.fmi.unibuc.ro/ro/prezentare/promotii/promotia1978informatica_10ani/
24
https://ro.wikipedia.org/wiki/Ion_V%C4%83duva
25
https://fmi.univ-ovidius.ro/
26
https://www.cinor.ro/index.htm
27
https://www.cantemircml.ro/

vi
Dhawan Sanjeev, Kulvinder Singh, Eduard-Marius Craciun, Adrian Răbâea, Amit Batra;
Next-Cart Recommendation by Utilizing Personalized Item Frequency Information in Online Web
Portals, Neural Processing Letters, 2023; https://doi.org/10.1007/s11063-023-11207-2

Sanjeev Dhawan, Kulvinder Singh, Adrian Răbâea, Amit Batra;


ImprovedGCN: An efficient and accurate recommendation system employing lightweight graph con-
volutional networks in social media; Electronic Commerce Research and Applications, 2022, Vol.
55, Pages 101191-101207; DOI: https://doi.org/10.1016/j.elerap.2022.101191

Sanjeev Dhawan, Kulvinder Singh, Adrian Răbâea, Amit Batra;


Session centered Recommendation Utilizing Future Contexts in Social Media; Analele Ştiinţifice
ale Universităţii Ovidius Constanţa - Seria Matematică, Vol. 29 (3), 2021, 91-104; DOI:
https://doi.org/10.2478/auom-2021-0036

E.M. Craciun, A. Răbâea, S. Das;


Cracks Interaction in a Pre-Stressed and Pre-Polarized Piezoelectric Material;
Journal of Mechanics, 36(2), 2020, 177-182; DOI: https://doi.org/10.1017/jmech.2019.57
https://www.cambridge.org/core/journals/journal-of-mechanics/article/abs/cracks-interaction-
in-a-prestressed-and-prepolarized-piezoelectric-material/3938BF0AD79D5BE6B81BC4FB6BE80208

EM Craciun, A Răbâea, MF Popa, CI Mihailov;


Crack propagation in the human bone. Mode I of fracture; Analele Ştiinţifice ale Univ. Ovidius
Constanţa - Seria Matematică, Vol. 26(2), 2018, 59-70; DOI: https://doi.org/10.2478/auom-2018-
0018

EM Craciun, M Marin, A Răbâea;


Anti-plane crack in human bone. I. Mathematical modelling; Analele Ştiinţifice ale Univer-
sităţii Ovidius Constanţa - Seria Matematică, Volume 26, Issue 1, 2018, Pages 81-90; DOI:
https://doi.org/10.2478/auom-2018-0004

T. Sadowski, E. M. Craciun, A. Răbâea, L. Marsavina;


Mathematical modeling of three equal collinear cracks in an orthotropic solid; Meccanica 51, 329-
339 (2016); https://doi.org/10.1007/s11012-015-0254-5

E.M. Craciun, T. Sadowski, A. Răbâea;


Stress concentration in an anisotropic body with three equal collinear cracks in Mode II of frac-
ture. I. Analytical study; ZAMM Journal of Applied Mathematics and Mechanics / Zeitschrift
fr Angewandte Mathematik und Mechanik, Vol. 94 (9); September 2014, Pages 721-729;
https://doi.org/10.1002/zamm.201200293

E-M Craciun, T. Sadowski, L. Marsavina, A. Răbâea;


Mathematical Aspects Regarding Cracks Behaviour in Wood Composites; Key Engineering Mate-
rials 601:108-111, March 2014; DOI: 10.4028/www.scientific.net/KEM.601.108

ƒ Probleme de informatică date la bacalaureat


ƒ Probleme de informatică date la olimpiade - I.O.I.
ƒ Probleme de informatică date la olimpiade - liceu
ƒ Probleme de informatică date la olimpiade - gimnaziu
ƒ Algoritmi elementari + olimpiade EJOI gimnaziu
ƒ Algoritmi şi structuri de date + olimpiade EGOI liceu
ƒ Programa pentru bacalaureat - informatică liceu
ƒ Programa pentru olimpiadă - informatică gimnaziu + liceu

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
Cuprins

Prefaţă iii

Cuprins viii

Lista figurilor xv

Lista tabelelor xviii

Lista programelor xix

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


1 OJI 2023 2
1.1 aeriana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 castel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2 OJI 2022 13
2.1 ceas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.1.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2 sss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

3 OJI 2021 - OSEPI 21


3.1 concurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2 sir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

4 OJI 2020 32
4.1 cartonase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.2 tai . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

viii
4.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

5 OJI 2019 48
5.1 Aur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.1.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.2 Cartele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
5.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
5.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
5.2.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

6 OJI 2018 71
6.1 Patrate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
6.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
6.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
6.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
6.2 forus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
6.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
6.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
6.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

7 OJI 2017 83
7.1 numere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
7.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
7.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
7.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
7.2 robot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
7.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
7.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
7.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

8 OJI 2016 96
8.1 colier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
8.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
8.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
8.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
8.2 Palindrom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
8.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
8.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
8.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105

9 OJI 2015 106


9.1 Cuart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
9.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
9.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
9.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
9.2 speciale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
9.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
9.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
9.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

10 OJI 2014 122


10.1 martisoare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
10.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
10.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
10.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
10.2 piramide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
10.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
10.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
10.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

11 OJI 2013 136


11.1 bete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
11.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
11.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
11.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
11.2 chibrituri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
11.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
11.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
11.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

12 OJI 2012 144


12.1 alice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
12.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
12.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
12.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
12.2 porumb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
12.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
12.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
12.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155

13 OJI 2011 156


13.1 magic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
13.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
13.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
13.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
13.2 numerus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
13.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
13.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
13.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166

14 OJI 2010 167


14.1 sir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
14.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
14.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
14.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
14.2 tren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
14.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
14.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
14.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181

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


15 ONI 2023 183
15.1 cadouri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
15.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
15.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
15.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
15.2 legos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
15.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
15.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
15.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
15.3 patinaj . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
15.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
15.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
15.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
16 ONI 2022 193
16.1 Culori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
16.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
16.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
16.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
16.2 Joc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
16.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
16.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
16.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
16.3 Rotire25 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
16.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
16.3.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
16.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200

17 ONI 2021 201


17.1 ktlon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
17.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
17.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
17.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
17.2 iepuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
17.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
17.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
17.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
17.3 taieri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
17.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
17.3.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
17.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208

18 ONI 2020 - suspendat !!! 209

19 ONI 2019 210


19.1 Copii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
19.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
19.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
19.1.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
19.2 Numere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
19.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
19.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
19.2.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
19.3 Trio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
19.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
19.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
19.3.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236

20 ONI 2018 239


20.1 desen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
20.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
20.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
20.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
20.2 mostenire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
20.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
20.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
20.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
20.3 pyk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
20.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
20.3.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
20.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
21 ONI 2017 245
21.1 prime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
21.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
21.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
21.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
21.2 robot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
21.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
21.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
21.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
21.3 roua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
21.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
21.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
21.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266

22 ONI 2016 267


22.1 Norocos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
22.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
22.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
22.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
22.2 Oglinda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
22.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
22.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
22.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
22.3 Perechi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
22.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
22.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
22.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274

23 ONI 2015 275


23.1 iepuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
23.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
23.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
23.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
23.2 inventie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
23.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
23.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
23.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
23.3 mesaj . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
23.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
23.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
23.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308

24 ONI 2014 309


24.1 2048 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
24.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
24.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
24.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
24.2 babilon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
24.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
24.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
24.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
24.3 iepurasi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
24.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
24.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
24.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
25 ONI 2013 330
25.1 greieri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
25.1.1 *Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
25.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
25.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
25.2 Onigim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
25.2.1 *Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
25.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
25.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
25.3 Extraprime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
25.3.1 *Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
25.3.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
25.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333

26 ONI 2012 334


26.1 culegere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
26.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
26.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
26.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
26.2 culori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
26.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
26.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
26.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
26.3 stele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
26.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
26.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
26.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343

27 ONI 2011 344


27.1 Fagure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
27.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
27.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
27.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
27.2 Goe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
27.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
27.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
27.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
27.3 Păpuşa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
27.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
27.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
27.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353

28 ONI 2010 354


28.1 cluburi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
28.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
28.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
28.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
28.2 domino . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
28.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
28.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
28.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
28.3 max . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
28.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
28.3.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
28.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
Appendix A Programa olimpiadei - gimnaziu 371
A.1 Clasa a V-a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
A.2 Clasa a VI-a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
A.3 Clasa a VII-a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
A.4 Clasa a VIII-a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
A.5 Barajul de selecţie a lotului naţional lărgit . . . . . . . . . . . . . . . . . . . . . . . 373
A.6 Note . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373

Appendix B main(), cin, cout, fin, fout 374


B.1 Funcţia main() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374

Appendix C ”Instalare” C++ 376


C.1 Kit OJI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
C.1.1 Code::Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
C.1.2 Folder de lucru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
C.1.3 Utilizare Code::Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
C.1.4 Setări Code::Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
C.1.5 Multe surse ı̂n Code Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
C.2 winlibs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
C.2.1 GCC şi MinGW-w64 pentru Windows . . . . . . . . . . . . . . . . . . . . . 386
C.2.2 PATH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
C.2.3 CodeBlocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389

Appendix D Exponenţiere rapidă 399


D.1 Analogie baza 2 cu baza 10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
D.2 Notaţii, relaţii şi formule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
D.3 Pregătire pentru scrierea codului! . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
D.4 Codul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
D.5 Chiar este rapidă? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
D.6 Rezumat intuitiv! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405

Appendix E Căutare binară 407


E.1 Mijlocul = ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
E.2 Poziţie oarecare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
E.2.1 Varianta iterativă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
E.2.2 Varianta recursivă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
E.3 Poziţia din stânga . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
E.3.1 Varianta iterativă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
E.3.2 Varianta recursivă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
E.4 Poziţia din dreapta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
E.4.1 Varianta iterativă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
E.4.2 Varianta recursivă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414

Appendix F ”Vecini” ... 415


F.1 Direcţiile N, E, S, V . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415

Index 417

Bibliografie 419

Lista autorilor 422


Lista figurilor

1 Descompunerea canonică a lui f . . . . . . . . . . . . . . . . . . . . . . . . . . . . i


2 Un desen ... i ` f¯ ` p f . . . . . . . . . . . . . . . . . . . . . . . . . . . i

6.1 Patrate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
6.2 forus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

7.1 Numere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
7.2 Robot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

9.1 Cuart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106


9.2 speciale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115

10.1 martişoare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122


10.2 Piramide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129

11.1 chibrituri1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139


11.2 chibrituri2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

12.1 alice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144


12.2 AliceIR1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
12.3 AliceIR2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
12.4 AliceIR3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
12.5 AliceIR4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
12.6 porumbi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
12.7 porumbIR1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
12.8 P orumbIR2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151

13.1 Numerus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162


13.2 Numerus - exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

14.1 sirir1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168


14.2 sirir2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
14.3 sirir3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
14.4 sirir4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
14.5 sirir5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

15.1 (Figura 1) O fundaţie de mărime 6 x 6 . . . . . . . . . . . . . . . . . . . . . . . . . 186


15.2 (Figura 2) Un turn de ı̂nalţime 3, fiecare etaj are mărimea 5 x 5 . . . . . . . . . . 186
15.3 (Figura 3) Un teren de legoball de mărime 6 x 3. . . . . . . . . . . . . . . . . . . . 187

19.1 Numere cu 3 cifre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220


19.2 Numere cu 4 cifre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
19.3 Numere cu 5 cifre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221

20.1 desen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

23.1 mesaj . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295

24.1 2048 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309


24.2 iepurasi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321

xv
25.1 greieri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330

26.1 culegere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334


26.2 culegereIR1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
26.3 culegereIR2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
26.4 culegereIR3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
26.5 culegereIR4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
26.6 culori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
26.7 culoriIR1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
26.8 culoriIR2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
26.9 culoriIR3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
26.10stele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
26.11steleIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342

27.1 fagure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344


27.2 Goe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
27.3 papusa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350

28.1 cluburiIR1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355


28.2 cluburiIR2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
28.3 cluburiIR3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
28.4 domino . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
28.5 dominoIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
28.6 maxIR1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
28.7 maxIR2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366

C.1 Fişierele din Kit OJI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376


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

D.1 Analogie B2 cu B10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399

E.1 căutare binară: mijlocul zonei ı̂n vector . . . . . . . . . . . . . . . . . . . . . . . . 407

F.1 ”vecini” ı̂n matrice şi sistem Oxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415


F.2 Toţi ”pereţii” sunt la N sau la V ı̂n matricea ”bordată” . . . . . . . . . . . . . . . 415
F.3 Toţi ”pereţii” sunt codificaţi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
Lista tabelelor

19.1 copii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

xviii
Lista programelor

1.1.1 oji2023 aeriana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4


1.1.2 oji2023 cecker-aeriana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.1 oji2023 castel.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.2 oji2023 cecker-castel.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.1.1 ceas.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.1.2 checker-ceas.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2.1 sss.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2.2 checker-sss.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.1 concurs balacea.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.1.2 concurs dumitrascu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.1.3 concurs ungureanu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.2.1 sir balacea.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.2.2 sir dumitrascu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.2.3 sir ungureanu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.1.1 cartonase.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.1.2 cartonase.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.1.3 cartonase1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.1.4 cartonase2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.2.1 tai.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.2.2 tai.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.2.3 tai1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.2.4 tai2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.2.5 tai3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.2.6 tai4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.1.1 aur LC.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.1.2 aur sol.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.1.3 aur td.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.1.4 Aur - Etapa nr. 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.1.5 Aur - Etapa nr. 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.1.6 Aur - Etapa nr. 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.1.7 Aur - Etapa nr. 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.1.8 Aur - Etapa nr. 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
5.1.9 Aur - Etapa nr. 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
5.2.1 cartele LC.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
5.2.2 cartele td.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
5.2.3 Cartele - Etapa nr. 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
5.2.4 Cartele - Etapa nr. 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
5.2.5 Cartele - Etapa nr. 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
5.2.6 Cartele - Etapa nr. 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
6.1.1 patrate AS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
6.1.2 patrate cpp CM.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
6.1.3 patrate FB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
6.1.4 patrate VG.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
6.2.1 forus CM 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
6.2.2 forus nvl 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
6.2.3 forus VG 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
6.2.4 oficial FB 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
7.1.1 numere cardas.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
7.1.2 numere cerchez.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

xix
7.1.3 numere jakab.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
7.1.4 numere sandor.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
7.1.5 numere vladescu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
7.2.1 robot cerchez.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
7.2.2 robot cerchez ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
7.2.3 robot jakab.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
8.1.1 colier gina.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
8.1.2 colier Marius.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
8.1.3 colier Miana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
8.1.4 colier sanda.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
8.2.1 palindrom Marius.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
8.2.2 palindrom Sanda.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
9.1.1 cuart dl.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
9.1.2 cuart dt.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
9.1.3 cuart la.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
9.1.4 cuartAI.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
9.1.5 cuartAI ecuatie.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
9.2.1 speciale dc.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
9.2.2 speciale fin dt.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
9.2.3 speciale SJ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
9.2.4 specialedl.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
10.1.1 mAna.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
10.1.2 mCarmen.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
10.1.3 mCristina.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
10.1.4 mMarilena.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
10.1.5 mRaluca.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
10.2.1 p s CM.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
10.2.2 p v CM.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
10.2.3 pAna.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
10.2.4 pCristina.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
10.2.5 pGina.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
10.2.6 pMarilena.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
10.2.7 pRaluca.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
11.1.1 bete OFICIAL.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
11.1.2 bete vectori.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
11.2.1 chibrituri OFICIAL.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
11.2.2 chibrituri v.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
12.1.1 alice CM2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
12.1.2 alice CS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
12.1.3 alice SJ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
12.2.1 p100 AS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
12.2.2 p100 CL.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
12.2.3 p100 CM1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
12.2.4 p100 CM2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
12.2.5 p100 CS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
12.2.6 p100 DT.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
12.2.7 p100 JIT.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
13.1.1 CARACTER.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
13.1.2 magic DM.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
13.1.3 MAGIC S.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
13.1.4 magicAna.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
13.1.5 MAGICDT3.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
13.2.1 A1 Numer.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
13.2.2 D NUMERU.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
13.2.3 S Numeru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
14.1.1 sir.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
14.1.2 sirana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
14.1.3 SIRcris.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
14.1.4 SIRcris2.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
14.1.5 SIRcris2.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
14.1.6 SIRVECT.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
14.2.1 Ana.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
14.2.2 Carmen.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
14.2.3 Cris1.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
14.2.4 Cris2.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
14.2.5 Cris3.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
14.2.6 Dana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
15.1.1 5 cadouri.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
15.2.1 5 legos.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
15.3.1 5 patinaj.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
19.1.1 copii cpp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
19.1.2 Copii - Etapa nr. 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
19.1.3 Copii - Etapa nr. 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
19.1.4 Copii - Etapa nr. 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
19.2.1 numere cpp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
19.2.2 Numere - Etapa nr. 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
19.2.3 Numere - Etapa nr. 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
19.2.4 Numere - Etapa nr. 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
19.2.5 Numere - Etapa nr. 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
19.2.6 Numere - Etapa nr. 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
19.2.7 Numere - Etapa nr. 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
19.3.1 trio cpp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
19.3.2 Trio - Etapa nr. 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
19.3.3 Trio - Etapa nr. 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
19.3.4 Trio - Etapa nr. 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
19.3.5 Trio - Etapa nr. 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
21.1.1 prime cp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
21.1.2 prime em.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
21.1.3 prime fara ciur sn.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
21.2.1 robot adriana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
21.2.2 robot cp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
21.2.3 robot ema.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
21.2.4 robot-JT.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
21.3.1 roua cardas.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
21.3.2 roua cp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
21.3.3 roua jt.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
22.1.1 norocos.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
22.2.1 oglinda.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
22.3.1 perechi.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
23.1.1 iepuras 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
23.1.2 iepuras 2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
23.1.3 iepuras 3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
23.1.4 iepuras 4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
23.1.5 iepuras 5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
23.1.6 iepuras 6.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
23.2.1 inventie 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
23.2.2 inventie 2cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
23.2.3 inventie 3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
23.2.4 inventie 4 20p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
23.2.5 inventie 5 45p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
23.2.6 inventie 6.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
23.2.7 inventie 7.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
23.2.8 inventie 8 35p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
23.3.1 mesaj 1.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
23.3.2 mesaj 2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
23.3.3 mesaj 3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
23.3.4 mesaj 4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
23.3.5 mesaj 5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
23.3.6 mesaj 6.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
23.3.7 mesaj 7.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
24.1.1 2048.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
24.1.2 2048A.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
24.1.3 2048F.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
24.1.4 2048G.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
24.1.5 2048L.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
24.1.6 2048R.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
24.2.1 babilon.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
24.2.2 babilonA.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
24.2.3 babilonC.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
24.2.4 babilonL.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
24.3.1 iepurasi AI.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
24.3.2 iepurasi CS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
24.3.3 iepurasi gina.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
24.3.4 iepurasi lucia.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
24.3.5 iepurasiM.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
26.1.1 culegere 2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
26.1.2 culegere 3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
26.2.1 culori 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
26.2.2 culori 2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
26.3.1 stele 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
26.3.2 stele 2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
26.3.3 stele 3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
27.1.1 fagure.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
27.2.1 GOE.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
27.3.1 papusa.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
28.1.1 cluburi CS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
28.1.2 cluburi fara vectori.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
28.1.3 cluburi SG.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
28.2.1 domino AS 1.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
28.2.2 domino AS 2.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
28.2.3 domino CM.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
28.2.4 domino CS.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
28.2.5 domino SG.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
28.3.1 MAX CM.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
28.3.2 MAX CS.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
28.3.3 MAX SG.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
B.1.1 sss1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
B.1.2 sss2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
D.4.1 exponentiere rapida1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
D.4.2 exponentiere rapida2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
D.4.3 exponentiere rapida3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
D.4.4 exponentiere rapida MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
D.5.1 exponentiere naiva MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
D.5.2 exponentiere rapida MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
D.6.1 secventa cod.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
E.2.1 cautare binara-v1-iterativ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
E.2.2 cautare binara-v1-recursiv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
E.3.1 cautare binara-v2-iterativ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
E.3.2 cautare binara-v2-recursiv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
E.4.1 cautare binara-v3-iterativ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
E.4.2 cautare binara-v3-recursiv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
Part I

OJI - Olimpiada judeţeană de


informatică

1
Capitolul 1

OJI 2023

1.1 aeriana
Problema 1 - Aeriana 100 de puncte
O companie aeriană are planificate N zboruri. Fiecare zbor are asociate câte şase numere
naturale cu următoarea semnificaţie: primul număr A1 identifică aeroportul de decolare, cel de-al
doilea număr A2 identifică aeroportul de aterizare, următoarele patru numere naturale H1, M1, H2
şi M2, reprezintă ı̂n ordine ora şi minutul decolării, respectiv ora şi minutul aterizării. Aterizarea
poate să fie ı̂n ziua curentă sau ı̂n ziua următoare.
Un zbor poate să dureze maximum 23 de ore şi 59 de minute. De exemplu, pentru H1 = 10,
M1 = 5, H2 = 15, M2 = 20 aterizarea are loc ı̂n aceeaşi zi cu decolarea (zborul durează 5 ore şi
15 minute), iar pentru H1 = 23, M1 = 5, H2 = 1, M2 = 15 aterizarea are loc ı̂n ziua următoare
(zborul durează 2 ore şi 10 minute).
Un virus informatic s-a infiltrat ı̂n sistemele de calcul ale companiei şi a inversat momentul
de decolare cu cel de aterizare al zborurilor pe care le consideră speciale. Un zbor este considerat
special de către acest virus ı̂n cazul ı̂n care codul aeroportului de decolare, A1, este un număr
prim, iar codul aeroportului de aterizare, A2, se divide cu suma cifrelor lui A1.

Cerinţe

Cunoscându-se numărul de zboruri N şi datele fiecăruia, ı̂nainte de intervenţia virusului, să se
determine:

1. Care este durata maximă a unui zbor, ı̂nainte de intervenţia virusului.


2. Care este durata maximă a unui zbor, după intervenţia virusului. Se iau ı̂n calcul atât
duratele zborurilor inversate (speciale), cât şi duratele zborurilor neinversate (nespeciale).

Date de intrare

Fişierul aeriana.in conţine pe prima linie valoarea C (numărul cerinţei, poate fi 1 sau 2), pe
a doua linie valoarea N (numărul de zboruri). Pe fiecare dintre următoarele N linii sunt câte şase
numere naturale A1, A2, H1, M1, H2, M2, ı̂n această ordine, despărţite prin câte un spaţiu, cu
semnificaţia din enunţ.

Date de ieşire

Fişierul aeriana.out va conţine pe prima linie două numere naturale separate printr-un spaţiu,
reprezentând numărul de ore şi respectiv numărul de minute ale zborului de durată maximă, ı̂n
condiţiile cerinţei specificate.

Restricţii şi precizări

ˆ 1 & N & 1 000;


ˆ 0 & H1, H2 & 23;
ˆ 0 & M 1, M 2 & 59;
ˆ 0 & A1, A2 & 1 000 000 000;
ˆ Un zbor va dura cel puţin un minut şi cel mult 23 de ore şi 59 de minute.

2
CAPITOLUL 1. OJI 2023 1.1. AERIANA 3

# Punctaj Restricţii
1 19 C 1 şi toate zborurile se desfăşoară ı̂n aceeaşi zi
2 17 C 1, M 1 0, M 2 0 pentru toate zborurile
3 17 C 1, fără alte precizări
4 47 C 2

Exemple:

aeriana.in aeriana.out Explicaţii


1 23 59 C=1, N=3. Duratele acestor zboruri sunt, ı̂n or-
3 dine, 23 de ore şi 59 de minute, 10 ore şi 51 de
47 55 0 0 23 59 minute, iar pentru ultimul zbor, 23 de ore şi 40
1 437 23 43 10 34 de minute.
11 457 10 43 10 23
2 23 40 C 2, N 3. Pentru primul zbor A1=47 este
3 număr prim, suma cifrelor sale este egală cu 11 şi
47 55 0 0 23 59 A2=55 se divide cu 11, deci primul zbor devine
1 437 23 43 10 34 23:59-00:00 şi are o durata de 0 ore şi 1 minut.
11 457 10 43 10 23 Al doilea zbor rămâne nemodificat, deoarece 1 nu
e prim.
Al treilea zbor rămâne nemodificat. Chiar dacă
11 este prim, 457 nu se divide cu 2 (suma cifrelor
lui 11).
Zborul de durata maximă, dupa interventia
virusului, este cel de-al treilea.

1.1.1 Indicaţii de rezolvare

Propusă de: stud. Gabor Ioana, Universitatea Babes-Bolyai, Cluj-Napoca


a Pentru cerinţa 1, se calculează toate duratele zborurilor, iar pe urmă trebuie afişat maximul
dintre acestea.
Pentru calculul duratei unui zbor, atât momentul decolării, cât şi momentul aterizării ”se
convertesc ı̂n minute”, adică se află, pentru fiecare moment, ”distanţa ı̂n minute” dintre momentul
00:00 al primei zile şi momentul respectiv, presupunând că ambele momente sunt ı̂n ziua 1, cu
formula total _minute = H*60 + M.
În cazul ı̂n care decolarea şi aterizarea au loc ı̂n aceeaşi zi, durata zborului (ı̂n minute) este
dată de diferenţa dintre total_minute_2 şi total_minute_1.
În cazul ı̂n care decolarea şi aterizarea au loc ı̂n zile diferite, diferenţa anterioara ar fi negativă.
În acest caz, se adună ”ı̂nca o zi”, adică 24*60 minute la total_minute_2, deoarece iniţial am
presupus că momentul aterizării este ı̂n ziua 1.
a Pentru cerinţa 2, se verifică pentru fiecare zbor dacă este ”zbor special”’.
În primul rând, primul cod (notat ı̂n enunţ A1) trebuie să fie un număr prim (deci obligatoriu
mai mare sau egal cu 2).
Pentru a căuta mai rapid dacă areşi alt divizor in afară de 1 şi el ı̂nsuşi, ne folosim de faptul
că pentru orice divizor d al lui A1, automat şi A1©d ar fi divizor al lui A1.
Astfel căutăm divizori posibili d ai lui A1 pornind cu d de la 2 şi mergând cât timp d j A1©d.
Dacă primul cod este prim, se calculează suma cifrelor acestuia şi se verifică dacă al doilea cod
e divizibil cu suma calculată.
În cazul ı̂n care un zbor este ”special”, se interschimbă h1 cu h2 şi m1 cu m2.
Se calculează duratele zborurilor şi maximul dintre acestea, precum ı̂n cazul cerinţei 1.

1.1.2 *Cod sursă


CAPITOLUL 1. OJI 2023 1.1. AERIANA 4

1.1.3 Rezolvare detaliată

Putem să spunem 7 cm şi 4 mm sau, la fel


de bine şi corect, 74 de mm.
Asta pentru ca 1 cmm este egal cu 10 mm
şi 7cm + 4mm = 7*10mm+4mm = 74mm.
Este mai uşor de lucrat cu o singură unitate de măsură (mm) decât cu două unităţi de măsură
(cm şi mm). Desigur, vom alege unitatea de măsură care este cea mai mică dintre cele două.
La fel vom proceda cu orele şi minutele; singura diferenţă este că 1 ora = 60 minute.
Întotdeauna un desen este foarte bine venit pentru a observa ce avem de făcut.

Avem două zile consecutive. Decolarea se face ı̂n mod obligatoriu ı̂n prima zi. Aterizarea poate
să fie ı̂n prima zi sau ı̂n a doua zi.
Trebuie să fim atenţi la valorile datelor de intrare! Observăm că N poate avea valoarea 1000
şi A1 poate avea valoarea 1 000 000 000. Un miliard ”ı̂ncape” ı̂ntr-un int dar o valoare de 1000
de miliarde nu ”ı̂ncape” decât ı̂ntr-un long long.
Şi o ultimă observaţie: este util să ”ı̂mpănăm ” programul cu mesaje care să afişeze pe ecran
valorile intermediare obţinute! ı̂n acest fel putem să observăm repede dacă am greşit pe undeva.
Iar când am terminat şi este totul ok, vom comenta aceste mesaje (nu este bine să le ştergem
pentru că, din greşeală, putem să ştergem ce nu trebuie!).

Listing 1.1.1: oji2023 aeriana.cpp


#include<iostream> // atentie la = si == (un egal si doua egaluri) ... !!!
#include<fstream> // functii separate pentru toate verificarile ... !!!

using namespace std;

//ifstream fin("aeriana.in");
//ifstream fin("aeriana1.in");
//ifstream fin("aeriana2.in");
//ifstream fin("..//..//teste_aeriana//input.01-aeriana");
ifstream fin("../../teste_aeriana/input.29-aeriana");
ofstream fout("aeriana.out");

int C; // cerinta
int N; // nr de zboruri
int A1, A2; // aeroporturi
int H1, H2; // ora decolare/aterizare
int M1, M2; // minut decolare/aterizare

int minut1, minut2, minut12;


int max1, max2; // max la C=1 si max la C=2

int A1prim; // A1prim=1 daca A1=prim; altfel, A1prim=0


int scifA1; // suma cifrelor lui A1
int A1c; // copie a lui A1, pentru calcul suma cifrelor lui A1

int rora, rminut; // raspuns ora, raspuns minut


int i; // de numarat de la 1 la N
int d; // divizor pentru verificare daca A1 este prim

int inversez; // inversez=1 daca trebuie sa inversez, si 0 altfel


int aux; // auxiliare pentru inversare
CAPITOLUL 1. OJI 2023 1.1. AERIANA 5

int calcul1() // C=1


{
//cout<<"--> calcul1()"<<endl;
max1=-1;

for(i=1; i<=N; i++)


{
fin>>A1>>A2;
fin>>H1>>M1;
fin>>H2>>M2;
//cout<<A1<<" "<<A2<<" "<<H1<<" "<<M1<<" "<<H2<<" "<<M2<<endl;

minut1=H1*60+M1;
minut2=H2*60+M2;
//cout<<"minut1 = "<<minut1<<" minut2 = "<<minut2<<endl;
if(minut2==0) minut2=24*60;
//cout<<"minut1 = "<<minut1<<" minut2 = "<<minut2<<endl;

if(minut1 < minut2)


minut12=minut2-minut1;
else
minut12=minut1-minut2;

if(minut12 > max1) max1=minut12;

//cout<<"minut12 = "<<minut12<<" max1 = "<<max1<<endl;


//getchar(); // opreste executia pana apas <Enter>
}// sf for

rora=max1/60;
rminut=max1%60;

//cout<<rora<<" "<<rminut;
fout<<rora<<" "<<rminut;

return 0;
} // sf calcul1()

int calcul2() // C=2


{
//cout<<"--> calcul2()"<<endl;
max2=-1;

for(i=1; i<=N; i++)


{
//auto t1 = clock();

fin>>A1>>A2;
fin>>H1>>M1;
fin>>H2>>M2;
//cout<<A1<<" "<<A2<<" "<<H1<<" "<<M1<<" "<<H2<<" "<<M2<<endl;

inversez=1; // presupun ca trebuie sa inversez

// verific daca A1=prim


if(A1==0 || A1==1) // 0 si 1 nu sunt numere prime
{
A1prim=0; // era scris gresit A1prim==0; ??? :-(
inversez=0;
//cout<<"A1 = "<<A1<<" este zero sau 1 ... deci"
// << " A1prim = "<<A1prim<<endl;
}
else
if(A1==2 || A1==3 || A1==5 || A1==7) // numere prime mici
{
A1prim=1; // 2 este numar prim
}
else
if(A1%2==0)
{
//cout<<A1<<"%"<<2<<" = 0"<<endl;
A1prim=0; // numerele pare nu sunt prime
inversez=0;
}
else // trebuie sa verific daca A1 este prim
CAPITOLUL 1. OJI 2023 1.1. AERIANA 6

{
//cout<<"verific daca A1 = "<<A1<<" este prim"<<endl;
A1prim=1; // presupun ca A1 este prim
d=3;
while(d*d <= N && A1prim==1)
{
if(A1%d==0) A1prim=0; // A1 se divide cu d
d=d+2; // trec la urmatorul numar impar
}
}

//cout<<"A1 = "<<A1<<" A1prim = "<<A1prim<<endl;

// daca A1 nu este prim atunci nu mai verific suma cifrelor lui A1

if(A1prim==1)
{
// verific daca A2 se divide cu suma cifrelor lui A1
A1c=A1;
scifA1=0;
while(A1c > 0) // A1c mai are cifre
{
scifA1=scifA1 + A1c%10; // adun ultima cifra
A1c=A1c/10; // sterg ultima cifra
}
//cout<<"A1 = "<<A1<<" scifA1 = "<<scifA1<<endl;

if(A2 % scifA1 == 0)
{
//cout<<A2<<" % "<<scifA1<<" == 0"<<endl;
inversez=1;
}
else // aici A2 nu se divide cu suma cifrelor lui A1
{
//cout<<A2<<" % "<<scifA1<<" != 0"<<endl;
inversez=0;
}
}// sf if
else // aici A1 nu este prim
{
inversez=0; // nu trebuie sa le inversez
//cout<<A1<<" nu este prim"<<endl;
}

if(inversez==1)
{
//cout<<"le inversez ..."<<endl;
aux=H1; H1=H2; H2=aux;
aux=M1; M1=M2; M2=aux;
//cout<<A1<<" "<<A2<<" "<<H1<<" "<<M1<<" "<<H2<<" "<<M2<<endl;
}

minut1=H1*60+M1;
minut2=H2*60+M2;
//cout<<"minut1 = "<<minut1<<" minut2 = "<<minut2<<endl;
if(minut2==0) minut2=24*60;
//cout<<"minut1 = "<<minut1<<" minut2 = "<<minut2<<endl;

if(minut1 < minut2)


{
minut12=minut2-minut1;
}
else
{
minut12=24*60 - minut1 + minut2;
}

if(minut12 > max2) max2=minut12;

//cout<<"minut12 = "<<minut12<<" max2 = "<<max2<<endl;


//getchar(); // opreste executia pana apas <Enter>
}// sf for

rora=max2/60;
rminut=max2%60;
CAPITOLUL 1. OJI 2023 1.2. CASTEL 7

//cout<<rora<<" "<<rminut;
fout<<rora<<" "<<rminut;

return 0;
} // sf calcul2()

int main()
{
fin>>C; //cout<<"C = "<<C<<endl;
fin>>N; //cout<<"N = "<<N<<endl<<endl;

if(C==1)
calcul1();
else
calcul2();

fin.close();
fout.close();

return 0;
}

Listing 1.1.2: oji2023 cecker-aeriana.cpp


#include "testlib.h" // se gaseste usor pe internet ... !!!

using namespace std;

int main()
{
int argc=4;

char* argv[] =
{
(char*)"checker",
(char*)"../../teste_aeriana/input.29-aeriana", // input
(char*)"../../teste_aeriana/output.29-aeriana", // rezultat corect
(char*)"aeriana.out", // rezultat de verificat si acordat punctaj
};

cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";

registerChecker("aeriana", argc, argv);

compareRemainingLines();
}

1.2 castel
Problema 2 - Castel 100 de puncte
Un joc dispune de N cuburi galbene şi N cuburi albastre, de
dimensiuni identice; pe fiecare cub galben este scris un număr nat-
ural nenul, de cel mult 9 cifre.
Jocul urmăreşte construirea unui castel alcătuit din mai multe
rânduri de cuburi, ı̂n care rândul de sus este format dintr-un singur
cub, de culoare galbenă, iar fiecare dintre celelalte rânduri ı̂ncep
şi se termină cu câte un cub de culoare galbenă.
Oricare două cuburi vecine pe acelaşi rând au câte o latură comună şi fiecare cub, cu excepţia
celor galbene de pe margine, are o latură comună cu un cub care aparţine rândului de deasupra.
Oricare două cuburi cu o latură comună au culori diferite.
Rândurile de cuburi sunt numerotate de jos ı̂n sus, ı̂ncepând de la 1. Pentru construcţia
castelului se preiau cuburile galbene ı̂n ordinea ı̂n care acestea sunt date, iar cele albastre ı̂ntr-o
ordine oarecare, şi sunt plasate pe rânduri, de jos ı̂n sus, şi pe fiecare rând de la stânga la dreapta,
astfel: primul cub se plasează pe rândul de la bază (numerotat cu 1), apoi fiecare cub (galben sau
CAPITOLUL 1. OJI 2023 1.2. CASTEL 8

albastru) se plasează fie ı̂n continuare, pe rândul curent, la dreapta, fie pe un rând nou, peste un
cub al rândului curent.
După plasarea cubului din vârful castelului, pe fiecare cub albastru se scrie un număr egal cu
suma numerelor scrise pe cei doi vecini galbeni situaţi pe acelaşi rând, ı̂n stânga şi ı̂n dreapta sa.
Pentru a câs,tiga jocul, castelul obţinut trebuie să aibă un număr maxim de rânduri, chiar dacă
poate nu foloses,te toate cuburile date.

Cerinţe

Cunoscând numerele scrise pe cele N cuburi galbene, ı̂n ordinea dată, scrieţi un program care
să determine:

1. numărul cuburilor galbene, dintre cele N date, pe care sunt scrise valori de o singură cifră;
2. rândul pe care se află cubul din vârful castelului şi numărul scris pe acest cub;
3. numărul cuburilor albastre din care este alcătuit castelul şi suma tuturor numerelor de pe
acestea.

Date de intrare

Fişierul castel.in conţine:

ˆ pe prima linie două numere naturale C şi N , ı̂n această ordine, despărţite printr-un spaţiu,
unde C reprezintă numărul cerinţei şi poate avea valorile 1, 2 sau 3, iar N are semnificaţia
din enunţ;
ˆ pe a doua linie, N numere naturale despărţite prin câte un spaţiu, reprezentând numerele
scrise pe cuburile galbene, ı̂n ordinea ı̂n care sunt preluate.

Date de ieşire

Fişierul castel.out conţine pe prima linie:

ˆ un singur număr natural pentru rezolvarea cerinţei 1, reprezentând valoarea determinată


conform acestei cerinţe;
ˆ două numere naturale despărţite printr-un spaţiu, ı̂n cazul cerinţelor 2 şi 3. Pentru cerinţa
2, primul număr reprezintă rândul pe care se află cubul din vârful castelului iar cel de-
al doilea număr reprezintă valoarea scrisă pe acest cub. Pentru cerinţa 3, prima valoare
reprezintă numărul de cuburi albastre care alcătuiesc castelul, iar a doua valoare reprezintă
suma tuturor numerelor scrise pe aceste cuburi.

Restricţii şi precizări

ˆ 3&N & 5 000.


# Punctaj Restricţii
1 25 C=1
2 30 C=2
3 45 C=3

Exemple:

castel.in castel.out Explicaţii


1 12 6 C=1 şi sunt 6 cuburi pe care sunt scrise
17 5 11 2 17 17 4 2 2 5 34 88 numere de o singură cifră.
2 12 45 Exemplul corespunde imaginii din enunt,
17 5 11 2 17 17 4 2 2 5 34 88 şi C=2. Cubul din vârful castelului este pe
rândul 4 şi pe el este scris 5.
3 12 6 110 Exemplul corespunde imaginii din enunt,
17 5 11 2 17 17 4 2 2 5 34 88 şi C=3. Sunt 6 cuburi albastre ı̂n castel şi
suma numerelor scrise pe acestea este 110.
CAPITOLUL 1. OJI 2023 1.2. CASTEL 9

1.2.1 Indicaţii de rezolvare

Propusă de: prof. Iordaiche Eugenia-Cristiana, Liceul Teoretic ”Grigore Moisil”, Timişoara
a Pentru cerinţa 1, se contorizează toate valorile citite care au o singură cifră, ele sunt strict
mai mari decât 0 şi mai mici sau egale cu 9.
a Pentru cerinţa 2, se calculează, pentru fiecare rând R al castelului, numărul cuburilor galbene
aflate pe acesta. Ştim că pe ultimul rând este un singur cub galben, pe penultimul rând sunt 2
cuburi galbene, pe antepenultimul 3 cuburi galbene, şi, procedând ı̂n acest fel, pe primul rând
al castelului (numerotat cu 1) sunt K cuburi galbene. Astfel, castelul construit, are ı̂n total
1+2+3+4+...+K cuburi galbene, aranjate pe cele K rânduri.
Determinăm cea mai mare valoare a lui K pentru care suma 1+2+3+4+...K nu depăşeşte
valoarea lui N . Rândul pe care se află cubul din vârful castelului este K iar numărul scris pe
acesta este cel de pe pozitia p ı̂n şirul de intrare, unde p 1  2  ...  k.
Alternativ p poate fi determinat şi cu formula k ˜ k  1©2.
a Pentru cerinţa 3, observăm că pe fiecare rând al castelului numărul cuburilor albastre este
cu 1 mai mic decât numărul cuburilor galbene. Păstrând aceleaşi notaţii ca la cerinţa anterioară,
numărul cuburilor albastre din castel este egal cu 1  2  3  ...  k  1.
Pentru fiecare cub albastru, calculăm numărul scris pe acesta ca fiind suma a două valori
preluate succesiv din fişierul de intrare. Acestea reprezintă numerele scrise pe cuburile galbene
situate pe acelaşi rând, ı̂n stânga şi dreapta fiecărui cub albastru.
Calculăm suma tuturor valorilor scrise pe cuburile albastre din castel.

1.2.2 *Cod sursă

1.2.3 Rezolvare detaliată

Întotdeauna un desen este foarte bine venit pentru


a observa ce avem de făcut. În dreapta este un desen
util pentru cazul 3. Vom păstra două valori consecutive
ale cuburilor galbene, ncgs (numărul de pe cubul galben
din stânga cubului albastru) şi ncgd (numărul de pe cubul galben din dreapta cubului albastru).
Folosim suma lor şi ... citim mai departe din fişier ncgd. Înainte de citire trebuie să actualizăm
ncgs (ncgs=ncgd;).
Există o zonă identică ı̂n codurile calcul2() şi calcul3(). Aceste instrucţiuni se puteau
”ı̂mpacheta” ı̂ntr-un singur subprogram pe care să-l fi apelat din calcul2() şi calcul3().

Fiecare scie codul cum vrea! Uneori este util şi un ”copy-paste”.
Trebuie să fim atenţi la valorile datelor de intrare! Numerele scrise pe cuburile galbene pot
avea 9 cifre, deci pot avea coduri 999 999 999 care este numai cu 1 mai mic decât 1 miliard.
N poate fi 5 000 iar suma tuturor numerelor poate fi aproape de 5 000 * 1 000 000 000, adică
de 5 mii de miliarde.
Un miliard ”ı̂ncape” ı̂ntr-un int dar o valoare de 5 000 de miliarde nu ”ı̂ncape” decât ı̂ntr-un
long long.
Şi o ultimă observaţie: este util să ”ı̂mpănăm ” programul cu mesaje care să afişeze pe ecran
valorile intermediare obţinute! ı̂n acest fel putem să observăm repede dacă am greşit pe undeva.
Iar când am terminat şi este totul ok, vom comenta aceste mesaje (nu este bine să le ştergem
pentru că, din greşeală, putem să ştergem ce nu trebuie!).

Listing 1.2.1: oji2023 castel.cpp


#include<iostream> // atentie la "long long"
#include<fstream> //

using namespace std;

//ifstream fin("castel.in");
CAPITOLUL 1. OJI 2023 1.2. CASTEL 10

//ifstream fin("castel1.in");
//ifstream fin("castel2.in");
//ifstream fin("castel3.in");

//ifstream fin("..//..//teste_castel//input.1_0-castel");
//ifstream fin("..//..//teste_castel//input.1_7-castel");

//ifstream fin("..//..//teste_castel//input.2_0-castel");
//ifstream fin("..//..//teste_castel//input.2_9-castel");

//ifstream fin("..//..//teste_castel//input.3_0-castel");
ifstream fin("..//..//teste_castel//input.3_9-castel");

ofstream fout("castel.out");

int C; // cerinta
int N; // nr de zboruri

int ncg; // numarul scris pe cubul galben citit din fisier

int ncgs; // numarul scris pe cubul galben din stanga


int ncgd; // numarul scris pe cubul galben din dreapta
int ncr; // numarul cubului rosu
int nrcg1; // nr cuburi galbene de 1 cifra

int rvarf; // randul varfului


int nrvarf; // nr cubului galben in varf
int nrca; // nr cuburi albastre

long long scr; // suma cuburi rosii;


int i, j; // folosit pentru numarat ...

int calcul1() // C=1


{
//cout<<"--> calcul1()"<<endl;

nrcg1=0;
for(int i=1; i<=N; i++)
{
fin>>ncg;
//cout<<i<<" : "<<ncg<<endl;
if(ncg <= 9) // are o cifra
{
nrcg1=nrcg1+1;
//cout<<" ncg = "<<ncg<<" nrcg1 = "<<nrcg1<<endl;
}
}

//cout<<"nrcg1 = "<<nrcg1<<endl;
fout<<nrcg1;

return 0;
} // sf calcul1()

int calcul2() // C=2


{
//cout<<"--> calcul2()"<<endl;

// ---------------------------------------
rvarf=0;
nrvarf=0;
while(nrvarf < N)
{
rvarf++; // trbuie sa adiun
nrvarf=nrvarf+rvarf;
}
//cout<<"rvarf = "<<rvarf<<" nrvarf = "<<nrvarf<<endl;
if(nrvarf > N)
{
nrvarf=nrvarf-rvarf;
rvarf=rvarf-1;
}
//cout<<"rvarf = "<<rvarf<<" nrvarf = "<<nrvarf<<endl;
// ---------------------------------------
CAPITOLUL 1. OJI 2023 1.2. CASTEL 11

scr=0;
for(i=rvarf; i>=1; i--)
{
fin>>ncg;
}

//cout<<rvarf<<" "<<ncg<<endl;
fout<<rvarf<<" "<<ncg<<endl;

return 0;
} // sf calcul2()

int calcul3() // C=2


{
//cout<<"--> calcul3()"<<endl;
// ---------------------------------------
rvarf=0;
nrvarf=0;
while(nrvarf < N)
{
rvarf++; // trbuie sa adiun
nrvarf=nrvarf+rvarf;
}
//cout<<"rvarf = "<<rvarf<<" nrvarf = "<<nrvarf<<endl;
if(nrvarf > N)
{
nrvarf=nrvarf-rvarf;
rvarf=rvarf-1;
}
//cout<<"rvarf = "<<rvarf<<" nrvarf = "<<nrvarf<<endl;
// ---------------------------------------

scr=0LL;
nrca=0;
for(i=rvarf-1; i>=1; i--)
{
fin>>ncg;
ncgs=ncg;
for(j=1; j<=i; j++)
{
fin>>ncg;
ncgd=ncg;
ncr=ncgs+ncgd;
//cout<<"i: "<<i<<" j: "<<j
// <<" ncgs = "<<ncgs<<" ncgd = "<<ncgd
// <<" ncr = "<<ncr<<endl;

scr=scr+ncr;
nrca++;
ncgs=ncgd;
}
//cout<<endl;
}
// cout<<"nrca= "<<nrca<<" scr = "<<scr<<endl;
fout<<nrca<<" "<<scr<<endl;

return 0;
} // sf calcul3()

int main()
{
fin>>C; //cout<<"C = "<<C<<endl;
fin>>N; //cout<<"N = "<<N<<endl<<endl;

if(C==1) calcul1(); else


if(C==2) calcul2(); else
if(C==3) // nu era necesar dar ... este ok pentru claritate!
calcul3();

fin.close();
fout.close();

return 0;
}
CAPITOLUL 1. OJI 2023 1.2. CASTEL 12

Listing 1.2.2: oji2023 cecker-castel.cpp


#include "testlib.h" // se gaseste usor pe internet ... !!!

using namespace std;

int main()
{
int argc=4;

char* argv[] =
{
(char*)"checker",

//(char*)"../../teste_castel/input.1_7-castel", // input
//(char*)"../../teste_castel/output.1_7-castel", // rezultat corect

//(char*)"../../teste_castel/input.2_9-castel", // input
//(char*)"../../teste_castel/output.2_9-castel", // rezultat corect

(char*)"../../teste_castel/input.3_9-castel", // input
(char*)"../../teste_castel/output.3_9-castel", // rezultat corect

(char*)"castel.out", // rezultat de verificat si acordat punctaj


};

cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";

registerChecker("castel", argc, argv);

compareRemainingLines();
}
Capitolul 2

OJI 2022

2.1 ceas
Problema 1 - ceas 100 de puncte
Un atelier de fabricat ceasuri cu cuc are nevoie de plăcuţe cu numerele pentru orele pe care
trebuie să le aşeze pe discul ceasurilor. Aceste numere sunt realizate la o imprimantă.
Din cauza unei erori imprimanta tipăreşte plăcuţe cu numere naturale, unele mai mari ca 12.
Atelierul poate utiliza doar plăcuţe cu numere cuprinse ı̂ntre 0 şi 12. Pentru a utiliza aceste numere
este nevoie ca ele să fie tăiate ı̂ncepând din partea dreaptă ı̂n grupuri de maxim 2 cifre, fiecare
grup reprezentând valoarea de pe o plăcuţă, care să fie o cifră la 0 la 9 sau unul dintre numerele 10,
11, 12. Dacă pe o plăcuţă se găseşte un număr mai mare ca 12 atunci plăcuţa trebuie tăiată, astfel
ı̂ncât ı̂n urma tăierii să se obţină numere de cel mult 2 cifre. Dacă ı̂n numărul de pe o plăcuţă
cifra zecilor este 0, atunci la prima tăiere se ia doar cifra unităţilor, altfel dacă numărul format cu
cifra zecilor şi unităţilor este mai mare ca 12, atunci se taie prima dată cifra unităţilor, iar dacă
numărul format cu cifra zecilor şi unităţilor este 10, 11 sau 12 se taie prima dată numărul format
din ultimele 2 cifre, apoi procedeul se repetă până la tăierea completă a plăcuţei. Imprimanta a
realizat N plăcuţe. De exemplu dacă plăcuţa este 12030, după tăiere se obţin 0, 3, 0, 12.

Cerinţe

Cerinţa 1
Determinaţi numărul total de apariţii ale cifrei X pe plăcuţe ı̂nainte de tăiere.
Cerinţa 2
Determinaţi numărul de tăieturi realizate conform enunţului.

Date de intrare

Pe prima linie a fişierului ceas.in se află valorile C, X şi N separate prin câte un singur spaţiu.
Pe linia a doua se află N numere naturale separate prin câte un singur spaţiu, având semnificaţia
din enunţ. Pentru C = 1 se rezolvă doar cerinţa 1, iar pentru C = 2 se rezolvă doar cerinţa 2.

Date de ieşire

Fişierul ceas.out conţine pe prima linie un singur număr natural care reprezintă valoarea
calculată conform cerinţei.

Restricţii şi precizări

ˆ 1 & N & 100.000


ˆ 0 &X&9
ˆ Valorile din şir sunt numere naturale & 50.000
ˆ Pentru testele ı̂n care avem C=2 valoarea X este prezentă ı̂n fişierul de intrare chiar dacă
nu este folosită ı̂n rezolvare.
ˆ Pentru teste ı̂n valoare de 39 de puncte avem C = 1

13
CAPITOLUL 2. OJI 2022 2.1. CEAS 14

ˆ Pentru teste ı̂n valoare de 61 de puncte avem C = 2

Exemple:

ceas.in ceas.out Explicaţii


106 4 Pe plăcuţe cifra 0 apare de patru ori.
1010 40 201 5123 31 6
206 7 În ordinea tăierilor se obţin: 0,12; 0,4; 1,0,2; 3,12,5; 1,3; 6.
120 40 201 5123 31 6 Numărul de tăieturi este 7.

2.1.1 Indicaţii de rezolvare

Propusa de: Pintea Adrian Doru, profesor la Colegiul Naţional Andrei Mureşanu Dej
Pentru cerinţa 1, se citesc pe rând cele N numere şi pentru fiecare număr se calculează de câte
ori conţine cifra X.
Pentru cerinţa 2, se citesc pe rând cele N numere şi pentru fiecare număr se fac tăieturile a
uneia (cifra unităţilor) sau a două cifre (cifra zecilor şi cifra unităţilor) conform cerinţei, numărând
fiecare taietură realizată.

2.1.2 *Cod sursă

2.1.3 Rezolvare detaliată

Listing 2.1.1: ceas.cpp


#include<iostream>
#include<fstream>

using namespace std;

//ifstream fin("ceas1.in");
//ifstream fin("ceas2.in");
//ifstream fin("ceas3.in");

//cerinta 1
//ifstream fin("../teste_ceas/00-ceas.in"); // 734
//ifstream fin("../teste_ceas/01-ceas.in"); // 14469
//ifstream fin("../teste_ceas/02-ceas.in"); // 11868
//ifstream fin("../teste_ceas/03-ceas.in"); // 13697
//ifstream fin("../teste_ceas/04-ceas.in"); // 19773
//ifstream fin("../teste_ceas/05-ceas.in"); // 20627
//ifstream fin("../teste_ceas/06-ceas.in"); // 50999
//ifstream fin("../teste_ceas/07-ceas.in"); // 31844
//ifstream fin("../teste_ceas/08-ceas.in"); // 30866
//ifstream fin("../teste_ceas/09-ceas.in"); // 39615

//cerinta 1
//ifstream fin("../teste_ceas/10-ceas.in"); // 3496
//ifstream fin("../teste_ceas/11-ceas.in"); // 34949
//ifstream fin("../teste_ceas/12-ceas.in"); // 104795
//ifstream fin("../teste_ceas/13-ceas.in"); // 139697
//ifstream fin("../teste_ceas/14-ceas.in"); // 174574
//ifstream fin("../teste_ceas/15-ceas.in"); // 209481
ifstream fin("../teste_ceas/16-ceas.in"); // 244393
//ifstream fin("../teste_ceas/17-ceas.in"); // 279229
//ifstream fin("../teste_ceas/18-ceas.in"); // 314061
//ifstream fin("../teste_ceas/19-ceas.in"); // 348865
//ifstream fin("../teste_ceas/20-ceas.in"); // 3
//ifstream fin("../teste_ceas/21-ceas.in"); // 4
//ifstream fin("../teste_ceas/22-ceas.in"); // 8
//ifstream fin("../teste_ceas/23-ceas.in"); // 0
//ifstream fin("../teste_ceas/24-ceas.in"); // 16
CAPITOLUL 2. OJI 2022 2.1. CEAS 15

ofstream fout("ceas.out");

int C; // cerinta
int X; // cifra
int N; // nr numere

int nr; // numar citit

int rez1; // rezultat le cerinta 1


int rez2; // rezultat le cerinta 2

void cerinta1()
{
int i;

rez1=0;
for(i=1; i<=N; i++)
{
fin>>nr;
if((nr==0)&&(X==0)) // Atentie: si zero este numar natural !!!
{
rez1++;
continue; // i++
}

while(nr != 0)
{
if(nr%10 == X) rez1++; // testez ultima cifra
nr=nr/10; // elimin ultima cifra
}
}

cout<<"rez1 = "<<rez1;
fout<<rez1;

return;
}

void cerinta2() // 120 40 201 5123 31 6


{
int i;
int nr2; // nr cu 2 cifre ... (este 10, 11, 12 ?)

rez2=0;
for(i=1; i<=N; i++)
{
fin>>nr;

//cout<<"nr = "<<nr<<": ";


while(nr != 0)
{

//getchar();
if((nr%10) >= 3) // daca ultima cifra este 3, 4, ..., 9
{
//cout<<(nr%10)<<", ";
nr=nr/10;
if(nr>0) // daca a mai ramas ceva in nr --> s-a taiat o cifra
{
rez2++; // daca a fost ultimul --> nu am ce sa tai
//cout<<" | ";
}
}
else // ultima cifra este 0, 1 sau 2
if(nr/10==0) // este o singura cifra --> se plaseaza, nu se taie
{
//cout<<nr<<"*, ";
nr=nr/10;
}
else // aici sunt cel putin 2 cifre si ultima cifra este 1 sau 2
{
nr2=nr%100; // nr2 = ultimele 2 cifre
CAPITOLUL 2. OJI 2022 2.1. CEAS 16

if((nr2==10) || (nr2==11) || (nr2==12))


{
//cout<<nr2<<"*, ";
nr=nr/100;
if(nr>0)// daca a ramas ceva in nr --> nr2 s-a taiat din nr
{
rez2++; // daca a fost ultimul --> nu am ce sa tai
//cout<<" | ";
}
}
else // tai ultima cifra si mai ramane ceva in nr
{
//cout<<(nr%10)<<"*, ";
nr=nr/10;
rez2++; // daca a fost ultimul --> nu am ce sa tai
//cout<<" | ";
}
}// nr > 10 si ultima cifra este 1 sau 2
} // while(nr != 0)
//cout<<endl<<"-------------------"<<endl;
}// for

cout<<"rez2 = "<<rez2;
fout<<rez2;

return;
}

int main()
{
fin>>C;
fin>>X;
fin>>N;
cout<<"C = "<<C<<" X = "<<X<<" N = "<<N<<’\n’;

if(C==1) cerinta1();
if(C==2) cerinta2();

fin.close();
fout.close();

return 0;
}

Listing 2.1.2: checker-ceas.cpp


#include "testlib.h"

using namespace std;

int main()
{
int argc=4;

char* argv[] =
{
(char*)"checker",
(char*)"../teste_ceas/16-ceas.in", // input
(char*)"../teste_ceas/16-ceas.out", // rezultat corect
(char*)"ceas.out", // rezultat de verificat si acordat punctaj
};

cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";

registerChecker("ceas", argc, argv);

compareRemainingLines();
}
CAPITOLUL 2. OJI 2022 2.2. SSS 17

2.2 sss
Problema 2 - sss 100 de puncte
Se dă un număr N, şi un şir de N numere naturale nenule.

Cerinţe

Cerinţa 1
Determinaţi suma valorilor aflate pe ultimele K poziţii ı̂n şir (unde K reprezintă valoarea celei
mai din dreapta cifre nenule a primei valori din şir).
Cerinţa 2
Ne imaginăm ı̂mpărţirea şirului ı̂n secvenţe ı̂n următorul mod: prima secvenţă este formată
din primele L elemente, a doua este formată din următoarele L - 1 elemente, a treia este formată
din următoarele L - 2 elemente şi aşa mai departe, ultima secvenţă este formată dintr-un singur
element şi acesta coincide cu ultimul element din şir. Considerând suma valorilor fiecărei secvenţe,
să se determine cea mai mare dintre aceste sume.

Date de intrare

Pe prima linie a fişierului sss.in se află două valori C şi N separate printr-un spaţiu. Pe linia a
doua se află N numere naturale separate prin câte un spaţiu. Pentru C = 1 se rezolvă doar cerinţa
1 iar pentru C = 2 se rezolvă doar cerinţa 2.

Date de ieşire

Fişierul sss.out conţine un singur număr care reprezintă valoarea calculată conform cerinţei.

Restricţii şi precizări

ˆ 1 & N & 100.000


ˆ Valorile din şir sunt numere naturale nenule 100.000;

ˆ Se garantează că pentru testele ı̂n care C = 1 şirul are cel puţin K elemente;

ˆ Se garantează că valoarea lui N permite descompunerea conform descrierii, pentru testele
care au C = 2;
ˆ Pentru teste ı̂n valoare de 51 de puncte avem C=1;

ˆ Pentru 27 de puncte dintre testele ı̂n care C=1 primul număr din şir are o cifră;

ˆ Pentru teste ı̂n valoare de 49 de puncte avem C=2;

ˆ Pentru teste ı̂n valoare de 22 de puncte dintre cele care au C=2, valoarea lui N este mai
mică sau egală cu 10.
ˆ Denumirea problemei este o prescurtare de la ”sume şi secvenţe”.

Exemple:

sss.in sss.out Explicaţii


16 37 Ultima cifră nenulă a primului element din şir este 2. Suma
120 4 21 5 31 6 ultimelor două valori din şir este 37.
2 10 11 Descompunerea se poate realiza ı̂n secvenţe de lungimile 4, 3, 2
1421361653 şi 1. Sumele obţinute pentru fiecare sunt: 8, 10, 11, 3.
CAPITOLUL 2. OJI 2022 2.2. SSS 18

2.2.1 Indicaţii de rezolvare

Propusa de: Marius Nicoli, profesor la Colegiul Naţional Fraţii Buzeşti Craiova, Programator
la Syncro Soft Craiova
Pentru cerinţa 1, aflăm mai ı̂ntâi valoarea lui k imediat după citirea primului termen al şirului.
Pentru acest lucru folosim algoritmul clasic de parcurgere a cifrelor unui număr (ı̂mpărţiri
repetate la 10). Ulterior citim şi celelalte numere şi acumulăm la suma cerută valorile celor aflate
pe poziţii mai mari sau egale cu n-k+1 (considerăm numerotarea de la poziţia 1).
Pentru cerinţa 2, imediat după citirea lui n şi ı̂nainte să citim elementele şirului, determinăm
valoarea L. Vom folosi o repetiţie ı̂n care construim suma 1 + 2 + 3 + . . . până când aceasta
devine egală cu n (lucru garantat de restricţiile din enunţ). Numărul de termeni ai acestei sume
este chiar L. Acum putem ı̂ncepe citirea valorilor şirului, de exemplu putem folosi o variabilă
sumaCurentă ı̂n care acumulăm iniţial valorile primelor L elemente, apoi resetăm sumaCurentă şi
acumulăm la ea valorile următoarelor L-1 şi aşa mai departe până terminăm de citit valorile din
şir.

2.2.2 *Cod sursă

2.2.3 Rezolvare detaliată

Listing 2.2.1: sss.cpp


#include<iostream>
#include<fstream>

using namespace std;

//ifstream fin("sss1.in");
//ifstream fin("sss2.in");

//cerinta 1
//ifstream fin("../teste_sss/00-sss.in"); // 14
//ifstream fin("../teste_sss/01-sss.in"); // 98
//ifstream fin("../teste_sss/02-sss.in"); // 3355
//ifstream fin("../teste_sss/03-sss.in"); // 11
//ifstream fin("../teste_sss/04-sss.in"); // 17442
//ifstream fin("../teste_sss/05-sss.in"); // 6
//ifstream fin("../teste_sss/06-sss.in"); // 1413
//ifstream fin("../teste_sss/07-sss.in"); // 35222
//ifstream fin("../teste_sss/08-sss.in"); // 154
//ifstream fin("../teste_sss/09-sss.in"); // 383221

//cerinta 2
//ifstream fin("../teste_sss/10-sss.in"); // 18
//ifstream fin("../teste_sss/11-sss.in"); // 25
//ifstream fin("../teste_sss/12-sss.in"); // 25
//ifstream fin("../teste_sss/13-sss.in"); // 67
//ifstream fin("../teste_sss/14-sss.in"); // 108
//ifstream fin("../teste_sss/15-sss.in"); // 29671
//ifstream fin("../teste_sss/16-sss.in"); // 30147
//ifstream fin("../teste_sss/17-sss.in"); // 30147
//ifstream fin("../teste_sss/18-sss.in"); // 30151
ifstream fin("../teste_sss/19-sss.in"); // 30356

ofstream fout("sss.out");

int C; // cerinta
int N; // nr numere
int L;

int s;
int smax;

int s1L; // s1L = 1+2+...+L ca sa determin L


CAPITOLUL 2. OJI 2022 2.2. SSS 19

int nr; // numar citit

int rez1; // rezultat le cerinta 1


int rez2; // rezultat le cerinta 2

void cerinta1()
{
int i;
int cifra;

rez1=0;

fin>>nr;

cout<<"nr = "<<nr<<endl;

while(nr%10==0) nr=nr/10; // elimin 0-urile de la sfarsit


//cout<<"nr = "<<nr<<" dupa eliminarea zerourilor"<<endl;

cifra=nr%10;
//cout<<"cifra = "<<cifra<<endl;
//getchar();

for(i=2; i<=N; i++)


{
fin>>nr;
//cout<<"i = "<<i<<" nr = "<<nr<<endl;

if(i >= (N-cifra+1))


{
rez1=rez1+nr;
//cout<<" rez1 = "<<rez1<<endl;
//getchar();
}
}

cout<<"rez1 = "<<rez1;
fout<<rez1;

return;
}

void cerinta2() // 120 40 201 5123 31 6


{
int i;

// 1+2+3+...+L=N;

if(N==1)
{
fin>>nr;
cout<<"rez2 = "<<nr<<endl;
fout<<rez2;
return;
}

if(N==3) // 3 = 2 + 1
{
fin>>nr; // citesc primele 2 nr
s=nr;
fin>>nr;
s=s+nr;
smax=s; // este prima valoare pentru sume

fin>>nr; // citesc 1 nr care este ultima


s=nr;

if(s>smax) smax=s;

cout<<"rez2 = "<<smax<<endl;
fout<<smax;

return;
}

// nu se poate merge asa pana la N = 100 000 ... !!!


CAPITOLUL 2. OJI 2022 2.2. SSS 20

s1L=0; // cu s determin L
L=0;
// s = 1 + 2 + 3 + ... + (L-1) + L = N
while(s<N)
{
L=L+1;
s=s+L;
//cout<<"L = "<<L<<" s = "<<s<<endl; // s trebuie sa ajunga la N
}
//cout<<"L = "<<L<<endl;
//getchar();

// pentru fiecare L calculam suma secventei si determinam mas sume


smax=0;
for(i=L; i>=1; i--) // sume pentru L, L-1, L-2, ..., 2, 1
{
//cout<<"pentru L = "<<i<<" : "<<endl;
s=0;
for(int k=1; k<=i; k++)
{
fin>>nr;
s=s+nr;
//cout<<"nr = "<<nr<<" s = "<<s<<endl;
//getchar();
}
if(s>smax) smax=s;
//getchar();
}
cout<<"rez2 = "<<smax<<endl;
fout<<smax;

return;
}

int main()
{
fin>>C;
fin>>N;
cout<<"C = "<<C<<" N = "<<N<<’\n’;

if(C==1) cerinta1();
if(C==2) cerinta2();

fin.close();
fout.close();

return 0;
}

Listing 2.2.2: checker-sss.cpp


#include "testlib.h"

using namespace std;

int main()
{
int argc=4;

char* argv[] =
{
(char*)"checker",
(char*)"../teste_sss/19-sss.in", // input
(char*)"../teste_sss/19-sss.out", // rezultat corect
(char*)"sss.out", // rezultat de verificat si acordat punctaj
};

cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";

registerChecker("sss", argc, argv);


compareRemainingLines();
}
Capitolul 3

OJI 2021 - OSEPI

3.1 concurs
Problema 1 - concurs 100 de puncte
În oraşul X va avea loc o nouă ediţie a concursului Y , la care participă 3 echipe având numerele
de concurs 1, 2 şi 3. Echipele pot avea număr diferit de concurenţi.
Ordinea ı̂n care participanţii intră ı̂n concurs este una oarecare. Fiecare concurent are de
susţinut 9 probe. La fiecare probă, un concurent obţine un punctaj exprimat printr-un număr
natural, cuprins ı̂ntre 0 şi 10, inclusiv.
La scurt timp după ce un concurent a susţinut toate cele 9 probe, se afişează performanţa
concurentului sub forma a două numere naturale, astfel:

ˆ primul număr poate fi 1, 2 sau 3 şi reprezintă echipa din care face parte concurentul;
ˆ al doilea număr este obţinut prin concatenarea (alipirea) numerelor ce reprezintă punctajele
nenule obţinute de concurent la cele 9 probe. Dacă un concurent are punctaj 0 la toate
probele atunci al doilea număr este 0.

Punctajul total al unui concurent se obţine adunând punctajele obţinute de acesta la cele 9
probe. Punctajul unei echipe se obţine adunând punctajele totale obţinute de membrii acesteia.
De exemplu, afişajul 2 14102172, semnifică faptul că acest concurent face parte din echipa 2
şi are punctajele nenule 1, 4, 10, 2, 1, 7 şi 2, la 7 dintre cele 9 probe susţinute. La celelalte două
probe a avut punctajul 0. Punctajul său total este 27, contribuţia sa la punctajul echipei 2 fiind
de 27 de puncte.
Este declarată campioană echipa cu punctajul cel mai mare. Dacă mai multe echipe au obţinut
cel mai mare punctaj, atunci toate aceste echipe sunt declarate campioane. Totuşi, dacă toate
echipele au totalizat 0 puncte, atunci nicio echipă nu este declarată campioană.

Cerinţe

Cunoscând numărul N de concurenţi, echipele din care fac parte precum şi punctajele obţinute
de fiecare dintre ei, să se determine:

1. punctajul maxim obţinut de un concurent şi numărul de concurenţi care au obţinut acest
punctaj;
2. numărul sau numerele de concurs ale echipelor declarate campioane, n̂ ordine crescătoare,
şi punctajul obţinut de acestea. Dacă toate echipele au punctajul final 0, se va afişa textul
FARA CAMPION

Date de intrare

Fişierul de intrare concurs.in conţine pe prima linie un număr C (care poate fi 1 sau 2),
indicând cerinţa de rezolvat. Pe a doua linie se găseşte un număr natural N reprezentând numărul
de concurenţi, iar pe fiecare dintre următoarele N linii se găsesc câte două numere naturale,
separate printr-un spaţiu, reprezentând echipa şi punctajele fiecăruia dintre cei N concurenţi, ı̂n
ordinea intrării ı̂n concurs.

21
CAPITOLUL 3. OJI 2021 - OSEPI 3.1. CONCURS 22

Date de ieşire

1. Dacă C 1, fişierul de ieşire concurs.out va conţine pe o singură linie, două numere


naturale, separate printr-un spaţiu, reprezentând punctajul maxim obţinut de un concurent
şi numărul de concurenţi care au obţinut acest punctaj.
2. Dacă C 2, fişierul de ieşire va conţine pe o singură linie textul FARA CAMPION
dacă toate echipele au la final punctajul 0. În caz contrar linia va conţine două, trei sau
patru numere naturale separate prin câte un spaţiu, reprezentând numărul sau numerele de
concurs ale echipelor declarate campioane, ı̂n ordine crescătoare, şi apoi punctajul obţ,inut
de acestea.

Restricţii şi precizări

ˆ Se garantează că datele din fişier respectă formatul precizat.


ˆ 1&N & 100 000.
ˆ Pentru teste ı̂n valoare de 35 de puncte avem C 1.
ˆ Pentru teste ı̂n valoare de 65 de puncte avem C 2.

Exemple:

concurs.in concurs.out Explicaţii


1 31 4 În primul exemplu punctajele obţinute de concurenţi sunt: 23,
7 31, 28, 31, 31, 0, 31 deci punctajul maxim este 31 şi sunt 4
1 1111973 concurenţi cu acest punctaj.
2 3101971
1 1999
2 1010101
3 1010101
30
3 1371910
2 3 62 În al doilea exemplu sunt 5 concurenţi, primul concurent este
5 din echipa 1 şi are punctajul 23, cel de-al doilea concurent este
1 1111973 din echipa 2 şi are punctajul 31, cel de-al treilea este din echipa
2 3101971 1 şi are punctajul 28, al patrulea este din echipa 3 şi are 31
1 1999 de puncte, iar al cincilea este din echipa 3 şi are 31 de puncte.
3 1010101 Punctajul total al echipei 1 este 51, punctajul total al echipei
3 1371910 2 este 31, punctajul total al echipei 3 este 62. Deci, va câştiga
echipa 3 cu 62 de puncte.
2 1 2 3 23 În al treilea exemplu sunt 3 concurenţi, primul concurent este
3 din echipa 2 şi are punctajul 23, cel de-al doilea concurent este
2 1111973 din echipa 3 şi are punctajul 23, cel de-al treilea este din echipa 1
3 31019 şi are punctajul 23. Deci, toate cele 3 echipe au punctaj maxim
1 1010111 23.

3.1.1 Indicaţii de rezolvare

Propunător: Violeta-Marilena Grecea - Colegiul Naţional de Informatică ”Matei Basarab”


Râmnicu-Vâlcea
Pentru rezolvarea problemei se utilizeză date simple, ı̂ntregi cu cel mult 18 cifre, algoritmi cu
cifrele unui număr, calculul maximului.
Atât pentru rezolvarea cerinţei 1 cât şi pentru rezolvarea cerinţei 2 trebuie calculat punctajul
total al unui concurent, ţinând cont de modalitatea de afişare a punctajelor acestuia la cele 9
probe susţinute: pentru fiecare probă punctajul este cuprins ı̂ntre 0 şi 10 inclusiv dar, se afişează
doar punctaje nenule (Se afişează 0 doar dacă toate cele 9 punctaje au fost nule.) De aceea, dacă
CAPITOLUL 3. OJI 2021 - OSEPI 3.1. CONCURS 23

valoarea afişată după susţinerea celor 9 probe este nenulă, stabilirea punctajul total al concuren-
tului se reduce la a calcula suma cifrelor numărului ce reprezintă performanţa sa, cu observaţia
că, dacă cifra prelucrată la un moment dat este 0, se va asocia cu valoarea 1 din faţa sa, şi la
punctajul total se adună 10 puncte.
Cerinţa 1 presupune calculul maximului dintr-un şir şi de câte ori apare acesta.
Cerinţa 2 presupune calculul maximului dintre trei valori, valori asociate puntajelor totale ale
celor 3 echipe, şi afişarea etichetei echipelor care au punctajul egal cu cel maxim.

3.1.2 Cod sursă

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

Listing 3.1.1: concurs balacea.cpp


/*
2.1. Autor: Georgeta Balacea
*/
#include<fstream>
using namespace std;
int x,n,nca,ncb,ncc,pmax,pa,pb,pc,pct,nrc;
int C;
long long P;

ifstream f("concurs.in");
ofstream g("concurs.out");

int main()
{
f>>x>>n;
if(x==2)
{
for(int i=1; i<=n; i++)
{
f>>C>>P;
pct=0;
while(P)
{
if(P%10==0)
{
pct+=10;
P/=100;
}
else
{
pct+=P%10;
P/=10;
}
}

if(C==1) pa+=pct;
else
if(C==2) pb+=pct;
else pc+=pct;
}

pmax=max(pa,max(pb,pc));
if(pmax)
{
if(pa==pmax) g<<1<<’ ’;
if(pb==pmax) g<<2<<’ ’;
if(pc==pmax) g<<3<<’ ’;
g<<pmax<<endl;
}
else
g<<"FARA CAMPION"<<endl;
}
else
{
for(int i=1; i<=n; i++)
{
f>>C>>P;
CAPITOLUL 3. OJI 2021 - OSEPI 3.1. CONCURS 24

pct=0;
long long aux=P;
while(P)
{
if(P%10==0)
{
pct+=10;
P/=100;
}
else
{
pct+=P%10;
P/=10;
}
}

if(pct>pmax)
{
nrc=1;
pmax=pct;
}
else
if(pct==pmax) nrc++;
}

g<<pmax<<" "<<nrc<<endl;
}

f.close();
g.close();

return 0;
}

Listing 3.1.2: concurs dumitrascu.cpp


/*
2.2. Autor Dumitrascu Dan Octavian
*/
#include <fstream>
using namespace std;
ifstream f("concurs.in");
ofstream g("concurs.out");

long long smax, nr, p,x,n,i,c, max1, c1, s, aux, s1, s2, s3;

int main()
{
f>>c;
if (c==1)
{
f>>n;
max1=0;
for (i=1;i<=n;i++)
{
f>>p;
f>>x;
aux=x;
s=0;
while (aux>0)
{
if (aux%10==0)
{
s=s+10;
aux=aux/100;
}
else
{
s=s+aux%10;
aux=aux/10;
}
}

if (s>max1)
{
CAPITOLUL 3. OJI 2021 - OSEPI 3.1. CONCURS 25

max1=s;
nr=1;
}
else
if (s==max1) nr++;
}

g<<max1<<" "<<nr<<"\n";
}
else
{
f>>n;
max1=0;
s1=0;
s2=0;
s3=0;
for (i=1;i<=n;i++)
{
f>>p;
f>>x;
if (x==0) s=0;
else
{
aux=x;
s=0;
while (aux>0)
{
if (aux%10==0)
{
s=s+10;
aux=aux/100;
}
else
{
s=s+aux%10;
aux=aux/10;
}
}

if (p==1) s1=s1+s;
if (p==2) s2=s2+s;
if (p==3) s3=s3+s;
}
}

if (s1==0&&s2==0&&s3==0)
g<<"FARA CAMPION"<<"\n";
else
{
max1=0;
if (s1>max1) max1=s1;
if (s2>max1) max1=s2;
if (s3>max1) max1=s3;
if (s1==max1) g<<"1 "<<max1<<"\n";
if (s2==max1) g<<"2 "<<max1<<"\n";
if (s3==max1) g<<"3 "<<max1<<"\n";
}
}

return 0;
}

Listing 3.1.3: concurs ungureanu.cpp


/*
2.3. Autor: Florentina Ungureanu
*/
#include <fstream>
using namespace std;

ifstream in("concurs.in");
ofstream out("concurs.out");

int E,c, n;
long long x, p1, p2, p3, p, pmax, k;
CAPITOLUL 3. OJI 2021 - OSEPI 3.2. SIR 26

int main()
{
in>>c>>n;
p1=p2=p3=p=pmax=k=0;
for(int i=1; i<=n; i++)
{
in>>E>>x;
p=0;
while(x)
{
if(x%10) p=p+x%10;
else
{
p+=10;
x/= 10;
}
x/= 10;
}

if(c==1)
if(p>pmax)
{
pmax=p;
k=1;
}
else
if(p==pmax) k++;
else;
else
E==1?p1+=p:(E==2?p2+=p:p3+=p);
}

if(c==1) out<<pmax<<’ ’<<k<<’\n’;


else
if(p1+p2+p3==0) out<<"FARA CAMPION\n";
else
{
pmax=max(p1,max(p2,p3));
if(p1==pmax) out<<"1 ";
if(p2==pmax) out<<"2 ";
if(p3==pmax) out<<"3 ";
out<<pmax<<’\n’;
}

return 0;
}

3.1.3 *Rezolvare detaliată

3.2 sir
Problema 2 - sir 100 de puncte
Se dă un şir format din n numere naturale nenule. Elementele şirului sunt numerotate de la
stânga la dreapta ı̂ncepând cu poziţia 1.
Cerinţe
Scrieţi un program care să determine răspunsul pentru ı̂ntrebări de următoarele tipuri:
1. Care este cea mai din stânga poziţie care conţine o valoare strict mai mare decât toate cele
din dreapta sa? - ı̂ntrebare de tipul 1
2. Care sunt poziţiile care conţin valori strict mai mari decât toate cele din stânga lor? -
ı̂ntrebare de tipul 2
3. Dacă fiecărui element aflat ı̂ntre prima şi ultima apariţie a maximului i-am mări valoarea
pentru a ajunge egal cu maximul, care este suma totală a valorilor adăugate? - ı̂ntrebare de
tipul 3
CAPITOLUL 3. OJI 2021 - OSEPI 3.2. SIR 27

Date de intrare

Fişierul de intrare sir.in conţine pe prima linie un număr C (care poate fi 1, 2 sau 3), indicând
tipul ı̂ntrebării. Pe linia a doua se află un număr natural N , reprezentând numărul de elemente
din şir. Pe a treia linie a fişierului de intrare se află N numere naturale, reprezentând elementele
şirului, date de la stânga la dreapta (cel mai din stânga are poziţia 1 şi cel mai din dreapta are
poziţia N ). Numerele de pe această linie sunt separate prin câte un spaţiu.

Date de ieşire

Dacă C 1, fişierul de ieşire sir.out trebuie să conţină un număr natural ce reprezintă
răspunsul la o ı̂ntrebare de tipul 1.
Dacă C 2, fişierul de ieşire trebuie să conţină, separaţi prin câte un spaţiu şi ı̂n ordine
crescătoare, indicii determinaţi ca răspuns la o ı̂ntrebare de tipul 2.
Dacă C 3, fişierul de ieşire trebuie să conţină un număr ce reprezintă răspunsul la o ı̂ntrebare
de tipul 3.

Restricţii şi precizări

ˆ 1&C & 3.
ˆ 1 & N &100 000.
ˆ Numerele din şirul dat sunt cuprinse ı̂ntre 1 şi 10 000, inclusiv.
ˆ Pentru teste ı̂n valoare de 24 de puncte avem C 1.
ˆ Pentru teste ı̂n valoare de 32 de puncte avem C 2.
ˆ Pentru teste ı̂n valoare de 44 de puncte avem C 3.

Exemple:

sir.in sir.out Explicaţii


1 6 Pentru exemplul 1, Cea mai din stânga poziţie a unei valori care
7 este mai mare decât toate cele din dreapta sa este 6 (acolo unde
3225354 se află valoarea 5)
2 14 Pentru exemplul 2, 1 şi 4 sunt poziţiile unde se afla valori mai
7 mari decât toate cele din stânga lor.
3225354
3 6 Pentru exemplul 3, maximul fiiind 5, conform explicaţ iei de
8 la ı̂ntrebarea de tipul 3, trebuie mărite două elemente pentru
3225315 a ajunge egale cu 5. Acestea sunt cel aflat pe poziţia 5 (de
4 mărit cu 2) precum şi cel de pe poziţia 6 (de mărit cu 4). Suma
valorilor cu care avem de mărit este 2 + 4 = 6.
3 0 Pentru exemplul 4, maximul este 7 şi apare o singură dată, deci
5 nu se mai măreşte nicio valoare.
32753

3.2.1 Indicaţii de rezolvare

Propunător: prof. Marius Nicoli - Colegiul Naţional ”Fraţii Buzeşti” Craiova


Pentru rezolvarea cerinţei 1 este necesară identificarea celei mai din dreapta poziţii pe care se
află valoarea maximă. Acest lucru se realizează la citirea datelor, păstrând o variabilă pe care
o actualizăm cu indicele curent, ı̂n momentul schimbării maximului sau ı̂n momentul găsirii unei
valori egale cu maximul.
Pentru rezolvarea cerinţei 2 trebuie identificate momentele ı̂n care maximul se schimbă. Deci,
la citirea datelor, atunci când valoarea curentă este strict mai mare decât maximul deja ı̂ntâlnit,
actualizăm maximul şi afişam poziţia curentă.
CAPITOLUL 3. OJI 2021 - OSEPI 3.2. SIR 28

Pentru rezolvarea cerinţei 3 păstr


u am o variabilă S pe care o gestionăm astfel:

ˆ Când se schimbă maximul reiniţializăm S cu 0.


ˆ Dacă valoarea curentă x nu schimbă maximul, adunăm la S diferenţa maxim  x.
ˆ De fiecare dată când ı̂ntâlnim o valoare egală cu maximul, salvăm valoarea curentă a lui S
(ı̂nainte să o reiniţializăm) ı̂ntr-o variabilă sol, pe care la final o afişăm.

Mai sus am descris o strategie de a procesa informaţiile dintr-o secvenţă cuprinsă ı̂ntre primul
şi ultimul element cu valoarea maximă, realizând calculele ı̂n timpul citirii datelor.

3.2.2 Cod sursă

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

Listing 3.2.1: sir balacea.cpp


/*
3.1.Autor Georgeta Balacea
*/
#include<fstream>
using namespace std;

int C,N,x,maxi,pmax,i,j,s,S;

ifstream f("sir.in");
ofstream g("sir.out");

int main()
{
f>>C>>N;
if(C==1)
{
for(i=1; i<=N; i++)
{
f>>x;
if(x>=maxi)
{
maxi=x;
pmax=i;
}
}

g<<pmax<<endl;
}
else if(C==2)
{
for(i=1; i<=N; i++)
{
f>>x;
if(x>maxi)
{
maxi=x;
g<<i<<" ";
}
}

g<<endl;
}
else
{
for(i=1; i<=N; i++)
{
f>>x;
if(x>maxi)
{
maxi=x;
s=0;
}
else
{
CAPITOLUL 3. OJI 2021 - OSEPI 3.2. SIR 29

s+=maxi-x;
if(x==maxi) S=s;
}
}

g<<S<<endl;
}

f.close();
g.close();

return 0;
}

Listing 3.2.2: sir dumitrascu.cpp


/*
3.2. Autor Dumitrascu Dan Octavian
*/
#include <fstream>
using namespace std;

ifstream f("sir.in");
ofstream g("sir.out");

int c,n,i,x,max1,p1,p2,sf,p,s;

int main()
{
f>>c;
if (c==1)
{
f>>n;
max1=0;
for (i=1;i<=n;i++)
{
f>>x;
if (x>=max1)
{
max1=x;
p=i;
}
}

g<<p<<"\n";
}
else
if (c==2)
{
f>>n;
max1=0;
for (i=1;i<=n;i++)
{
f>>x;
if (x>max1)
{
max1=x;
g<<i<<" ";
}
}

g<<"\n";
}
else
{
f>>n;
max1=0;
p1=0;
p2=0;
s=0;
sf=0;
for (i=1;i<=n;i++)
{
f>>x;
s=s+x;
CAPITOLUL 3. OJI 2021 - OSEPI 3.2. SIR 30

if (x>max1)
{
max1=x;
p1=i;
p2=p1;
s=0;
}
else
if (x==max1)
{
p2=i;
sf=s;
}
}

g<<(p2-p1-1)*max1-(sf-max1);
}

return 0;
}

Listing 3.2.3: sir ungureanu.cpp


/*
3.3. Autor: Florentina Ungureanu
*/
#include <fstream>
using namespace std;

ifstream in ("sir.in");
ofstream out("sir.out");

int n, c, x, maxi, i, poz, g, rez;

int main ()
{
in>>c>>n;
switch (c)
{
case 1:
{
maxi=poz= 0;
for (i=1; i<=n; i++)
{
in>>x;
if (x >= maxi)
{
maxi = x;
poz = i;
}
}

out<<poz<<’\n’;
return 0;
}

case 2:
{
maxi=0;
for (i=1; i<=n; i++)
{
in>>x;
if (x > maxi)
{
maxi = x;
out<<i<<’ ’;
}
}

out<<’\n’;

return 0;
}

case 3:
CAPITOLUL 3. OJI 2021 - OSEPI 3.2. SIR 31

{
for (i=1; i<=n; i++)
{
in>>x;
if (x > maxi)
{
maxi = x;
g = 0;
}
else g += maxi-x;

if (x == maxi)rez = g;
}

out<<rez<<’\n’;
}
}

return 0;
}

3.2.3 *Rezolvare detaliată


Capitolul 4

OJI 2020

4.1 cartonase
Problema 1 - cartonase 100 de puncte
Ionel are N cartonaşe. Fiecare cartonaş are ı̂nscrise două numere (un număr, s, ı̂n partea
stângă, şi celălalt număr, d, ı̂n partea dreaptă).
El a aşezat cartonaşele ı̂ntr-un şir, lipite unul de celălalt, astfel ı̂ncât numărul din partea
dreaptă a primului cartonaş este lipit de numărul din partea stângă a celui de-al doilea cartonaş,
numărul din partea dreaptă a celui de al doilea cartonaş este lipit de numărul din partea stângă
a celui de-al treilea cartonaş etc.
Spunem că două cartonaşe alăturate ”se potrivesc” dacă numărul din dreapta al primului
cartonaş este egal cu numărul din stânga al celui de al doilea cartonaş.
Ionel observă că sunt perechi de cartonaşe alăturate care ”se potrivesc” şi chiar secvenţe de
mai multe cartonaşe alăturate, ı̂n care primul ”se potriveşte” cu al doilea, al doilea ”se potriveşte”
cu al treilea etc.

Cerinţe

Scrieţi un program care să citească numărul N de cartonaşe, numerele ı̂nscrise pe fiecare
cartonaş şi determină:
1) Numărul de perechi de cartonaşe care ”se potrivesc”.
2) Numărul de cartonaşe din cea mai lungă secvenţă ı̂n care fiecare două cartonaşe alăturate
”se potrivesc”.
3) Numărul de secvenţe cu număr maxim de cartonaşe care ”se potrivesc”.

Date de intrare

Fişierul de intrare cartonase.in conţine doar numere naturale nenule:


- pe prima linie se găseşte numărul C care poate avea doar valorile 1, 2 sau 3 şi reprezintă
cerinţa care urmează a fi rezolvată. Pe a doua linie a fişierului se găseşte numărul natural
N , cu semnificaţia din enunţ.
- pe fiecare dintre următoarele N linii se află, ı̂n acestă ordine, câte două numere naturale s
şi d, separate printr-un spaţiu, cu semnificaţia din enunţ pentru un cartonaş. Perechile de
numere sunt date ı̂n ordinea ı̂n care cartonaşele corespunzătoare lor apar ı̂n şirul lui Ionel.

Date de ieşire

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


răspunsul la cerinţa specificată.

Restricţii şi precizări

a 1&N & 500; 1 & s & 10 000; 1 & d & 10 000


a Pentru rezolvarea fiecărei cerinţe se obţin câte 30 de puncte.

32
CAPITOLUL 4. OJI 2020 4.1. CARTONASE 33

Exemple:

cartonase.in cartonase.out Explicaţii


1 2 Sunt 2 perechi de cartonaşe alăturate care ”se potrivesc”:
5 - primul cu al doilea (2 10 şi 10 5)
2 10 - al treilea cu al patrulea (10 2 şi 2 10)
10 5
10 2
2 10
37 5
2 4 Primele patru cartonase formează o secvenţă ı̂n care fiecare
5 două cartonaşe alăturate ”se potrivesc”:
2 10 - primul cartonaş cu al doilea (2 10 şi 10 5)
10 5 - al doilea cartonaş cu al treilea (10 5 şi 5 2)
52 - al treilea cartonaş cu al patrulea (5 2 şi 2 10)
2 10
37 5
3 2 Sunt maximum doua cartonaşe alăturate care se potrivesc.
6 În fisier există două secvenţe de câte două cartonaşe care ”se
2 10 potrivesc”:
10 5 primele două cartonaşe şi al patrulea cu al cincilea cartonaş
28
62
2 10
37 5

Timp maxim de executare/test: 0.5 secunde


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

4.1.1 Indicaţii de rezolvare


Descriere a unei soluţii posibile
Se citesc numerele de pe cartonaşe, reţinând la un moment dat numerele de pe două cartonaşe
alăturate (citite consecutiv):
- ı̂n s1, d1 reţinem numerele de pe cartonaşul anterior citit
- ı̂n s2, d2 citim numerele de pe cartonaşul curent

Cerinţa 1

- utilizăm o variabilă de tip contor pentru a număra perechile


- pentru fiecare pereche de cartonaşe alăturate (s1, d1, s2, d2), verificăm dacă ”se potrivesc”
(dacă d1 s2)

Cerinţa 2

- utilizăm o variabilă de tip contor pentru a număra cartonaşele


- dacă d1 s2 adunăm 1 la contorul care numără cartonaşele dintr-o secvenţă. Comparăm
acest contor cu maximul(L) şi reţinem ı̂n L valoarea mai mare.
- dacă d1 j s2, iniţializăm contorul cu 1.

Cerinţa 3

- utilizăm o variabilă de tip contor pentru a număra cartonaşele


CAPITOLUL 4. OJI 2020 4.1. CARTONASE 34

- dacă d1 s2 adunăm 1 la contorul care numără cartonaşele dintr-o secvenţă. Comparăm


acest contor cu maximul(L) şi reţinem ı̂n L valoarea mai mare.
- dacă d1 j s2, iniţializăm contorul cu 1.
- Numărăm secvenţele de lungime egală cu L ı̂ntr-un alt contor care se resetează atunci când
se modifică L.

4.1.2 Cod sursă

Listing 4.1.1: cartonase.c


1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4
5 int N, R, X, Y, K, P, i, Max, Lc, Nr, Nrs, x, y;
6
7 int main()
8 {
9 freopen("cartonase.in", "r",stdin);
10 freopen("cartonase.out","w",stdout);
11
12 scanf("%d\n",&P);
13 assert(P>0 && P<4);
14
15 scanf("%d\n",&N);
16 assert(N>0 && N<501);
17
18 Nr = Max = 0;
19 Lc = 1;
20 Nrs = 0;
21
22 scanf("%d %d", &X, &Y);
23 assert(X>0 && X<10001);
24 assert(Y>0 && Y<10001);
25
26 for(i = 2; i <= N ; i++)
27 {
28 scanf("%d %d", &x, &y);
29 assert(x>0 && x<10001);
30 assert(y>0 && y<10001);
31
32 if (Y == x)
33 {
34 Nr++;
35 Lc++;
36 }
37 else Lc = 1;
38
39 if(Lc > Max) {Max = Lc; Nrs = 1;}
40 else if (Lc == Max) Nrs++;
41
42 Y = y;
43 }
44
45 if(P==1) printf("%d\n", Nr);
46 else if (P==2 ) printf("%d\n", Max);
47 else printf("%d\n", Nrs);
48
49 return 0;
50 }

Listing 4.1.2: cartonase.cpp


#include <fstream>

using namespace std;

int main()
{
ifstream in ("cartonase.in");
CAPITOLUL 4. OJI 2020 4.1. CARTONASE 35

ofstream out ("cartonase.out");

int n,L=1,P=0,C,s1,d1,s2,d2,i,nr=0,i1,i2,cate;

in>>C>>n;

if(C==1)
{
in>>s1>>d1;
for(i=2;i<=n;++i)
{
in>>s2>>d2;
if(d1==s2)
P++;
s1=s2;
d1=d2;
}

out<<P<<endl;
}

if(C==2)
{
in>>s1>>d1;
nr=1;
i1=1;
i2=1;
for(i=2;i<=n;++i)
{
in>>s2>>d2;
if(d1==s2)
{
nr++;
if(nr>L){L=nr;}
}
else {nr=1;}

s1=s2;
d1=d2;
}

out<<L<<endl;
}

if(C==3)
{
in>>s1>>d1;
nr=1;
cate=1;
for(i=2;i<=n;++i)
{
in>>s2>>d2;
if(d1==s2)
{
nr++;
if(nr>L){L=nr; cate=1;}
else if(nr==L) cate++;
}
else {nr=1;}

s1=s2;
d1=d2;
}

out<<cate<<endl;
}

return 0;
}

Listing 4.1.3: cartonase1.cpp


/*
Implementare Dan Pracsiu
*/
CAPITOLUL 4. OJI 2020 4.1. CARTONASE 36

#include <fstream>

using namespace std;

int main()
{
int i, n;
int task; /// cerinta
int a1, b1; /// a1,b1= valorile de pe cartonasul precedent
int a2, b2; /// a2, b2 = valorile de pe cartonasul curent
int nrPerechi; /// pentru cerinta 1
int maxLen, L, cnt;

/// maxLen = lungimea maxima a unei secvente de cartonase


/// cnt = numarul secventelor maximale

ifstream fin("cartonase.in");
ofstream fout("cartonase.out");

fin >> task >> n;

if (task == 1) /// cerinta 1


{
nrPerechi = 0;
fin >> a1 >> b1;
for (i = 2; i <= n; i++)
{
fin >> a2 >> b2;
if (a2 == b1) nrPerechi++;
a1 = a2;
b1 = b2;
}
fout << nrPerechi << "\n";
}
else /// cerintele 2 si 3
{
fin >> a1 >> b1;
maxLen = 1;
cnt = 1;
L = 1;
for (i = 2; i <= n; i++)
{
fin >> a2 >> b2;
if (a2 == b1) L++;
else L = 1;

if (maxLen < L)
{
maxLen = L;
cnt = 1;
}
else if (maxLen == L) cnt++;

a1 = a2;
b1 = b2;
}

if (task == 2) fout << maxLen << "\n";


else fout << cnt << "\n";
}

fin.close();
fout.close();

return 0;
}

Listing 4.1.4: cartonase2.cpp


#include<fstream>

using namespace std;

int n,s,d,nr,c,S,D,lc,lmax;
CAPITOLUL 4. OJI 2020 4.2. TAI 37

ifstream f("cartonase.in");
ofstream g("cartonase.out");

int main()
{
f>>c>>n;
///cerinta 1
if(c==1)
{ f>>s>>d;
for(int i=2;i<=n;i++)
{
f>>S>>D;
if(d==S) nr++;
s=S;d=D;
}
g<<nr<<endl;
}
else
{ ///cerintele 2 si 3
f>>s>>d;lmax=1;nr=1;lc=1;
for(int i=2;i<=n;i++)
{
f>>S>>D;
if(d==S) lc++;
else
lc=1;
if(lc>lmax)
{lmax=lc;nr=1;}
else
if(lc==lmax) nr++;
s=S;d=D;
}
///afisare cerinta 2
if(c==2)
g<<lmax<<endl;
else g<<nr<<endl; ///afisare cerinta 3
}

f.close();
g.close();

return 0;
}

4.1.3 *Rezolvare detaliată

4.2 tai
Problema 2 - tai 100 de puncte
Un număr este prim dacă are exact doi divizori naturali. Prin tăierea unui număr ı̂n p părţi
ı̂nţelegem ı̂mpărţirea acestuia ı̂n p numere, fiecare de cel puţin o cifră, astfel ı̂ncât prin alipirea
numerelor obţinute de la stânga la dreapta obţinem numărul iniţial.
De exemplu, dacă ı̂mpărţim numărul 12045 ı̂n două părţi avem patru variante de tăiere
obţinându-se numerele: 1 şi 2045; 12 şi 045; 120 şi 45; 1204 şi 5. Dacă ı̂l ı̂mpărţim ı̂n trei
părţi avem şase variante de tăiere obţinându-se numerele 1, 2 şi 045; 1, 20 şi 45; 1, 204 şi 5; 12, 0
şi 45; 12, 04 şi 5; 120, 4 şi 5.

Cerinţe

Se consideră un şir format din N numere naturale.


1) Determinaţi cel mai mare număr prim din şirul celor N numere.
2) Determinaţi cel mai mare număr prim dintre cele obţinute prin tăierea ı̂n două părţi a
fiecărui număr din şirul celor N .
3) Determinaţi cel mai mare număr prim dintre cele obţinute prin tăierea ı̂n trei părţi a fiecărui
număr din şirul celor N .
CAPITOLUL 4. OJI 2020 4.2. TAI 38

Date de intrare

Pe prima linie a fişierului tai.in se găseşte numărul C care poate avea doar valorile 1, 2 sau 3
şi reprezintă cerinţa care urmează a fi rezolvată. Pe a doua linie se găseşte N , cu semnificaţia din
enunţ, iar pe a treia linie se găseşte şirul celor N numere naturale despărţite prin câte un spaţiu.

Date de ieşire

În fişierul de ieşire tai.out pe prima linie se va afişa un număr natural reprezentând răspunsul
la cerinţa specificată.

Restricţii şi precizări

a 1&N & 100


a 0 & orice număr din şir & 1 000 000 000
a Pentru cerinţele 2 şi 3 se garantează că pentru toate numerele din şir se poate efectua tăierea
a Pentru cerinţa 1 dacă şirul nu conţine numere prime se va afişa 0
a Pentru cerinţele 2 şi 3 dacă ı̂n urma tăierilor nu se obţine niciun număr prim, se va afişa 0
a Pentru rezolvarea fiecărei cerinţe se obţin 30 de puncte.

Exemple:

tai.in tai.out Explicaţii


1 17 Numere prime din şir sunt 2, 13 şi 17, iar maximul este 17
5
2 13 21 17 1
2 19 Din 23 se obţin două numere 2 şi 3, din 196 se pot obţine nu-
3 merele 1 şi 96 sau 19 şi 6, iar din 27 se obţin numerele 2 şi 7.
23 196 27 Cel mai mare număr prim care se poate obţine este 19.
3 71 Din numărul 1234 se pot obţine numerele: 1, 2, 34 sau 1, 23, 4
3 sau 12, 3, 4.
1234 17119 5678 Din numărul 17119 se pot obţine numerele: 1, 7 şi 119 sau 1, 71
şi 19 sau 1, 711 şi 9 sau 17, 1 şi 19 sau 17, 11 şi 9.
Din numărul 5678 se pot obţine numerele: 5, 6 şi 78 sau 5, 67
şi 8 sau 56, 7 şi 8.
Cel mai mare număr prim care se poate obţine este 71.

Timp maxim de executare/test: 0.5 secunde


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

4.2.1 Indicaţii de rezolvare


Descriere a unei soluţii posibile
Pentru ca un număr să fie prim folosim algoritm de numărare de divizori sau de determinare
a primului divizor propriu.
În funcţie de algoritmul folosit se obţin punctaje parţiale. Optim pentru problema dată este
să caut un divizor propriu şi să mă opresc la primul divizor propriu.
Folosim propietatea:
Dacă un număr x are cel puţin un divizor propriu, notăm cu d cel mai mic divizor propriu al
său. Ştim că d şi x©d sunt divizorii lui x. Atunci d ˜ d $ x.
Cerinţa 1
- Calculăm maximul numerelor
Cerinţa 2
CAPITOLUL 4. OJI 2020 4.2. TAI 39

- Vom ı̂mpărţi numerele date ı̂n exact două numere şi vom calcula maximul celor prime
Cerinţa 3
- Vom ı̂mpărţi numerele date ı̂n exact 3 numere ca ı̂n enunţ şi vom calcula maximul celor
prime. Se pot ı̂mpărţi direct ı̂n 3 părţi numerele cu două strucuturi repetitive şi folosind puterile
lui 10 sau se poate ı̂mpărţi o dată ı̂n 2 părţi şi o parte iar ı̂n 2 părţi.

4.2.2 Cod sursă

Listing 4.2.1: tai.c


1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4
5 #define inf 1000000000
6
7 int N, R, X, K, P, j, i, ok, cif, x, d, pz, p, a, b, c, Max,cm, nc, Nr, p1, k;
8
9 int main()
10 {
11 freopen("tai.in", "r",stdin);
12 freopen("tai.out","w",stdout);
13
14 scanf("%d\n",&P);
15 assert(P>0 && P<4);
16
17 scanf("%d\n",&N);
18 assert(N>0 && N<101);
19
20 if(P==1)
21 {
22 Max = 0;
23 for( i = 1; i <= N ; i++)
24 {
25 scanf("%d", &X);
26 assert(X>=0 && X<=inf);
27 if(X<2)
28 ok = 0;
29 else
30 ok = 1;
31
32 for(d = 2; d * d <= X && ok; d++)
33 if(X%d == 0)
34 ok = 0;
35
36 if(ok && X > Max)
37 Max = X;
38 }
39 printf("%d\n", Max);
40 }
41
42 if(P==2)
43 {
44 Max = 0;
45 for( i = 1; i <= N ; i++)
46 {
47 scanf("%d", &x);
48 assert(x>=0 && x<=inf);
49 pz = 1;
50 ok = 1;
51 while (x/pz > 0)
52 pz*=10;
53 p = pz/10;
54 while (p>9)
55 {
56 a = x % p;
57 b = x / p;
58
59 ok = 1;
60 for(d = 2; d * d <= a && ok; d++)
61 if(a % d == 0)
CAPITOLUL 4. OJI 2020 4.2. TAI 40

62 ok = 0;
63
64 if(a>1 && ok && a > Max)
65 Max = a;
66
67 ok = 1;
68 for(d = 2; d * d <= b && ok; d++)
69 if(b % d == 0)
70 ok = 0;
71
72 if(b>1 && ok && b > Max)
73 Max = b;
74 p/=10;
75 }
76 }
77 printf("%d\n", Max);
78 }
79
80 if(P==3)
81 {
82 Max = 0;
83 for( k = 1; k <= N ; k++)
84 {
85 scanf("%d", &X);
86 assert(X>=0 && X<=inf);
87 nc = 0;
88 pz = 1;
89 while (X/pz > 0)
90 {
91 pz*=10;
92 nc++;
93 }
94 pz = pz/10;
95 p1 = p = pz;
96 for(i = 1; i< nc -1; i++)
97 {
98 c = X / p1;
99 x = X % p1;
100 p = p1 / 10;
101
102 ok = 1;
103 for(d = 2; d * d <= c && ok; d++)
104 if(c % d == 0)
105 ok = 0;
106
107 if(c>1 && ok && c > Max)
108 Max = c;
109 while (p>9)
110 {
111 a = x % p;
112 b = x / p;
113
114 ok = 1;
115 for(d = 2; d * d <= a && ok; d++)
116 if(a % d == 0)
117 ok = 0;
118
119 if(a>1 && ok && a > Max)
120 Max = a;
121
122 ok = 1;
123 for(d = 2; d * d <= b && ok; d++)
124 if(b % d == 0)
125 ok = 0;
126
127 if(b>1 && ok && b > Max)
128 Max = b;
129 p/=10;
130 }
131 p1 /=10;
132 }
133 }
134
135 printf("%d\n", Max);
136 }
137
CAPITOLUL 4. OJI 2020 4.2. TAI 41

138 return 0;
139 }

Listing 4.2.2: tai.cpp


#include <fstream>

using namespace std;

ifstream f("tai.in");
ofstream g("tai.out");

int N,i,x,nd,d,C,aux,y1,y2,y3,z,t,w,p,max1,x1,x2,q;

int main()
{
f>>C;
if (C==1)
{
f>>N;
max1=0;
for (i=1;i<=N;i++)
{
f>>x;
for (d=2;d*d<=x;d++)
if (x%d==0) break;
if (x>1&&d*d>x&& x>max1)
max1=x;
}
g<<max1<<"\n";
}
else
if (C==2)
{
max1=0;
f>>N;
for (i=1;i<=N;i++)
{
f>>x;
aux=x;
p=10;
while (aux>=p)
{
x1=aux%p;
x2=aux/p;
//g<<x<<"="<<x2<<" "<<x1<<endl;
p=p*10;
for (d=2;d*d<=x1;d++)
if (x1%d==0) break;
if (x1>1&&d*d>x1&& x1>max1)
max1=x1;
for (d=2;d*d<=x2;d++)
if (x2%d==0) break;
if (x2>1&&d*d>x2&& x2>max1)
max1=x2;
}
}
g<<max1<<"\n";
}
else
{
f>>N;
max1=0;
for (i=1;i<=N;i++)
{
f>>x;
aux=x;
p=10;
while (aux>p*10)
p=p*10;
for (t=10;t*10<=p;t=t*10)
for (q=10;q*t<=p;q=q*10)
{
y1=x%t;
z=x/t;
CAPITOLUL 4. OJI 2020 4.2. TAI 42

y2=z%q;
y3=z/q;
for (d=2;d*d<=y1;d++)
if (y1%d==0) break;
if (y1>1&&d*d>y1&& y1>max1)
max1=y1;
for (d=2;d*d<=y2;d++)
if (y2%d==0) break;
if (y2>1&&d*d>y2&& y2>max1)
max1=y2;
for (d=2;d*d<=y3;d++)
if (y3%d==0) break;
if (y3>1&&d*d>y3&& y3>max1)
max1=y3;
}
}
g<<max1<<"\n";
}

return 0;
}

Listing 4.2.3: tai1.cpp


#include <iostream>
#include <fstream>

using namespace std;

ifstream in("tai.in");
ofstream out("tai.out");

int prim(int x)
{
int ok,d;
ok=1;
if(x<=1)ok=0;
for(d=2;d*d<=x&&ok;++d)
if(x%d==0) ok=0;
return ok;
}

int main()
{
int N,i,x,ok,xmax=0,C,d,y,x1,x2,p,p2,x21,x22;

in>>C>>N;

if(C==1)
{
for(i=1;i<=N;++i)
{
in>>x;

if(prim(x))if(x>xmax)xmax=x;
}
out<<xmax;
}

if(C==2)
{
for(i=1;i<=N;++i)
{
in>>y;
p=10;
while(p<y)
{
x1=y/p;
x2=y%p;
if(prim(x1))
if(x1>xmax) xmax=x1;

if(prim(x2))if(x2>xmax)xmax=x2;
p=p*10;
}
CAPITOLUL 4. OJI 2020 4.2. TAI 43

}
out<<xmax;
}

if(C==3)
{
for(i=1;i<=N;++i)
{
in>>y;
p=100;
while(p<y)
{
x1=y/p;
x2=y%p;
if(prim(x1))
if(x1>xmax) xmax=x1;

p2=10;
while(p2<x2)
{
x21=x2/p2;
x22=x2%p2;
if(prim(x21))
if(x21>xmax) xmax=x21;
if(prim(x22))
if(x22>xmax) xmax=x22;
p2=p2*10;
}
p=p*10;
}
}

out<<xmax;
}

return 0;
}

Listing 4.2.4: tai2.cpp


#include <fstream>

using namespace std;

int Prim(int n)
{
if (n <= 1) return 0;
if (n == 2) return 1;
if (n % 2 == 0) return 0;
for (int i = 3; i * i <= n; i += 2)
if (n % i == 0) return 0;
return 1;
}

int main()
{
int x, n, task, p, q, M = 0;

ifstream fin("tai.in");
ofstream fout("tai.out");

fin >> task >> n;

if (task == 1)
{
while (n--)
{
fin >> x;
if (Prim(x) && x > M) M = x;
}
}
else if (task == 2)
{
while (n--)
{
CAPITOLUL 4. OJI 2020 4.2. TAI 44

fin >> x;
p = 10;
while (x / p > 0)
{
if (Prim(x / p) && M < x / p) M = x / p;
if (Prim(x % p) && M < x % p) M = x % p;
p *= 10;
}
}
}
else /// task = 3
{
while (n--)
{
fin >> x;
for (p = 100; x / p > 0; p *= 10)
for (q = 10; q < p; q *= 10)
{
if (Prim(x / p) && M < x / p) M = x / p;
if (Prim(x % p / q) && M < x % p / q) M = x % p / q;
if (Prim(x % q) && M < x % q) M = x % q;
}
}
}

fout << M << "\n";


fin.close();
fout.close();
return 0;
}

Listing 4.2.5: tai3.cpp


#include <fstream>

using namespace std;

ifstream f("tai.in");
ofstream g("tai.out");

int c,n,a;
bool eprim(int);
int nr_cifre(int);
int putere(int);

int main()
{
f>>c>>n;
if(c==1)
{
int sol=0;
for(int i=1; i<=n; i++)
{
f>>a;
if(eprim(a))
sol=max(sol,a);
}
g<<sol;
}

if(c==2)
{
int sol=0;
for(int i=1; i<=n; i++)
{
f>>a;
int cnt=nr_cifre(a)-1;
for(int j=1; j<=cnt; j++)
{
int aux=putere(j);
int b=a%aux,c=a/aux;
if(eprim(b))
sol=max(sol,b);
if(eprim(c))
sol=max(sol,c);
CAPITOLUL 4. OJI 2020 4.2. TAI 45

}
}
g<<sol;
}

if(c==3)
{
int sol=0;
for(int i=1; i<=n; i++)
{
f>>a;
int cnt=nr_cifre(a)-1;
for(int j=1; j<=cnt; j++)
{
int aux=putere(j);
int b=a%aux;
int c=a/aux;
if(b>=10)
{
int cntt=nr_cifre(b)-1;
for(int jj=1; jj<=cntt; jj++)
{
int auxx=putere(jj);
int bb=b%auxx;
int cc=b/auxx;
if(eprim(bb))
sol=max(sol,bb);
if(eprim(cc))
sol=max(sol,cc);
}
if(eprim(c)) sol=max(sol,c);
}
else
{
int cntt=nr_cifre(c)-1;
for(int jj=1; jj<=cntt; jj++)
{
int auxx=putere(jj);
int bb=c%auxx;
int cc=c/auxx;
if(eprim(bb))
sol=max(sol,bb);
if(eprim(cc))
sol=max(sol,cc);
}
if(eprim(b)) sol=max(sol,b);

}
}
}
g<<sol;
}

return 0;
}

bool eprim(int x)
{
if(x==1||x==0)
return false;
if(x==2)
return true;
if(x%2==0)
return false;
for(int i=3; i*i<=x; i+=2)
if(x%i==0)
return false;
return true;
}

int nr_cifre(int x)
{
int cnt=0;
while(x)
{
x/=10;
CAPITOLUL 4. OJI 2020 4.2. TAI 46

cnt++;
}
return cnt;
}

int putere(int x)
{
int p=1;
while(x)
{
p*=10;
x--;
}
return p;
}

Listing 4.2.6: tai4.cpp


#include<fstream>

using namespace std;

ifstream f("tai.in");
ofstream g("tai.out");

bool prim(long long x)


{
if(x==2) return 1;
if(x%2==0) return 0;
if(x<2) return 0;

for(int d=3; d*d<=x; d=d+2)


if(x%d==0) return 0;

return 1;
}

int nrc(long long x)


{
int N=0;
while(x)
{
N++;
x/=10;
}
return N;
}

long long c,x,i,n,max_p,n1,n2,n3,Nc;


long long pz[]={1,10,100,1000,10000,100000,1000000,10000000,
100000000,1000000000,10000000000};

int main()
{
f>>c;
if(c==1)
{
f>>n;
for(i=1;i<=n;i++)
{
f>>x;
if(prim(x))
max_p=max(x,max_p);
}
if(max_p==1) max_p=0;
g<<max_p<<endl;
}
else
if(c==2)
{
f>>n;
for(i=1;i<=n;i++)
{
f>>x;
Nc=nrc(x);
CAPITOLUL 4. OJI 2020 4.2. TAI 47

for(int j=1;j<Nc;j++)
{
n1=x/pz[j];
n2=x%pz[j];
if(prim(n1)) max_p=max(max_p,n1);
if(prim(n2)) max_p=max(max_p,n2);
}
}
g<<max_p<<endl;
}
else
{
f>>n;

for(i=1;i<=n;i++)
{
f>>x;
Nc=nrc(x);
long long X=x;

for(int j=1;j<Nc-1;j++)
{
n3=x%pz[j];
x=x/pz[j];
int Nrc=Nc-j;

for(int k=1;k<Nrc;k++)
{
n2=x%pz[k];
n1=x/pz[k];
// g<<n1<<" "<<n2<<" "<<n3<<endl;
if(prim(n1)) max_p=max(max_p,n1);
if(prim(n2)) max_p=max(max_p,n2);
if(prim(n3)) max_p=max(max_p,n3);
}
x=X;
}
}
g<<max_p<<endl;
}

f.close();
g.close();

return 0;
}

4.2.3 *Rezolvare detaliată


Capitolul 5

OJI 2019

5.1 Aur
Problema 1 - Aur 90 de
puncte
După ce au mers ı̂mpreună prin lume, Păcală şi Tândală au strâns o căruţă plină de bănuţi
de aur, iar acum ı̂i răstoarnă pe toţi ı̂n curtea casei şi ı̂i ı̂mpart ı̂n N grămezi. Păcală numără
bănuţii din fiecare grămadă şi ı̂i dictează lui Tândală N numere naturale pe care acesta trebuie
să le scrie ı̂n ordine pe o tăbliţă. După ore bune de muncă, Păcală constată că Tândală a scris pe
un singur rând, ı̂n ordine, de la stânga la dreapta, toate numerele dictate de el, dar lipite unul de
altul. Acum pe tăbliţă e doar un şir lung de cifre. Ce să facă Păcală acum?

Cerinţe

Cunoscând cele N numere naturale dictate de Păcală, scrieţi un program care să determine:
1. numărul cifrelor scrise pe tăbliţă de Tândală;
2. ce-a de-a K-a cifră de pe tăbliţă, ı̂n ordine de la stânga la dreapta;
3. cel mai mare număr ce se poate forma cu exact P cifre alăturate de pe tăbliţă, considerate
ı̂n ordine de la stânga la dreapta.

Date de intrare

Fişierul aur.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 dacă cerinţa este 1, sau două numere naturale N şi
K (despărţite printr-un spaţiu) dacă cerinţa este 2, sau două numere naturale N şi P (despărţite
printr-un spaţiu) dacă cerinţa este 3.
- pe cea de-a treia linie, N numere naturale despărţite prin câte un spaţiu, ce reprezintă, ı̂n
ordine, numerele pe care Păcală i le dictează lui Tândală.

Date de ieşire

Fişierul aur.out va conţine pe prima linie un singur număr natural ce reprezintă rezultatul de-
terminat conform fiecărei cerinţe.

Restricţii şi precizări

a 1 & N & 100000 şi 1 & K & 900000; Se garantează că există cel puţin K cifre scrise pe tăbliţă.
a 1 & P & 18; Se garantează ca există cel puţin P cifre scrise pe tăbliţă.
a toate numere dictate de Păcală sunt nenule şi au cel mult 9 cifre fiecare;
a Pentru rezolvarea corectă a primei cerinţe se acordă 20 de puncte, pentru rezolvarea corectă
a celei de-a doua cerinţe se acordă 30 de puncte, iar pentru rezolvarea corectă a celei de-a treia
cerinţe se acordă 40 de puncte.

48
CAPITOLUL 5. OJI 2019 5.1. AUR 49

Exemple
aur.in aur.out Explicaţii
1 12 Se rezolvă cerinţa 1.
7 Tândală a scris pe tăbliţă: 259134592799.
25 9 13 459 2 79 9 Numărul cifrelor scrise de Tândală este 12.
2 7 Se rezolvă cerinţa 2. N are valoarea 7 şi K are
7 10 valoarea 10. Pe tăbliţă este scris: 259134592799
25 9 13 459 2 79 9 Cea de-a zecea cifră este 7.
3 9279 Se rezolvă cerinţa 3. N are valoarea 7 şi P are valoarea 4.
74 Tândală a scris pe tăbliţă: 259134592799.
25 9 13 459 2 79 9 Cel mai mare număr format din patru cifre este 9279.

Timp maxim de executare/test: 0.5 secunde


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

5.1.1 Indicaţii de rezolvare


Descriere a unei soluţii posibile

Cerinţa1 :
- pentru fiecare număr citit din fişier identificăm cifrele sale;
- utilizăm o variabilă de tip contor pentru numărarea cifrelor tuturor numerelor.

Cerinţa 2:
- pentru fiecare număr citit din fişier determinăm cifrele sale ı̂n ordine, de la stânga la dreapta;
- numărăm cifrele până ı̂n momentul ı̂n care variabila care le contorizează ajunge la valoare K.

Cerinţa 3
- considerăm toate secvenţele posibile formate din P cifre alăturate;
- cu cifrele fiecărei secvenţe construim un număr natural;
- calculăm cea mai mare valoare a unui număr natural construit anterior.

Tipuri de date folosite - tipul ı̂ntreg şi/sau tipul caracter

Gradul de dificultate
Cerinţa 1 - 2
Cerinta 2 - 3
Cerinta 3 - 4

5.1.2 Cod sursă

Listing 5.1.1: aur LC.cpp


#include <iostream>
#include <fstream>
#include <cmath>

using namespace std;

ifstream fin("aur.in");
ofstream fout("aur.out");

int main()
{
int p;
fin>>p;

if(p==1)
{
int n,nr=0;
char c;
fin>>n;
while(fin>>c)
if(c!=’ ’) nr++;
CAPITOLUL 5. OJI 2019 5.1. AUR 50

fout<<nr;
}

if(p==2)
{
int n,k,nr=0;
char c,a;
fin>>n>>k;

while(fin>>c)
{
if(c!=’ ’) nr++;
if(nr==k) a=c;
}

fout<<a;
}

if(p==3)
{
unsigned long long n, k, maxx=0, v, y=0, nr=0;
char c;

fin>>n>>k;

unsigned long long f1=1;


for(int i=1;i<k;i++)
f1=f1*10;

while(fin>>c)
{
if(c!=’ ’)
{
v=(int)c-48;
y=y*10+v;
}

nr++;
if(nr==k)
{
if(y>maxx) maxx=y;
y=y%f1;
nr--;
}
}

fout<<maxx;
}

return 0;
}

Listing 5.1.2: aur sol.cpp


#include <fstream>

using namespace std;

ifstream f("aur.in");
ofstream g("aur.out");

long long nr_max,p=1,nou,nr;

int main()
{
char c,cifraK;
int nr_cif=0,cerinta,K,N,i,P;

f>>cerinta>>N;

if (cerinta==2) f>>K;
else
if (cerinta==3) f>>P;

if (cerinta==1)
CAPITOLUL 5. OJI 2019 5.1. AUR 51

{
while(f>>c)
nr_cif++;
g<<nr_cif<<’\n’;
}
else
if (cerinta==2)
while(f>>c)
{
nr_cif++;
if (nr_cif==K)
{
g<<c<<’\n’;
break;
}
}
else
{
for(i=1; i<P; i++)
{
f>>c;
nr=nr*10+(c-’0’);
p=p*10;
}

nr_max=nr;

while(f>>c)
{
nou=(nr%p)*10+(c-’0’);
if(nou>nr_max) nr_max=nou;
nr=nou;
}

g<<nr_max<<’\n’;
}
return 0;
}

Listing 5.1.3: aur td.cpp


#include <fstream>

using namespace std;

ifstream f("aur.in");
ofstream g("aur.out");

long long c, i, N, K, P, cif, nr, y, p, x, aux, cate, q, t, maxf;

int main()
{
f>>c;

if(c==1)
{
f>>N;
cate=0;
for(i=1; i<=N; i++)
{
f>>x;
while(x)
{
cate++;
x /= 10;
}
}
g<<cate<<" \n";
}
else
if(c==2)
{
f>>N>>K;
nr=0;
for (i=1; i<=N; i++)
CAPITOLUL 5. OJI 2019 5.1. AUR 52

{
f>>x;
y=x;
p=1;

while (p<=y)
p *= 10;

p /= 10;
y=x;

while(p>=1)
{
nr++;
cif = y / p %10;
p /= 10;
if(nr == K)
{
g<<cif<<"\n";
return 0;
}
}
}
}
else
{
f>>N>>P;
q=1;

for(i=1; i<P; i++)


q=q*10;

nr=0;
t=0;
maxf=0;

for(i=1; i<=N; i++)


{
f>>x;
y=x;
p=1;

while(p<=y)
p *= 10;

p /= 10;
y=x;
while(p>=1)
{
nr++;
cif = y / p %10;
t = t % q;
t= t*10 + cif;
p /= 10;
if(nr == K)
{
maxf=t;
}
else
if(nr>K)
{
if(t > maxf) maxf=t;
}
}
}
g<<maxf;
}
return 0;
}

5.1.3 Rezolvare detaliată

Etapa nr. 0:
CAPITOLUL 5. OJI 2019 5.1. AUR 53

Listing 5.1.4: Aur - Etapa nr. 0


#include<iostream>
#include<fstream>

using namespace std;

ifstream fin("aur.in");
ofstream fout("aur.out");

int C, N, K, P;
int nr; // cate un numar pe randul 3 (din cele N numere)
int nc; // numarul cifrelor scrise pe tablita
int ck; // cifra K scrisa pe tablita
int nrmaxp; // nr max format cu P cifre

void rezolva1()
{

void rezolva2()
{

void rezolva3()
{

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}
if(C==3) {rezolva3(); return 0;}

return 0;
}

Etapa nr. 1:
Listing 5.1.5: Aur - Etapa nr. 1
#include<iostream>
#include<fstream>

using namespace std;

ifstream fin("aur.in");
ofstream fout("aur.out");

int C, N, K, P;
int nr; // cate un numar pe randul 3 (din cele N numere)
int nc; // numarul cifrelor scrise pe tablita
int ck; // cifra K scrisa pe tablita
int nrmaxp; // nr max format cu P cifre

void rezolva1()
{
fin>>N;
cout<<"N = "<<N<<"\n";

nc=0;

unsigned char ch;


while(fin>>ch)
{
if(ch>=’0’ && ch<=’9’) nc++;
}
cout<<"nc = "<<nc<<"\n";
fout<<nc<<’\n’;
CAPITOLUL 5. OJI 2019 5.1. AUR 54

fout.close();
}

void rezolva2()
{

void rezolva3()
{

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}
if(C==3) {rezolva3(); return 0;}

return 0;
}

Etapa nr. 2:
Listing 5.1.6: Aur - Etapa nr. 2
#include<iostream>
#include<fstream>

using namespace std;

ifstream fin("aur.in");
ofstream fout("aur.out");

int C, N, K, P;
int nr; // cate un numar pe randul 3 (din cele N numere)
int nc; // numarul cifrelor scrise pe tablita
int ck; // cifra K scrisa pe tablita
int nrmaxp; // nr max format cu P cifre

void rezolva1()
{
fin>>N;
cout<<"N = "<<N<<"\n";

nc=0;

unsigned char ch;


while(fin>>ch)
{
if(ch>=’0’ && ch<=’9’) nc++;
}
cout<<"nc = "<<nc<<"\n";
fout<<nc<<’\n’;
fout.close();
}

void rezolva2()
{
fin>>N;
cout<<"N = "<<N<<"\n";

fin>>K;
cout<<"K = "<<K<<"\n";

nc=0;

unsigned char ch;


while(nc < K)
{
fin>>ch;
if(ch>=’0’ && ch<=’9’) nc++;
CAPITOLUL 5. OJI 2019 5.1. AUR 55

}
cout<<"ch = "<<ch<<"\n";
fout<<ch<<’\n’;
fout.close();
}

void rezolva3()
{

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}
if(C==3) {rezolva3(); return 0;}

return 0;
}

Etapa nr. 3:
Listing 5.1.7: Aur - Etapa nr. 3
#include<iostream>
#include<fstream>

using namespace std;

ifstream fin("aur.in");
ofstream fout("aur.out");

int C, N, K, P;
int nr; // cate un numar pe randul 3 (din cele N numere)
int nc; // numarul cifrelor scrise pe tablita
int ck; // cifra K scrisa pe tablita
long long nrmaxp; // nr max format cu P cifre

void rezolva1()
{
fin>>N;
cout<<"N = "<<N<<"\n";

nc=0;

unsigned char ch;


while(fin>>ch)
{
if(ch>=’0’ && ch<=’9’) nc++;
}
cout<<"nc = "<<nc<<"\n";
fout<<nc<<’\n’;
fout.close();
}

void rezolva2()
{
fin>>N;
cout<<"N = "<<N<<"\n";

fin>>K;
cout<<"K = "<<K<<"\n";

nc=0;

unsigned char ch;


while(nc < K)
{
fin>>ch;
if(ch>=’0’ && ch<=’9’) nc++;
}
cout<<"ch = "<<ch<<"\n";
CAPITOLUL 5. OJI 2019 5.1. AUR 56

fout<<ch<<’\n’;
fout.close();
}

void rezolva3()
{
fin>>N;
cout<<"N = "<<N<<"\n";

fin>>P;
cout<<"P = "<<P<<"\n";

// nr1 = c_1 c_2 ... c_p ---> nrnou = c_2 c_3 ...c_p c_{p+1}
// c_2 c_3 ... c_p = restul impartirii lui nr1 la prod10p_1
// = 10*10*...*10 de p-1 ori

long long prod10p_1=1;


for(int i=1; i<=P-1; i++) prod10p_1=prod10p_1*10;
cout<<"prod10p_1 = "<<prod10p_1<<"\n";

long long nr1=0LL;


unsigned char ch;
for(int i=1; i<=P; i++)
{
fin>>ch;
nr1=nr1*10+(ch-’0’);
}
cout<<"nr1 = "<<nr1<<"\n";

nrmaxp=nr1;
while(fin>>ch)
{
if(ch>=’0’ && ch<=’9’)
{
nr1=(nr1 % prod10p_1)*10 + (ch-’0’);
if(nr1 > nrmaxp) nrmaxp=nr1;
}
}
cout<<"nrmaxp = "<<nrmaxp<<"\n";
fout<<nrmaxp<<’\n’;
fout.close();
}

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}
if(C==3) {rezolva3(); return 0;}

return 0;
}

Etapa nr. 4 FINALA1 comentat mesajele ajutatoare:


Listing 5.1.8: Aur - Etapa nr. 4
#include<iostream>
#include<fstream>

using namespace std;

ifstream fin("aur.in");
ofstream fout("aur.out");

int C, N, K, P;
int nr; // cate un numar pe randul 3 (din cele N numere)
int nc; // numarul cifrelor scrise pe tablita
int ck; // cifra K scrisa pe tablita
long long nrmaxp; // nr max format cu P cifre

void rezolva1()
{
CAPITOLUL 5. OJI 2019 5.1. AUR 57

fin>>N;
//cout<<"N = "<<N<<"\n";

nc=0;

unsigned char ch;


while(fin>>ch)
{
if(ch>=’0’ && ch<=’9’) nc++;
}
//cout<<"nc = "<<nc<<"\n";
fout<<nc<<’\n’;
fout.close();
}

void rezolva2()
{
fin>>N;
//cout<<"N = "<<N<<"\n";

fin>>K;
//cout<<"K = "<<K<<"\n";

nc=0;

unsigned char ch;


while(nc < K)
{
fin>>ch;
if(ch>=’0’ && ch<=’9’) nc++;
}
//cout<<"ch = "<<ch<<"\n";
fout<<ch<<’\n’;
fout.close();
}

void rezolva3()
{
fin>>N;
//cout<<"N = "<<N<<"\n";

fin>>P;
//cout<<"P = "<<P<<"\n";

// nr1 = c_1 c_2 ... c_p ---> nrnou = c_2 c_3 ...c_p c_{p+1}
// c_2 c_3 ... c_p = restul impartirii lui nr1 la prod10p_1
// = 10*10*...*10 de p-1 ori

long long prod10p_1=1;


for(int i=1; i<=P-1; i++) prod10p_1=prod10p_1*10;
//cout<<"prod10p_1 = "<<prod10p_1<<"\n";

long long nr1=0LL;


unsigned char ch;
for(int i=1; i<=P; i++)
{
fin>>ch;
nr1=nr1*10+(ch-’0’);
}
//cout<<"nr1 = "<<nr1<<"\n";

nrmaxp=nr1;
while(fin>>ch)
{
if(ch>=’0’ && ch<=’9’)
{
nr1=(nr1 % prod10p_1)*10 + (ch-’0’);
if(nr1 > nrmaxp) nrmaxp=nr1;
}
}
//cout<<"nrmaxp = "<<nrmaxp<<"\n";
fout<<nrmaxp<<’\n’;
fout.close();
}

int main()
CAPITOLUL 5. OJI 2019 5.1. AUR 58

{
fin>>C;
//cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}
if(C==3) {rezolva3(); return 0;}

return 0;
}

Etapa nr. 5 FINALA2 sters mesajele ajutatoare:


Listing 5.1.9: Aur - Etapa nr. 5
#include<iostream>
#include<fstream>

using namespace std;

ifstream fin("aur.in");
ofstream fout("aur.out");

int C, N, K, P;
int nr; // cate un numar pe randul 3 (din cele N numere)
int nc; // numarul cifrelor scrise pe tablita
int ck; // cifra K scrisa pe tablita
long long nrmaxp; // nr max format cu P cifre

void rezolva1()
{
fin>>N;
nc=0;

unsigned char ch;


while(fin>>ch)
{
if(ch>=’0’ && ch<=’9’) nc++;
}
fout<<nc<<’\n’;
fout.close();
}

void rezolva2()
{
fin>>N;
fin>>K;
nc=0;

unsigned char ch;


while(nc < K)
{
fin>>ch;
if(ch>=’0’ && ch<=’9’) nc++;
}
fout<<ch<<’\n’;
fout.close();
}

void rezolva3()
{
fin>>N;
fin>>P;

// nr1 = c_1 c_2 ... c_p ---> nrnou = c_2 c_3 ...c_p c_{p+1}
// c_2 c_3 ... c_p = restul impartirii lui nr1
// la prod10p_1 = 10*10*...*10 de p-1 ori

long long prod10p_1=1;


for(int i=1; i<=P-1; i++) prod10p_1=prod10p_1*10;

long long nr1=0LL;


unsigned char ch;
for(int i=1; i<=P; i++)
{
CAPITOLUL 5. OJI 2019 5.2. CARTELE 59

fin>>ch;
nr1=nr1*10+(ch-’0’);
}

nrmaxp=nr1;
while(fin>>ch)
{
if(ch>=’0’ && ch<=’9’)
{
nr1=(nr1 % prod10p_1)*10 + (ch-’0’);
if(nr1 > nrmaxp) nrmaxp=nr1;
}
}
fout<<nrmaxp<<’\n’;
fout.close();
}

int main()
{
fin>>C;
if(C==1) {rezolva1(); return 0;}
if(C==2) {rezolva2(); return 0;}
if(C==3) {rezolva3(); return 0;}
return 0;
}

5.2 Cartele
Problema 2 - cartele 90 de
puncte
Într-o şcoală există un sistem de acces cu ajutorul cartelelor, conectat la un calculator şi
o imprimantă. Fiecare elev al şcolii are câte o cartelă. Într-o zi, la utilizarea fiecărei cartele,
sistemul imprimă următoarele informaţii pe hârtie, pe câte o linie, după regula următoare:
- Caracterul b dacă elevul este băiat sau caracterul f dacă este fată. Caracterul va fi urmat de
un spaţiu;
- Caracterul i dacă elevul a intrat ı̂n şcoală sau caracterul e dacă a ieşit din şcoală. De
asemenea, acest caracter va fi urmat de un spaţiu;
- Momentul utilizării cartelei, exprimat prin oră, minute şi secunde. Acestea vor fi reprezentate
ı̂n cadrul liniei, exact ı̂n această ordine, prin trei numere naturale, separate ı̂ntre ele prin câte un
spaţiu.

Cerinţe

Cunoscându-se toate cele N linii imprimate ı̂ntr-o zi determinaţi:


1. Câţi băieţi şi câte fete sunt la şcoală după cele N acţiuni imprimate de sistem.
2. Care este numărul total de secunde ı̂n care, ı̂n şcoală, s-au aflat un număr egal, nenul,
de fete şi băieţi, până ı̂n momentul utilizării ultimei cartele. Dacă nu există această situaţie se
afişează 0.
3. Care este numărul maxim de secunde ı̂n care, ı̂n şcoală, până ı̂n momentul utilizării ultimei
cartele, s-au aflat neı̂ntrerupt un număr impar de băieţi. Dacă nu există o astfel de situaţie se
afişează 0.

Date de intrare

Fişierul de intrare cartele.in conţine pe prima linie un număr natural C reprezentând numărul
cerinţei care poate avea valorile 1, 2 sau 3, pe a doua linie numărul natural N, iar pe următoarele
N linii informaţiile imprimate de sistem sub forma descrisă ı̂n enunţ, ı̂n ordinea strict crescătoare
a momentului folosirii cartelei.

Date de ieşire

Dacă C = 1, atunci fişierul de ieşire cartele.out va conţine, ı̂n această ordine, separate printr-un
spaţiu, numărul de băieţi şi numărul de fete determinat conform cerinţei 1.
Dacă C = 2 sau C = 3, atunci fişierul de ieşire cartele.out va conţine pe prima linie un singur
număr natural ce reprezintă rezultatul determinat conform cerinţei.
CAPITOLUL 5. OJI 2019 5.2. CARTELE 60

Restricţii şi precizări

a 1 & N & 10000


a La momentul utilizării primei cartele, ı̂n şcoală nu se află niciun elev
a Sistemul de acces nu permite folosirea simultană a două cartele
a Pentru orice linie imprimată de sistem 0 & ora & 23, 0 & minute & 59 şi 0 & secunde & 59
a Pe fiecare linie a fişierului de intrare, după ultimul număr, reprezentând secundele, nu există
spaţiu.
a Pentru rezolvarea corectă a primei cerinţe se acordă 20 de puncte, pentru rezolvarea corectă
a celei de-a doua cerinţe se acordă 30 de puncte iar pentru rezolvarea corectă a celei de-a treia
cerinţe se acordă 40 de puncte.

Exemple

cartele.in cartele.out Explicaţii


1 01 Se rezolvă cerinţa 1. Un băiat a intrat la momentul 0 0 24
3 (adică ora 0, minutul 0 şi secunda 24) şi ieşit la momentul
b i 0 0 24 0 0 29. O fată a intrat la momentul 0 0 26.
f i 0 0 26 După cele 3 acţiuni, ı̂n şcoală a rămas o fată.
b e 0 0 29 Numărul cifrelor scrise de Tândală este 12.
2 3 Se rezolvă cerinţa 2. Între momentul 0 0 24 şi 0 0 26 ı̂n
3 şcoală este doar un băiat. Între momentul 0 0 26 şi 0 0 29
b i 0 0 24 ı̂n şcoală se află un băiat şi o fată adică un număr nenul
f i 0 0 26 egal de fete şi băieţi.
b e 0 0 29 Deci, numărul de secunde determinat este 3.
2 47 Se rezolvă cerinţa 2.
8 Între momentele 8 19 12 şi 8 19 15 ı̂n şcoală se află 1 băiat şi 1
f i 8 19 10 fată, deci durata este 3 secunde
b i 8 19 12 Între momentele 8 20 0 şi 8 20 4 ı̂n şcoală se află 1 băiat şi 1
b e 8 19 15 fată, deci durata este 4 secunde
b i 8 20 0 Între momentele 8 20 10 şi 8 20 50 ı̂n şcoală se află 1 băiat şi 1
b e 8 20 4 fată, deci durata este 40 de secunde
b i 8 20 10
b i 8 20 50 Durata totală este 3+4+40=47 de secunde
b i 8 20 51
3 3 Se rezolvă cerinţa 2.
9 Între momentele 8 19 12 şi 8 19 15 ı̂n şcoală se află 1 băiat, deci
f i 8 19 10 durata este 3 secunde
b i 8 19 12 Între momentele 8 20 0 şi 8 20 1 ı̂n şcoală se află 1 băiat, deci
f e 8 19 13 durata este 1 secundă
b e 8 19 15 Între momentele 8 20 10 şi 8 20 12 ı̂n şcoală se află 3 băieţi,
b i 8 20 0 deci durata este 2 secunde
b e 8 20 1
b i 8 20 10 Durata maximă cerută este de 3 secunde
b i 8 20 12
b i 8 20 13

Timp maxim de executare/test: 0.5 secunde


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

5.2.1 Indicaţii de rezolvare

Descrierea soluţiei
Se vor citi datele ı̂n formatul specificat şi se vor transforma ı̂n secunde momentele fiecărei
acţiuni.
Cerinţa 1:
CAPITOLUL 5. OJI 2019 5.2. CARTELE 61

- se actualizează numărul de băieţi şi fete ı̂n funcţie de acţiune (intrare sau ieşire) şi se afişează
valorile finale, obţinute după a N -a linie citită.
Cerinţa 2 :
- ı̂n timpul parcurgerii se reactualizează numărul de băieţi şi fete ı̂n funcţie de acţiune (intrare
sau ieşire), vom determina durata de timp curentă care are proprietatea cerută (număr egal de
fete şi băieţi prezenţi ı̂n şcoală, număr nenul) şi adunăm perioadele determinate.
Cerinţa 3:
- ı̂n timpul parcurgerii se actualizează numărul de băieţi şi fete prezenţi ı̂n şcoală, ı̂n funcţie
de acţiune (intrare sau ieşire). Vom determina durata neı̂ntreruptă de timp curentă care are
proprietatea cerută şi vom afişa maximul acestora.
Se folosesc tipurile de date caracter şi ı̂ntregi (char/int respectiv char/integer) apoi se simulează
acţiunile descrise ı̂n secvenţe strict crescătoare de timpi.
Gradul de dificultate
Cerinţa 1 - 2
Cerinţa 2 - 3
Cerinţa 3 - 4

5.2.2 Cod sursă

Listing 5.2.1: cartele LC.cpp


#include<iostream>
#include<fstream>
#include<cstdlib>

using namespace std;

int main()
{
ifstream f("cartele.in");
ofstream g("cartele.out");

short int C;
f>>C;

if(C==1)
{
int nr_Fete=0,nr_Baieti=0;
char c,c1;
int nr,h,m,s;

f>>nr;

for(int i=1; i<=nr; i++)


{
f>>c>>c1>>h>>m>>s;

if(c==’f’)
{
if(c1==’e’)
nr_Fete--;
else
nr_Fete++;
}
else
{
if(c1==’e’)
nr_Baieti--;
else
nr_Baieti++;
}

}
g<<nr_Baieti<<" "<<nr_Fete;
}

if(C==2)
{
int nr_Fete=0,nr_Baieti=0;
CAPITOLUL 5. OJI 2019 5.2. CARTELE 62

char c,c1;
int nr,s1,s2,h,m,s,timp_total=0;

f>>nr;

for(int i=1; i<=nr; i++)


{
f>>c>>c1>>h>>m>>s;

bool era_egal=false;

if(nr_Fete!=0 && nr_Fete==nr_Baieti)


era_egal=true;

if(c==’f’)
{
if(c1==’e’)
nr_Fete--;
else
nr_Fete++;
}
else
{

if(c1==’e’)
nr_Baieti--;
else
nr_Baieti++;
}

if(i==1)
{
s1=0;
s1+=h*3600;
s1+=m*60;
s1+=s;
}
else
{
s2=0;
s2+=h*3600;
s2+=m*60;
s2+=s;
if(era_egal)
timp_total+=s2-s1;
s1=s2;
}
}

g<<timp_total;
}

if(C==3)
{
int nr_Baieti=0,nr,s1=0,s2,timp_maxim=0;
char c,c1;
int h,m,s;

f>>nr;

for(int i=1; i<=nr; i++)


{
f>>c>>c1>>h>>m>>s;
bool era_impar=false;

if(nr_Baieti%2==1)
era_impar=true;

if(c==’b’)
{
if(c1==’e’)
nr_Baieti--;
else
nr_Baieti++;
}
if(nr_Baieti%2==1&&s1==0)
CAPITOLUL 5. OJI 2019 5.2. CARTELE 63

{
s1+=h*3600;
s1+=m*60;
s1+=s;
}
else
{
s2=0;
s2+=h*3600;
s2+=m*60;
s2+=s;

if(era_impar&&nr_Baieti%2==0)
{
if(s2-s1>timp_maxim)
timp_maxim=s2-s1;
s1=0;
}
}
}

g<<timp_maxim;
}
}

Listing 5.2.2: cartele td.cpp


#include <fstream>

using namespace std;

ifstream f("cartele.in");
ofstream g("cartele.out");

int maxim,sec1,sec,p,h,m,s,h1,m1,s1,i,N,max1,cb,cf,suma;
char c,a;

int main()
{
f>>p;
f>>N;

if (p==1)
{
cb=0;
cf=0;
for (i = 1; i <= N; i++)
{
f>>c>>a>>h>>m>>s;
if (c==’b’)
if (a==’i’) cb++;
else cb--;
else
if (a==’i’) cf++;
else cf--;
}

g<<cb<<" "<<cf<<"\n";
}
else
if (p==2)
{
f>>c>>a>>h1>>m1>>s1;

sec1=h1*3600+m1*60+s1;

if (c==’b’) cb=1,cf=0;
else cb=0,cf=1;

suma=0;
for (i = 2; i <= N; i++)
{
f>>c>>a>>h>>m>>s;

sec=h*3600+m*60+s;
CAPITOLUL 5. OJI 2019 5.2. CARTELE 64

if (cb==cf && cb>0) suma += (sec-sec1);

if (c==’b’)
if (a==’i’) cb++;
else cb--;
else
if (a==’i’) cf++;
else cf--;

sec1=sec;
}

g<<suma<<"\n";
}
else
{
f>>c>>a>>h1>>m1>>s1;

if (c==’b’) {cb=1; cf=0; sec1=h1*3600+m1*60+s1;}


else cb=0,cf=1;

maxim=0;
for (i = 2; i <= N; i++)
{
f>>c>>a>>h>>m>>s;
sec=h*3600+m*60+s;
if (c==’b’)
{
if (cb%2!=0 && sec-sec1 > maxim) maxim=sec-sec1;
if (a==’i’) cb++; else cb--;
sec1=sec;
}
else
if (a==’i’) cf++; else cf--;
}

g<<maxim<<"\n";
}
return 0;
}

5.2.3 Rezolvare detaliată

Etapa nr. 0:

Listing 5.2.3: Cartele - Etapa nr. 0


#include<iostream>
#include<fstream>

using namespace std;

ifstream fin("cartele.in");
ofstream fout("cartele.out");

int C, N;
char elev; // ’b’ sau ’f’
char inout; // ’i’ sau ’e’
int ora, minut, sec;

int nrb, nrf; // nr_baieti, nr_fete


int nrtotsec; // nr total secunde
int nrmaxsec; // nr maxim secunde

void rezolva1()
{

void rezolva2()
{
CAPITOLUL 5. OJI 2019 5.2. CARTELE 65

void rezolva3()
{

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}
if(C==3) {rezolva3(); return 0;}

return 0;
}

Etapa nr. 1:
Listing 5.2.4: Cartele - Etapa nr. 1
#include<iostream>
#include<fstream>

using namespace std;

ifstream fin("cartele.in");
ofstream fout("cartele.out");

int C, N;
unsigned char elev; // ’b’ sau ’f’
unsigned char inout; // ’i’ sau ’e’
int ora, minut, sec;

int nrb, nrf; // nr_baieti, nr_fete


int nrtotsec; // nr total secunde
int nrmaxsec; // nr maxim secunde

void citesteCartela()
{
fin>>elev;
fin>>inout;
fin>>ora;
fin>>minut;
fin>>sec;
cout<<elev<<" "<<inout<<" "<<ora<<" "<<minut<<" "<<sec<<"\n";
}

void rezolva1()
{
fin>>N;
cout<<"N = "<<N<<"\n";

nrb=0;
nrf=0;

for(int i=1; i<=N; i++)


{
citesteCartela();

if(elev==’b’)
{
if(inout==’i’) nrb=nrb+1; else nrb=nrb-1;
}
else
if(elev==’f’)
{
if(inout==’i’) nrf=nrf+1; else nrf=nrf-1;
}
}

cout<<"nrb = "<<nrb<<" nrf = "<<nrf<<"\n";


CAPITOLUL 5. OJI 2019 5.2. CARTELE 66

fout<<nrb<<" "<<nrf<<’\n’;
fout.close();
}

void rezolva2()
{

void rezolva3()
{

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}
if(C==3) {rezolva3(); return 0;}

return 0;
}

Etapa nr. 2:
Listing 5.2.5: Cartele - Etapa nr. 2
#include<iostream>
#include<fstream>

using namespace std;

ifstream fin("cartele.in");
ofstream fout("cartele.out");

int C, N;
unsigned char elev; // ’b’ sau ’f’
unsigned char inout; // ’i’ sau ’e’
int ora, minut, sec;

int nrb, nrf; // nr_baieti, nr_fete


int nrtotsec; // nr total secunde
int nrmaxsec; // nr maxim secunde

void citesteCartela()
{
fin>>elev;
fin>>inout;
fin>>ora;
fin>>minut;
fin>>sec;
cout<<elev<<" "<<inout<<" "<<ora<<" "<<minut<<" "<<sec<<"\n";
}

void rezolva1()
{
fin>>N;
cout<<"N = "<<N<<"\n";

nrb=0;
nrf=0;

for(int i=1; i<=N; i++)


{
citesteCartela();

if(elev==’b’)
{
if(inout==’i’) nrb=nrb+1; else nrb=nrb-1;
}
else
if(elev==’f’)
CAPITOLUL 5. OJI 2019 5.2. CARTELE 67

{
if(inout==’i’) nrf=nrf+1; else nrf=nrf-1;
}
}

cout<<"nrb = "<<nrb<<" nrf = "<<nrf<<"\n";


fout<<nrb<<" "<<nrf<<’\n’;
fout.close();
}

void rezolva2()
{
nrtotsec=0;

fin>>N;
cout<<"N = "<<N<<"\n";

nrb=0;
nrf=0;

bool adunTimp=false;
int timp1, timp2;

timp1=0; // moment vechi


for(int i=1; i<=N; i++)
{
citesteCartela();

if(elev==’b’)
{
if(inout==’i’) nrb=nrb+1; else nrb=nrb-1;
}
else
if(elev==’f’)
{
if(inout==’i’) nrf=nrf+1; else nrf=nrf-1;
}

timp2=ora*60*60+minut*60+sec; // moment actual

if(adunTimp) nrtotsec=nrtotsec+(timp2-timp1);

timp1=timp2;
if(nrb==nrf && nrb>0) adunTimp=true; else adunTimp=false;
}

cout<<"nrtotsec = "<<nrtotsec<<"\n";
fout<<nrtotsec<<’\n’;
fout.close();
}

void rezolva3()
{

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}
if(C==3) {rezolva3(); return 0;}

return 0;
}

Etapa nr. 3:
Listing 5.2.6: Cartele - Etapa nr. 3
#include<iostream>
#include<fstream>
CAPITOLUL 5. OJI 2019 5.2. CARTELE 68

using namespace std;

ifstream fin("cartele.in");
ofstream fout("cartele.out");

int C, N;
unsigned char elev; // ’b’ sau ’f’
unsigned char inout; // ’i’ sau ’e’
int ora, minut, sec;

int nrb, nrf; // nr_baieti, nr_fete


int nrtotsec; // nr total secunde
int nrmaxsec; // nr maxim secunde

void citesteCartela()
{
fin>>elev;
fin>>inout;
fin>>ora;
fin>>minut;
fin>>sec;
cout<<elev<<" "<<inout<<" "<<ora<<" "<<minut<<" "<<sec<<"\n";
}

void rezolva1()
{
fin>>N;
cout<<"N = "<<N<<"\n";

nrb=0;
nrf=0;

for(int i=1; i<=N; i++)


{
citesteCartela();

if(elev==’b’)
{
if(inout==’i’) nrb=nrb+1; else nrb=nrb-1;
}
else
if(elev==’f’)
{
if(inout==’i’) nrf=nrf+1; else nrf=nrf-1;
}
}

cout<<"nrb = "<<nrb<<" nrf = "<<nrf<<"\n";


fout<<nrb<<" "<<nrf<<’\n’;
fout.close();
}

void rezolva2()
{
nrtotsec=0;

fin>>N;
cout<<"N = "<<N<<"\n";

nrb=0;
nrf=0;

bool adunTimp=false;
int timp1, timp2;

timp1=0; // moment vechi


for(int i=1; i<=N; i++)
{
citesteCartela();

if(elev==’b’)
{
if(inout==’i’) nrb=nrb+1; else nrb=nrb-1;
}
else
if(elev==’f’)
CAPITOLUL 5. OJI 2019 5.2. CARTELE 69

{
if(inout==’i’) nrf=nrf+1; else nrf=nrf-1;
}

timp2=ora*60*60+minut*60+sec; // moment actual

if(adunTimp) nrtotsec=nrtotsec+(timp2-timp1);

timp1=timp2;
if(nrb==nrf && nrb>0) adunTimp=true; else adunTimp=false;
}

cout<<"nrtotsec = "<<nrtotsec<<"\n";
fout<<nrtotsec<<’\n’;
fout.close();
}

void rezolva3()
{
nrmaxsec=0;

fin>>N;
cout<<"N = "<<N<<"\n";

nrb=0;

int timp1, timp2;

timp1=0; // moment inainte de citire cartela


for(int i=1; i<=N; i++)
{
citesteCartela();

if(elev==’b’) // s-a schimbat paritatea numarului de baieti


{
timp2=ora*60*60+minut*60+sec; //moment actual(dupa citire cartela)

if(inout==’i’) nrb=nrb+1; else nrb=nrb-1;

if(nrb%2==1) // a fost nr par de baieti si a venit acum un baiat ...


{ // ... incepe timp !!!
// impar este oricum diferit de zero ... deci ...
// ... nu verific nrb==0
timp1=timp2;
cout<<" nrb = "<<nrb<<" timp1 = "<<timp1<<"\n";
}
else // a fost nr impar de baieti si ... a venit acum un baiat
{
if(nrmaxsec < (timp2-timp1)) nrmaxsec = timp2-timp1;
cout<<" nrb = "<<nrb<<" timp2 = "<<timp2<<"\n";
}
}
}

cout<<"nrmaxsec = "<<nrmaxsec<<"\n";
fout<<nrmaxsec<<’\n’;
fout.close();
}

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}
if(C==3) {rezolva3(); return 0;}

return 0;
}

Etapa nr. 4 FINALA1 comentat mesajele ajutatoare:


Tema !!!
CAPITOLUL 5. OJI 2019 5.2. CARTELE 70

Etapa nr. 5 FINALA2 sters mesajele ajutatoare:


Tema !!!
Capitolul 6

OJI 2018

6.1 Patrate
Problema 1 - Patrate 90 de puncte
Un elev a desenat un set format din mai multe pătrate care conţin numere naturale nenule,
distincte, consecutive, dispuse ı̂n număr egal pe laturi. Pe latura fiecărui pătrat sunt scrise un
număr impar de valori. În fiecare pătrat, numerele sunt scrise ı̂n ordine crescătoare parcurgând
laturile sale, ı̂ncepând din colţul stânga-jos, ı̂n sensul invers al acelor de ceasornic. Elevul a
numerotat pătratele cu 1, 2, 3 etc., ı̂n ordinea strict crescătoare a numărului de valori conţinute
de fiecare. Diferenţa dintre cel mai mic număr din pătratul P 1 $ P  şi cel mai mare număr din
pătratul P  1 este egală cu 1. Primele patru pătrate sunt:

Figura 6.1: Patrate

Astfel, primul pătrat conţine numerele naturale distincte consecutive de la 1 la 8, dispuse


câte trei pe fiecare latură a pătratului. Al doilea pătrat conţine următoarele 16 numere naturale
distincte consecutive, dispuse câte cinci pe fiecare latură. Al treilea pătrat conţine următoarele 24
de numere naturale distincte consecutive, dispuse câte şapte pe fiecare latură. Al patrulea pătrat
conţine următoarele 32 de numere naturale distincte consecutive, dispuse câte nouă pe fiecare
latură etc.

Cerinţe

Scrieţi un program care rezolvă următoarele două cerinţe:


1. citeşte un număr natural M şi determină numărul K de valori conţinute de pătratul nu-
merotat cu M ;
2. citeşte un număr natural N şi determină numărul T al pătratului care conţine numărul N
pe una dintre laturi.

Date de intrare

Fişierul de intrare patrate.in conţine pe prima linie un număr natural C reprezentând cerinţa
din problemă care trebuie rezolvată (1 sau 2). Dacă C 1, atunci fişierul conţine pe a doua linie
numărul natural M . Dacă C 2, atunci fişierul conţine pe a doua linie numărul natural N .

Date de ieşire

71
CAPITOLUL 6. OJI 2018 6.1. PATRATE 72

Dacă C 1, atunci fişierul de ieşire patrate.out conţine pe prima linie numărul K,


reprezentând răspunsul la cerinţa 1 a problemei. Dacă C 2, atunci fişierul de ieşire patrate.out
conţine pe prima linie numărul natural T , reprezentând răspunsul la cerinţa 2.

Restricţii şi precizări

a 1 & M & 260000000


a 7 & N & 2147302920
a Numerele N, M, T şi K sunt numere naturale
a NU există două pătrate cu acelaşi număr de valori scrise pe laturi
a Pentru rezolvarea corectă a cerinţei 1 se acordă 10 puncte; pentru rezolvarea corectă a cerinţei
2 se acordă 80 de puncte. Se acordă 10 puncte din oficiu.

Exemple
patrate.in patrate.out Explicaţii
1 24 Cerinţa este 1. Pătratul numerotat cu M 3 conţine
3 K 24 de numere naturale (vezi figura din enunţ).
2 4 Cerinţa este 2. Numărul N 73 este conţinut de pătratul
73 K 24 numerotat cu T 4 (vezi figura din enunţ).

Timp maxim de executare/test: 0.3 secunde


Memorie: 8M B
Dimensiune maximă a sursei: 5KB

6.1.1 Indicaţii de rezolvare

Descrierea soluţiei

Autor prof. Carmen Mincă


Colegiul Naţional de Informatică ”Tudor Vianu” - Bucureşti

Pătratele conţin numere naturale distincte consecutive.


Primul pătrat are pe latură L 3 2 ˜ 1  1 numere şi conţine ı̂n total K 4 ˜ L  4 8 ˜ 1
numere
Al doilea pătrat are pe latură L 5 2 ˜ 2  1 numere şi conţine ı̂n total K 4 ˜ L  4 2 ˜ 8
numere
Al treilea pătrat are pe latură L 7 2 ˜ 3  1 numere şi conţine ı̂n total K 4 ˜ L  4 3 ˜ 8
numere
...........
Al T -lea pătrat are pe latură L 2 ˜ T  1 numere şi conţine ı̂n total 4 ˜ L  4 T ˜ 8 numere
Cerinţa 1. Pe laturile pătratului M sunt scrise 8 ˜ M numere naturale distincte.
Cerinţa 2. Numărul de numere folosite ı̂n primele T  1 pătrate este:
8 ˜ 1  8 ˜ 2  8 ˜ 3  ...  8 ˜ T  1 8 ˜ 1  2  3  ...  T  1 4 ˜ T ˜ T  1
Numerele din pătratul T sunt: 4 ˜ T T  1  1, 4 ˜ T T  1  2, 4 ˜ T T  1  3, ...,
4 ˜ T ˜ T  1  8 ˜ T 4 ˜ T ˜ T  1
Numărul N este ı̂n pătratul T dacă este adevărată relaţia: 4 ˜ T T  1  1 & N & 4 ˜ T ˜ T  1

6.1.2 Cod sursă

Listing 6.1.1: patrate AS.cpp


//#include <iostream>
#include <fstream>
#include<cmath>

using namespace std;

int N,C,K,M,T;

int main()
{
CAPITOLUL 6. OJI 2018 6.1. PATRATE 73

ifstream in("patrate.in");
ofstream out("patrate.out");

in>>C;

if(C==1)
{
in>>M;
out<<8*M<<endl;
}
else
{
in>>N;
T=sqrt(N);
if(T%2)T++;
out<<T/2<<endl;
}
return 0;
}

Listing 6.1.2: patrate cpp CM.cpp


#include <fstream>
using namespace std;

ifstream f("patrate.in");
ofstream g("patrate.out");

int main()
{
int N,C,M,T,K,nr=0;
f>>C;

if(C==1)
{
f>>M;
K=8*M;
g<<K<<endl;
}
else
{
f>>N;
T=0;
nr=0;
while(8*(T+1)<=N-nr)
{
++T;
K=8*T;
nr=nr+K;
}
if(N>nr){ ++T; }

g<<T<<endl;
}

return 0;
}

Listing 6.1.3: patrate FB.cpp


//#include <iostream>
#include <fstream>

using namespace std;

ifstream f("patrate.in");
ofstream g("patrate.out");

long long c,N,x,k,T,M;

int main()
{
f>>c;
if(c==1)
CAPITOLUL 6. OJI 2018 6.2. FORUS 74

{
f>>M;
g<<8*M;
}
else
{
f>>N;
k=8;
T=1;
while(N-k>0)
{
N=N-k;
k=k+8;
T++;
}

g<<T;
}
return 0;
}

Listing 6.1.4: patrate VG.cpp


#include <fstream>

using namespace std;

int main()
{ int m, cer, n;
long long t,x;

ifstream f("patrate.in");
ofstream g("patrate.out");

f>>cer>>n;

if(cer==1)
g<<8*n<<endl;
else
{
if(n<8) g<<1<<endl;
else
{
m=1; t=0; x=0;
while(t<n)
{
t=8*(m+x);
x+=m;
m++;
}
g<<m-1<<endl;
}
}
return 0;
}

6.1.3 *Rezolvare detaliată

6.2 forus
Problema 2 - forus 90 de puncte
La ora de educaţie tehnologică a clasei a V-a profesorul Forus, pasionat de matematică, a adus
pentru fiecare dintre cei N elevi câte un carton pe care este scris câte un număr natural nenul.
Fiecare elev poate folosi cartonul aşa cum l-a primit sau poate să taie o singură dată cartonul
ı̂ntre două cifre şi să lipească partea stângă la finalul părţii drepte. Elevul NU are voie să facă
o tăietură ı̂n faţa cifrei 0, deci niciunul dintre numerele obţinute NU poate să ı̂nceap cu cifra
0. Dintre toate numerele pe care le poate obţine, elevul ı̂l alege pe cel care are număr minim de
CAPITOLUL 6. OJI 2018 6.2. FORUS 75

divizori, iar dacă poate obţine mai multe astfel de numere, l alege pe cel mai mic dintre ele. La
sfârşitul orei, profesorul strânge cartoanele cu numerele alese, ı̂n ordinea distribuirii lor.
De exemplu, dacă iniţial elevul primeşte cartonul cu numărul 25082 atunci el are doar
următoarele trei variante de tăiere şi lipire:

Figura 6.2: forus

Cerinţe

Scrieţi un program care citeşte numărul natural N şi cele N numere scrise pe cartoanele aduse
de profesorul Forus, apoi rezolvă următoarele două cerinţe:
1. determină numărul de cartoane pe care elevii au voie să le taie de oriunde (NU conţin cifre
ı̂n faţa cărora NU au voie să taie);
2. determină, ı̂n ordinea strângerii cartoanelor, numerele preluate de către profesorul Forus la
finalul orei.

Date de intrare

Fişierul de intrare forus.in conţine pe prima linie un număr natural C reprezentând cerinţa
din problemă care trebuie rezolvată (1 sau 2). A doua linie din fişier conţine un număr natural N ,
reprezentând numărul de elevi, iar a treia linie din fişier conţine N numere naturale, separate prin
câte un spaţiu, reprezentând numerele scrise pe cartoanele aduse de profesor, ı̂n ordinea distribuirii
lor.

Date de ieşire

Dacă C 1, fişierul de ieşire forus.out conţine pe prima linie un număr natural reprezentând
răspunsul la cerinţa 1.
Dacă C 2, fişierul de ieşire forus.out conţine pe prima linie N numere naturale, separate
prin câte un spaţiu, reprezentând răspunsul la cerinţa 2; numerele sunt scrise ı̂n ordinea ı̂n care
au fost strânse.

Restricţii şi precizări

a 2 & N & 30
a 1 & numărul natural de pe carton $ 1000000000
a Pentru rezolvarea corectă a cerinţei 1 se acordă 20 de puncte; pentru rezolvarea corectă a
cerinţei 2 se acordă 70 de puncte. Se acordă 10 puncte din oficiu.

Exemple

forus.in forus.out Explicaţii


1 3 Cerinţa este 1. Sunt 3 numere care pot fi
3 tăiate de oriunde: 1234, 543, 52.
1234 25082 543 52 150
CAPITOLUL 6. OJI 2018 6.2. FORUS 76

2 15 2341 25082 453 501 Cerinţa este 2. Pentru cartonul cu numărul


5 51 se pot obţine numerele 15 şi 51. Ambele
51 1234 50822 345 150 numere au câte 4 divizori. Astfel, se va alege
numărul 15, fiind cel mai mic.
Pentru cartonul cu numărul 1234 (4 divizori)
pot fi obţinute numerele: 2341 (2 divizori),
3412 (6 divizori) şi 4123 (8 divizori). Se va
alege numărul 2341 pentru că are numărul
minim de divizori. Analog se va proceda
pentru toate celelalte numere din şir.

Timp maxim de executare/test: 0.5 secunde


Memorie: 8M B
Dimensiune maximă a sursei: 10KB

6.2.1 Indicaţii de rezolvare

Descrierea soluţiei

Autor prof. FLAVIUS BOIAN


Colegiul Naţional ”SPIRU HARET” TG-JIU

Cerinţa 1. Pentru fiecare număr citit, se verifică dacă conţine cel puţin o cifră de 0 ı̂n scrierea
sa. Se vor contoriza numerele citite care nu conţin cifra 0.
Cerinţa 2. Pentru fiecare număr citit se construiesc prin permutări circulare la dreapta cu
o poziţie toate numerele posibile. Dintre acestea se va alege numărul cu un număr minim de
divizori, cu observaţia că numărul ales trebuie să aibă acelaşi număr de cifre ca şi numărul iniţial
(nu am voie să tai ı̂naintea cifrei 0). Vom genera toate aceste numerele care se pot forma şi vom
calcula numărul de divizori, reţinând de fiecare dată pe cel cu număr minim de divizori, iar ı̂n caz
de egalitate a numărului de divizori ı̂l vom reţine pe cel mai mic.

6.2.2 Cod sursă

Listing 6.2.1: forus CM 100.cpp


///#include <iostream>
#include <fstream>
using namespace std;

ifstream f("forus.in");
ofstream g("forus.out");

int nrdiv(int N)
{
int d, nrd=1;
for(d=1;d*d<N;d++)
if(N%d==0)nrd+=2;
if(d*d==N) ++nrd;
return nrd;
}

int main()
{
int C,N,nr;
f>>C>>N;
if(C==1)
{
int r=0,ok;
for(int i=1; i<=N; i++)
{
f>>nr;
//cout<<nr<<" ";
ok=1;
while(nr && ok)
CAPITOLUL 6. OJI 2018 6.2. FORUS 77

{
if (nr%10==0)ok=0;
nr=nr/10;
}
r=r+ok;
}
g<<r<<endl;
}
else
{
int y,p,nrc,x,pr,ult,pu,xmin,nrdm,nrd,z;
for(int i=1; i<=N; i++)
{
f>>nr;
p=1;nrc=1;pu=10;
xmin=nr; nrdm=nrdiv(nr);
x=nr;
while(x>0)
{
x=x/10;
p=p*10;
nrc++;
}
p=p/10;z=p;
for(int i=1; i<nrc; i++)
{
pr=nr/p;
ult=nr%p;
x=ult*pu+pr;
if(x/z>0)
{
nrd=nrdiv(x);
if(nrd<nrdm)
{
xmin=x;
nrdm=nrd;
}
else
if(nrd==nrdm) xmin=min(xmin,x);
}
pu=pu*10;
p=p/10;
}
g<<xmin<<" ";
}
g<<endl;
}

return 0;
}

Listing 6.2.2: forus nvl 100.cpp


/// Nicu Vlad-Laurentiu

#include <bits/stdc++.h>

using namespace std;

ifstream fin("forus.in");
ofstream fout("forus.out");

int nr_div(int x)
{
int p,d=2,N=1;
while(x>1)
{
p=0;
while(x%d==0)
{
p++;
x/=d;
}
if(p)N*=(p+1);
if(d*d<x) d++;
CAPITOLUL 6. OJI 2018 6.2. FORUS 78

else d=x;
}
return N;
}

int pow10(int nc)


{
int P=1;
for(int i=1; i<=nc; ++i)
P*=10;
return P;
}

int main()
{
int n,x,cer;
fin>>cer>>n;
if(cer==1)
{
int nr=0,nc,n0;
for(; n; n--)
{
fin>>x;
nc=0,n0=0;
if(x==0) nr++;
while(x)
{
if(x%10==0) n0++;
nc++;
x/=10;
}
if(n0==0) nr++;
}
fout<<nr;
}
else
{
int nc;
long long put,nrmax=0,val,nrc;
for(; n; n--)
{
fin>>x;

nc=log10(x);
put=pow10(nc);
nrmax=nr_div(x);
val=x;

for(int i=1; i<=nc; ++i)


{
x=x%put*10+x/put;
if(x/put!=0)
{
nrc=nr_div(x);
if(nrc<nrmax)
{
nrmax=nrc;
val=x;
}
else if(nrc==nrmax &&val>x) val=x;
}
}
fout<<val<<" ";
}
}
return 0;
}

Listing 6.2.3: forus VG 100.cpp


#include <fstream>

using namespace std;

int main()
CAPITOLUL 6. OJI 2018 6.2. FORUS 79

{
ifstream f("forus.in");
ofstream g("forus.out");

long long x,mx;


int c, n, a,b, r,i,ok,nd,d,y,nc,p,j,nz;

f>>c;
if(c==1)
{
f>>n;
r=0;
for(i=1;i<=n;i++)
{
f>>x;
ok=1;
while(x>0 && ok)
if(x%10==0) ok=0;
else x/=10;
if(ok) r++;
}

g<<r;
}
else
{
f>>n;
for(i=1;i<=n;i++)
{
f>>x;
if(x<10)
g<<x<<’ ’;
else
{
y=x;
mx=1000000000;
nc=0;
p=1;
while(x)
{
nc++;
x/=10;
p=p*10;
}

p=p/10;
x=y;

do
{
nd=0;
for(d=1;d*d<x;d++)
if(x%d==0) nd+=2;
if(d*d==x) nd++;

// g<<x<<’ ’<<nd<<’ ’<<’\n’;


if(nd<mx)
{
r=x;
mx=nd;
}
else
if(nd==mx) if(x<r) r=x;

if(x/(p/10)%10==0)
{
nz=0;
y=p/10;
while(x/y%10==0 && y>1)
{
y=y/10;
nz++;
}
a=x/p;
x=x*10+a;
x=x%p;
CAPITOLUL 6. OJI 2018 6.2. FORUS 80

for(j=1;j<=nz;j++)
x=x*10;
nc=nc-nz;
}
else
{
a=x/p;
b=x%p;
x=b*10+a;
}

nc--;

} while(nc>0);

g<<r<<’ ’;
}
}
}
return 0;
}

Listing 6.2.4: oficial FB 100.cpp


#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;

ifstream f("forus.in");
ofstream g("forus.out");

int N,P,i,u,x,ok,k,t,cifre,minim,numar,pf,ps,p,ajt;
int main()
{
f>>P>>N;
if(P==1)
{
for(i=1; i<=N; i++)
{
f>>x;
ok=1;
while(x)
{
u=x%10;
if(u==0)
{
ok=0;
break;
}
x=x/10;
}
if(ok==1) k++;
}
g<<k;
}
if(P==2)
{
for(i=1; i<=N; i++)
{
f>>x;
t=x;
cifre=0;
while(t)
{
t=t/10;
cifre++;
}
t=x;

int prod=1,d,putere=0;
while(t%2==0)
{
t=t/2;
putere++;
CAPITOLUL 6. OJI 2018 6.2. FORUS 81

}
if(putere>0) prod=prod*(putere+1);
d=3;
while(t>1)
{
putere=0;
while(t%d==0)
{
t=t/d;
putere++;
}
if(putere>0)
prod=prod*(putere+1);
d=d+2;
if(d*d>t)
d=t;
}
minim=prod;

t=x;
numar=x;
k=cifre-1;
p=1;
while(k)
{
p*=10;
k--;
}
k=cifre-1;
while(k)
{
if(t%10!=0)
{
pf=t%10;
ps=t/10;
t=pf*p+ps;
prod=1,putere=0;
ajt=t;
while(t%2==0)
{
t=t/2;
putere++;
}
if(putere>0) prod=prod*(putere+1);
d=3;
while(t>1)
{
putere=0;
while(t%d==0)
{
t=t/d;
putere++;
}
if(putere>0) prod=prod*(putere+1);
d=d+2;
if(d*d>t) d=t;
}
if(prod<minim)
{
minim=prod;
numar=ajt;
}
if(prod==minim and ajt<numar)
{
numar=ajt;
}
t=ajt;
}
else
{
pf=t%10;
ps=t/10;
t=pf*p+ps;
}
k--;
}
CAPITOLUL 6. OJI 2018 6.2. FORUS 82

g<<numar<<" ";
}
}
return 0;
}

6.2.3 *Rezolvare detaliată


Capitolul 7

OJI 2017

7.1 numere
Problema 1 - numere 90 de puncte
Un copil construieşte un triunghi cu numerele naturale nenule astfel:
- ı̂n vârful triunghiului scrie valoarea 1;
- completează liniile triunghiului de sus ı̂n jos, iar căsuţele de pe aceeaşi linie de la stânga la
dreapta cu numere naturale consecutive, ca ı̂n figurile următoare.

Figura 7.1: Numere

În figura 1 este ilustrat un astfel de triunghi având 5 linii, conţinând numerele naturale de la
1 la 15. În acest triunghi copilul ı̂ncepe să construiască drumuri, respectând următoarele reguli:
- orice drum ı̂ncepe din 1;
- din orice căsuţă se poate deplasa fie ı̂n căsuţa situată pe linia următoare ı̂n stânga sa (deplasare
codificată cu 1), fie ı̂n căsuţa situată pe linia următoare ı̂n dreapta sa (deplasare codificată cu 2);
- orice drum va fi descris prin succesiunea deplasărilor efectuate.
De exemplu, drumul ilustrat ı̂n figura 2 poate fi descris astfel: 1222.

Cerinţe

Scrieţi un program care rezolvă următoarele două cerinţe:


1. citeşte descrierea unui drum şi afişează numărul la care se termină drumul;
2. citeşte un număr natural nenul K, determină un drum care se termină cu numărul K pentru
care suma numerelor prin care trece drumul este maximă şi afişează această sumă.

Date de intrare

Fişierul de intrare numere.in conţine pe prima linie un număr natural C reprezentând cerinţa
din problemă care trebuie rezolvată (1 sau 2).
Dacă C este egal cu 1, a doua linie din fişier conţine un număr natural N , reprezentând
lungimea drumului, iar a treia linie din fişier conţine descrierea drumului sub forma a N valori, 1
sau 2, separate ı̂ntre ele prin câte un spaţiu.
Dacă C este egal cu 2, a doua linie din fişier conţine numărul natural K.

Date de ieşire

83
CAPITOLUL 7. OJI 2017 7.1. NUMERE 84

Fişierul de ieşire numere.out va conţine o singură linie pe care va fi scris un singur număr
natural. Dacă C 1, va fi scris numărul cu care se termină drumul descris ı̂n fişierul de intrare.
Dacă C 2, va fi scrisă suma maximă a numerelor aflate pe un drum care se termină cu numărul
K.

Restricţii şi precizări

a 1 & N & 10000


a 1 & K & 10001 ˜ 10002©2
a Pentru rezolvarea corectă a cerinţei 1 se acordă 40 de puncte; pentru rezolvarea corectă a
cerinţei 2 se acordă 50 de puncte. 10 puncte se acordă din oficiu.

Exemple
numere.in numere.out Explicaţii
1 13 Cerinţa este 1. Drumul descris are lungimea 4 şi trece
4 prin numerele 1, 2, 5, 8, 13 .
1212
2 19 Cerinţa este 2. Suma maximă se obţine pe drumul
9 care trece prin numerele 1, 3, 6, 9 1  3  6  9 19.

Timp maxim de executare/test: 0.2 secunde


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

7.1.1 Indicaţii de rezolvare

prof. Cerasela-Daniela Cardaş, Colegiul Naţional A.T.Laurian Botoşani

1.Initializam casuta curenta si numarul liniei de pornire cu 1.

Pentru fiecare din cei n pasi din descriere:


- o alegere de tip 1 presupune actualizarea casutei curente cu valoarea casuta_cure
- o alegere de tip 2 conduce la actualizarea casutei curente cu casuta_curenta+lini
- incrementam numarul liniei curente.

2. Daca linia pe care se afla numarul K este l si numarul de ordine al numarului K


pe linia l este c, se observa ca suma maxima se obtine din insumarea ultimelor valo
de pe liniile 1,2,...,c si a valorilor de pe pozitia c din liniile c+1,c+2...,l.

Fie ultim - valoarea ultimului element de pe fiecare linie si l valoarea liniei cur
Initial ultim=1, l=0.
Cat timp ultim < K,incrementam linia, actualizam ultim cu ultim<-ultim+l, calculam
numerelor de linie.
Cand ultim>=K, elemc<-K
Repetat
-eliminam din suma s ultimul element de pe linia l si adunam elementul de pe poziti
-elemc<-elemc-l+1
-decrementam linia l
pana cand l=c

7.1.2 Cod sursă

Listing 7.1.1: numere cardas.cpp


///autor prof. Cerasela-Daniela Cardas, Colegiul National A.T.Laurian Botosani
#include <fstream>

using namespace std;


CAPITOLUL 7. OJI 2017 7.1. NUMERE 85

ifstream fin("numere.in");
ofstream fout("numere.out");

unsigned C,N,K,pas,curent,linie,rest,s,ultim;

int main()
{
fin>>C;
if(C==1)
{ fin>>N;curent=1;
for(linie=1;linie<=N;linie++)
{
fin>>pas;
curent+=linie;
if(pas==2)
curent++;
}
fout<<curent<<’\n’;
return 0;
}
///C=2
fin>>K;
while(ultim<K)
{
ultim+=++linie;
s+=ultim;
}
rest=ultim-K;
s-=rest*(rest+1)/2;
fout<<s<<’\n’;
return 0;
}

Listing 7.1.2: numere cerchez.cpp


//Emanuela Cerchez 90 puncte
#include <fstream>

using namespace std;

ifstream fin("numere.in");
ofstream fout("numere.out");
int c, n, K, nr, sum;

int main()
{
int lin, col, i, j, d, ultim;
fin>>c;
if (c==1)
{
fin>>n;
col=1;
for (i=0; i<n; i++)
{
fin>>d;
col+=d-1;
}
lin=n+1;
nr=lin*(lin-1)/2;//1+2+...lin-1
nr+=col;
fout<<nr<<’\n’;
}
else
{
fin>>K;
for (lin=1; K>lin*(lin+1)/2; lin++);
col=K-lin*(lin-1)/2;
sum=ultim=0;
for (i=1; i<=col; i++)
{
ultim+=i;
sum+=ultim;
}
for (i=col+1; i<=lin; i++)
{
CAPITOLUL 7. OJI 2017 7.1. NUMERE 86

ultim+=i;
sum+=(ultim-(i-col));
}
fout<<sum<<’\n’;
}
fout.close();
return 0;
}

Listing 7.1.3: numere jakab.cpp


#include <iostream>
#include <fstream>
#include <stdlib.h>

using namespace std;

int main()
{
ifstream in("numere.in");
ofstream out("numere.out");

int p,a,b,n,i,nr=1,lin,col;
in>>p;

if(p==1)
{
in>>n;
for(i=2;i<=n+1;i++)
{
in>>a;
if(a==1)
nr=nr+i-1;
else
nr=nr+i;
}
out<<nr<<endl;
}

if(p==2)
{
in>>nr;
a=1;lin=1;
while(a<nr)
{
lin++;
a=a+lin;
}

col=(a+nr)%lin;
a=1;
b=1;
for(i=2;i<=col;i++)
{
b=b+i;
a=a+b;
}
for(i=col;i<lin;i++)
{
b=b+i;
a=a+b;
}
out<<a;
}
in.close();
out.close();
return 0;
}

Listing 7.1.4: numere sandor.cpp


#include <fstream>

using namespace std;


CAPITOLUL 7. OJI 2017 7.1. NUMERE 87

ifstream fin("numere.in");
ofstream fout("numere.out");

int main()
{
int C,N,nr,i,x;
fin>>C;
if(C==1)
{
fin>>N;nr=1;
for(i=1;i<=N;i++)
{
fin>>x;
if(x==1)
nr=nr+i;
else
nr=nr+i+1;
}
fout<<nr;
}
else
{
int n,S;
fin>>N;
n=1;
while(n*(n+1)/2<N)
n++;
S=N;
while(n*(n+1)/2!=N)
{
n--;
N=N-n;
S=S+N;
}
n--;
while(n>=1)
{
S=S+n*(n+1)/2;
n--;
}
fout<<S;
}
return 0;
}

Listing 7.1.5: numere vladescu.cpp


#include <fstream>

using namespace std;

ifstream fin("numere.in");
ofstream fout("numere.out");

int n,c,nr,i,k,x,s,a,b,j;

int main()
{
fin>>c;
if (c==1)
{
fin>>n;
nr=1;
for (i=1;i<=n;i++)
{
fin>>x;
if (x==1)
nr=nr+i;
else
nr=nr+i+1;
}
fout<<nr;
}
else
CAPITOLUL 7. OJI 2017 7.2. ROBOT 88

{
fin>>k;
i=1; a=1;
while (a<k)
{
a=i*(i+1)/2;
if (k>a)
i=i+1;
}
b=0;
a=(i-1)*i/2;
while (a<k)
{
a=a+1;
b=b+1;
}
for (j=1;j<=b;j++)
s=s+j*(j+1)/2;
for (j=b+1;j<=i-1;j++)
s=s+j*(j-1)/2+b;
s=s+k;
fout<<s;
}
return 0;
}

7.1.3 *Rezolvare detaliată

7.2 robot
Problema 2 - robot 90 de puncte
Paul doreşte să ı̂nveţe cum să programeze un robot. Pentru ı̂nceput s-a gândit să construiască
un robot format dintr-un mâner, 10 butoane aranjate circular şi un ecran. Pe butoane sunt scrise,
ı̂n ordine crescătoare, cifrele de la 0 la 9, ca ı̂n figură.

Figura 7.2: Robot

Un roboprogram va fi format dintr-o secvenţă de instrucţiuni. Instrucţiunile pot fi:

Instrucţiune Explicaţii
Dp Mânerul robotului se deplasează spre dreapta cu p poziţii (p este o cifră).
Sp Mânerul robotului se deplasează spre stânga cu p poziţii (p este o cifră).
A Este apăsat butonul ı̂n dreptul căruia se află mânerul robotului şi pe ecran
apare cifra scrisă pe buton.
T Terminarea programului (se utilizează o singură dată la final şi este precedată
de cel puţin o instrucţiune A).

Iniţial mânerul robotului este plasat ı̂n dreptul butonului 0, iar ecranul este gol.
De exemplu, ı̂n urma executării roboprogramului D4AS1AAD6AT robotul apasă butoanele pe
care sunt scrise cifrele 4, 3, 3, 9, iar pe ecran va apărea 4339.

Cerinţe

Să se scrie un program care rezolvă următoarele cerinţe:


1. citeşte un roboprogram şi determină numărul de cifre afişate pe ecran după executarea
roboprogramului;
CAPITOLUL 7. OJI 2017 7.2. ROBOT 89

2. citeşte un roboprogram şi determină cifrele afişate pe ecran după executarea roboprogra-
mului;
3. citeşte un număr natural N şi construieşte un roboprogram de lungime minimă prin ex-
ecutarea căruia pe ecran se va obţine numărul N ; deoarece robotului ı̂i place să se deplaseze ı̂n
special spre dreapta, dacă există mai multe roboprograme de lungime minimă, se va afişa robo-
programul cu număr maxim de instrucţiuni D.

Date de intrare

Fişierul de intrare robot.in conţine pe prima linie un număr natural C, reprezentând cerinţa
care urmează să fie rezolvată (1, 2 sau 3). Dacă C 1 sau C 2, pe a doua linie a fişierului se
află un roboprogram. Dacă C 3, pe a doua linie a fişierului de intrare se află numărul natural
N.

Date de ieşire

Fişierul de ieşire robot.out va conţine o singură linie. Dacă C 1, pe prima linie se va scrie
un număr natural reprezentând numărul de cifre afişate pe ecran după executarea roboprogra-
mului din fişierul de intrare. Dacă C 2, pe prima linie vor fi scrise cifrele afişate pe ecran ı̂n
urma executării roboprogramului din fişierul de intrare. Dacă C 3, pe prima linie va fi scris
roboprogramul solicitat de cerinţa 3.

Restricţii şi precizări

a 0 & N & 1000000000


a Lungimea roboprogramului citit din fişierul de intrare sau scris ı̂n fişierul de ieşire este cel
mult 1000 de caractere.
a Dacă mânerul este plasat ı̂n dreptul butonului 0 şi se deplasează spre dreapta, se va ı̂ndrepta
către butonul 1; dacă deplasarea este spre stânga, se va ı̂ndrepta către butonul 9.
a Pentru rezolvarea corectă a primei cerinţe se acordă 10 de puncte, pentru rezolvarea corectă
a celei de a doua cerinţe se acordă 30 de puncte, iar pentru rezolvarea corectă a celei de a treia
cerinţe se acordă 50 de puncte. 10 puncte se acordă din oficiu.

Exemple

robot.in robot.out Explicaţii


1 3 C 1, pentru acest test se rezolvă cerinţa 1.
D1AD2AS1AT Se afişează pe ecran 3 cifre (132) .
2 3 C 2, pentru acest test se rezolvă cerinţa 2.
S0AD2AS1AT Mânerul robotului se deplasează cu 0 unităţi la stânga, deci
rămâne ı̂n dreptul butonului 0 şi apasă, apoi se deplasează 2
unităţi spre dreapta şi ajunge ı̂n dreptul butonului 2, apasă, apoi
se deplasează 1 unitate la stânga şi ajunge ı̂n dreptul butonului
1 şi apasă acest buton  021.
3 3 C 3, pentru acest test se rezolvă cerinţa 3.
19332 Pentru a afişa cifra 1, mânerul robotului se deplasează 1 uni-
tate la dreapta după care apasă (D1A). Pentru a afişa cifra 9,
din poziţia curentă mânerul robotului se deplasează 2 unităţi la
stânga şi apasă (S2A). Pentru a afişa cifra 3, din poziţia curentă
mânerul robotului se deplasează 4 unităţi la dreapta după care
apasă (D4A). Pentru a afişa a doua cifra 3, mânerul robotului
rămâne ı̂n poziţia curentă şi apasă butonul. Pentru a afişa cifra
2, din poziţia curentă mânerul robotului se deplasează 1 uni-
tate la stânga după care apasă (S1A). Programul se termină cu
instrucţiunea T  D1AS2AD4AAS1AT .

Timp maxim de executare/test: 0.2 secunde


Memorie: total 2 MB din care pentru stivă 1 MB
Dimensiune maximă a sursei: 10 KB
CAPITOLUL 7. OJI 2017 7.2. ROBOT 90

7.2.1 Indicaţii de rezolvare

prof. Jakab Irma-Tunde, Liceul Teoretic ”Bolyai Farkas”

Punctul 1

Numarul de cifre afisate pe ecran dupa executarea roboprogramului inseamna de cate


apasa robotul un anumit buton, adica de cate ori trebuie sa se execute instructiune

Astfel, se citeste roboprogramul caracter cu caracter si se numara caracterele ’A’.

Punctul 2

Determinarea cifrelor afisate pe ecran dupa executarea roboprogramului inseamna det


cifrei in dreptul careia se va pozitiona manerul robotului la executarea instructiu

Se citesc datele caracter cu caracter, se identifica directia si pozitia iar in fun


directia indicata se determina cifra care trebuie afisata.

Pentru stabilirea pozitiei, caracterele cifre din roboprogram trebuie transformate


cifre numerice.

Daca directia indicata este dreapta si deoarece manerul robotului se deplaseaza cir
numarul de pozitii efectuate va fi suma dintre pozitia (cifra curenta) si cifra ind
in program modulo 10 (avand in total 10 cifre). Daca directia indicata este dreapta
din cauza deplasarii circulare din pozitia curenta se scade cifra din roboprogram,
rezultatul este negativ, se aduna 10.

Trebuie sa se tina cont de faptul ca instructiunile pot sa indice cifre 0 chiar la


respectiv cifrele pot aparea de mai multe ori datorita prezentei repetate a instruc

Punctul 3

Pentru numarul citit, instructiunile trebuie asociate incepand de la cifra cea mai
semnificativa spre cifra unitatilor si trebuie acordat atentie cifrelor 0 de la sfa
numarului dat (se determina oglinditul numarului si se retine numarul de zerouri de
sfarsitul numarului citit).

Numarul citit se prelucreaza cifra cu cifra, se calculeaza numarul de deplasari nec


spre stanga si spre dreapta, se alege directia in care deplasarea se va face intr-u
minim de pasi.
In calcularea numarului de deplasari se tine cont de miscarea circulara a manerului
In cazul in care cele doua numere sunt egale, se alege directia dreapta.

Daca numarul citit avea zerouri la sfarsitul numarului, se determina numarul de dep
necesare afisarii acestora si se introduc in roboprogram un numar de instructiuni A
numarul de zerouri calculate.

7.2.2 Cod sursă

Listing 7.2.1: robot cerchez.cpp


//Em. Cerchez 90 puncte
#include <fstream>

using namespace std;

ifstream fin("robot.in");
ofstream fout("robot.out");
CAPITOLUL 7. OJI 2017 7.2. ROBOT 91

int cerinta, n;

int main()
{
char c;
int nr, st, dr, poz, zero, cat, cifra;

fin>>cerinta;

if(cerinta==1)
{
c=’*’; nr=0;
while (c!=’T’)
{
fin>>c;
if (c==’A’) nr++;
}
fout<<nr<<’\n’;
fout.close();
return 0;
}

if(cerinta==2)
{
c=’*’; nr=0; poz=0;
while (c!=’T’)
{
fin>>c;
if (c==’A’) fout<<poz;
else
if (c==’D’)
{
fin>>c;
cat=c-’0’;
poz=(poz+cat)%10;
}
else
if (c==’S’)
{
fin>>c;
cat=c-’0’;
poz-=cat;
if(poz<0) poz+=10;
}
}
fout<<’\n’;
fout.close();
return 0;
}

fin>>n;

if (n==0){fout<<"AT\n"; fout.close(); return 0; }


zero=0;
while (n%10==0) {zero++;n/=10;}
nr=0;
while (n) {nr=nr*10+n%10; n/=10;}

//obtin nr
poz=0;
while (nr)
{
cifra=nr%10; nr/=10;
if (cifra!=poz)
{
if (cifra<poz)
{
st=poz-cifra;
dr=10+cifra-poz;
}
else
{
dr=cifra-poz;
st=10+poz-cifra;
}
CAPITOLUL 7. OJI 2017 7.2. ROBOT 92

if (st<dr)
fout<<"S"<<st;
else
fout<<"D"<<dr;
}
poz=cifra;
fout<<"A";
}

if (zero)
{
if (poz)
{
dr=10-poz; st=poz;
if (st<dr)
fout<<"S"<<st;
else
fout<<"D"<<dr;
}
while (zero) {fout<<"A"; zero--;}
}
fout<<"T\n";
fout.close();
return 0;
}

Listing 7.2.2: robot cerchez ok.cpp


//Em. Cerchez 90 puncte
#include <fstream>

using namespace std;

ifstream fin("robot.in");
ofstream fout("robot.out");

int cerinta, n;

int main()
{
char c;
int nr, st, dr, poz, zero, cat, cifra;
fin>>cerinta;
if (cerinta==1)
{
c=’*’; nr=0;
while (c!=’T’)
{
fin>>c;
if (c==’A’) nr++;
}
fout<<nr<<’\n’;
fout.close();
return 0;
}

if (cerinta==2)
{
c=’*’; nr=0; poz=0;
while (c!=’T’)
{
fin>>c;
if (c==’A’) fout<<poz;
else
if (c==’D’)
{
fin>>c;
cat=c-’0’;
poz=(poz+cat)%10;
}
else
if (c==’S’)
{
fin>>c;
cat=c-’0’;
CAPITOLUL 7. OJI 2017 7.2. ROBOT 93

poz-=cat;
if(poz<0) poz+=10;
}
}
fout<<’\n’;
fout.close();
return 0;
}

fin>>n;
if (n==0){fout<<"AT\n"; fout.close(); return 0; }
zero=0;
while (n%10==0) {zero++;n/=10;}
nr=0;
while (n) {nr=nr*10+n%10; n/=10;}

//obtin nr
poz=0;
while (nr)
{
cifra=nr%10; nr/=10;
if (cifra!=poz)
{
if (cifra<poz)
{
st=poz-cifra;
dr=10+cifra-poz;
}
else
{
dr=cifra-poz;
st=10+poz-cifra;
}
fout<<"D"<<dr;
}
poz=cifra;
fout<<"A";
}

if (zero)
{
if (poz)
{
dr=10-poz; st=poz;
fout<<"D"<<dr;
}
while (zero) {fout<<"A"; zero--;}
}
fout<<"T\n";
fout.close();
return 0;
}

Listing 7.2.3: robot jakab.cpp


//Jakab Tunde
#include <iostream>
#include <fstream>
#include <stdlib.h>

using namespace std;

int main()
{
ifstream in("robot.in");
ofstream out("robot.out");
char c;
int a=0,b=0,n=0,m=0,z=0,e,d,p;
in>>p;

if(p==1)
{
while(!in.eof())
{
in>>c;
CAPITOLUL 7. OJI 2017 7.2. ROBOT 94

if (c==’A’)a++;
}
out<<a<<endl;
}

if(p==2)
{
in>>c;
b=0;
while(c!=’T’)
{
if (c==’D’)
{
in>>c;
a=c-48;
b=(b+a)%10;
}
else
if (c==’S’)
{
in>>c;
a=c-48;
b=(b+10-a)%10;
}
if(c==’A’) out<<b;
in>>c;
}
}

if(p==3)
{
in>>a;
if(a==0)out<<"A";
else
if(a<10)
{
if(10-a<a)
out<<’S’<<10-a<<’A’;
else
out<<’D’<<a<<’A’;
}
else
{
z=0;
while(a%10==0)
{
z++;
a=a/10;
}
while(a!=0)
{
b=b*10+a%10;
a=a/10;
}

a=b;
b=a%10;
if(10-b<b)
out<<’S’<<10-b<<’A’;
else
out<<’D’<<b<<’A’;
a=a/10;
while(a!=0)
{
if(b==a%10)
out<<’A’;
else
if(b>a%10)
if(10-b+a%10<=b-a%10)
out<<’D’<<10-b+a%10<<’A’;
else
out<<’S’<<b-a%10<<’A’;
else
if(10-a%10+b<a%10-b)
out<<’S’<<10-a%10+b<<’A’;
else
CAPITOLUL 7. OJI 2017 7.2. ROBOT 95

out<<’D’<<a%10-b<<’A’;
b=a%10;
a=a/10;
}

if(z!=0)
{
if(10-b<b)
out<<’D’<<b;
else
out<<’S’<<b;
while(z!=0)
{
out<<’A’;
z--;
}
}
}

out<<’T’;
}
in.close();
out.close();
return 0;
}

7.2.3 *Rezolvare detaliată


Capitolul 8

OJI 2016

8.1 colier
Problema 1 - colier 90 de
puncte
Maria are ı̂n camera sa N mărgele aşezate una lângă alta. Pe fiecare dintre ele este scris un
număr natural format din cifre nenule distincte. Pentru fiecare mărgea, Maria şterge numărul şi
ı̂n locul său scrie altul, având doar două cifre, respectiv cifra minimă şi cifra maximă din numărul
scris iniţial, ı̂n ordinea ı̂n care aceste cifre apăreau ı̂nainte de ştergere. Acum Maria consideră că
mărgelele sunt de două tipuri, ı̂n funcţie de numărul de două cifre scris pe ele: tipul 1 (cele care
au cifra zecilor mai mică decât cifra unităţilor) şi tipul 2 (celelalte). Folosind mărgelele, fetiţa
doreşte ca prin eliminarea unora dintre ele (dar fără să le schimbe ordinea celorlalte) să obţină
un colier circular cât mai lung care să respecte proprietatea că oricare două mărgele vecine ale
sale sunt de tipuri diferite. În colierul format cu mărgelele rămase după eliminare se consideră că
prima mărgea este vecină cu ultima.

Cerinţe

1) determinaţi numărul de mărgele de tipul 1;


2) determinaţi numărul maxim de mărgele pe care le poate avea colierul;

Date de intrare

Fişierul colier.in conţine pe prima linie un număr natural T . Pe linia a doua se găseşte un
număr natural N . Pe linia a treia sunt N numere naturale ce reprezintă, ı̂n ordine, valorile scrise
iniţial pe mărgele. Aceste numere sunt separate prin câte un spaţiu.

Date de ieşire

Dacă valoarea lui T este 1, se va rezolva numai punctul 1) din cerinţe. În acest caz, fişierul de
ieşire colier.out va conţine pe prima linie un număr natural reprezentând răspunsul la cerinţa 1).
Dacă valoarea lui T este 2, se va rezolva numai punctul 2) din cerinţe. În acest caz, fişierul de
ieşire colier.out va conţine pe prima linie un număr natural reprezentând răspunsul la cerinţa 2).

Restricţii şi precizări

a 1 & N & 50000;


a Numerele scrise iniţial pe mărgele au cifrele distincte, nu conţin cifra 0 şi sunt cuprinse ı̂ntre
12 şi 987654321;
a T va fi 1 sau 2;
a Pentru obţinerea colierului, Maria poate decide să nu elimine nicio mărgea;
a Colierul obţinut poate fi format şi dintr-o singură mărgea;
a Pentru teste ı̂n valoare de 20 de puncte avem T 1 şi toate numerele scrise iniţial pe mărgele
au două cifre;
a Pentru teste ı̂n valoare de 30 de puncte avem T 1 şi dintre numerele scrise iniţial pe
mărgele sunt şi unele cu mai mult de două cifre;
a Pentru teste ı̂n valoare de 50 de puncte avem T 2.

96
CAPITOLUL 8. OJI 2016 8.1. COLIER 97

Exemple
colier.in colier.out Explicaţii
1 3 Numerele scrise de Maria pe mărgele vor fi, ı̂n ordine: 12 68 31
5 24 93. Trei dintre ele (12, 68 şi 24) sunt de tipul 1. (T fiind 1
12 678 312 24 938 se rezolvă doar cerinţa 1).
2 4 Numerele scrise de Maria pe mărgele vor fi, ı̂n ordine: 12 68 31
5 24 93. Eliminând mărgeaua de pe poziţia 1 sau pe cea de pe
12 678 312 24 938 poziţia 2 şi aşezându-le pe celelalte circular obţinem un colier cu
4 mărgele ı̂n care oricare două vecine sunt de tipuri diferite. (T
fiind 2 se rezolvă doar cerinţa 2). Maria este obligată să elimine
una din cele două mărgele, altfel ar exista mărgele vecine de
acelaşi tip.

Timp maxim de executare/test: 0.5 secunde


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

8.1.1 Indicaţii de rezolvare

prof. Marius Nicoli, C.N. ”Fratii Buzeşti”, Craiova

Prima cerinţă se rezolvă prin aplicarea pentru fiecare număr a algoritmului de parcurgere a
cifrelor sale, identificând cifra maximă si cea minimă a sa, precum şi poziţiile lor.
Pentru cerinţa a doua, determinăm câte secvenţe maximale formate din valori de acelaşi tip
există. Dacă prima şi ultima secvenţă sunt formate din acelaşi tip de mărgele, scădem 1 din
valoarea dererminată anterior.
Ambele cerinţe se rezolvă procesând numerele ı̂n momentul citirii, deci fără a fi necesare
tablouri de memorie.

8.1.2 Cod sursă

Listing 8.1.1: colier gina.cpp


#include<fstream>

using namespace std;

ifstream f("colier.in");
ofstream g("colier.out");

int main()
{
int x,P,M,p,m,poz=0,n,t,s=0,a,b,k=1;

f>>t>>n;
f>>x;

poz=0;
m=10;
M=-1;
while(x)
{
poz++;
if(x%10>M)
{
M=x%10;
P=poz;
}
if(x%10<m)
{
m=x%10;
p=poz;
}
CAPITOLUL 8. OJI 2016 8.1. COLIER 98

x=x/10;
}

s+=(1+(p<P))==1;
a=1+(p<P);
for(int i=2;i<=n;i++)
{
f>>x;
poz=0;
m=10;
M=-1;
while(x)
{
poz++;
if(x%10>M)
{
M=x%10;
P=poz;
}
if(x%10<m)
{
m=x%10;
p=poz;
}
x=x/10;
}

s+=(1+(p<P))==1;
b=1+(p<P);
if(a!=b)
{
k++;
a=b;
}
}
if(k%2)k--;

if(t==1)
g<<s<<’\n’;
else
g<<k<<’\n’;
f.close();
g.close();
return 0;
}

Listing 8.1.2: colier Marius.cpp


#include <fstream>

using namespace std;

int n, i, x, c, maxim, minim, nr, pmaxim, pminim, tip, tipa, sol1, sol2, first, t;

int main ()
{
ifstream fin ("colier.in");
ofstream fout("colier.out");

fin>>t>>n;
sol2 = 1;
for(i=1;i<=n;i++)
{
fin>>x;
maxim = 0;
minim = 9;
nr = 0;
while(x != 0)
{
c = x % 10;
nr++;
if(c > maxim)
{
maxim = c;
pmaxim = nr;
CAPITOLUL 8. OJI 2016 8.1. COLIER 99

}
if(c < minim)
{
minim = c;
pminim = nr;
}
x /= 10;
}

if(pmaxim < pminim)


{
tip = 1;
sol1++;
}
else
{
tip = 2;
}
if(i == 1)
first = tip;
else
{
if (tip != tipa)
{
sol2++;
}
}
tipa = tip;
}

if (tip == first)
sol2--;

if (t == 1)
fout<<sol1<<"\n";
else
{
if (sol1 == n || sol1 == 0)
fout<<"1\n";
else
fout<<sol2<<"\n";
}
return 0;
}

Listing 8.1.3: colier Miana.cpp


#include<fstream>

using namespace std;

ifstream f("colier.in");
ofstream g("colier.out");

int main()
{
int n, nr=1, tip1=0, tip2=0,x,c,u,k=0,cmin=10,cmax=0,pcmin,pcmax,p,i,t;
f>>t>>n>>x;

while (x)
{
c=x%10;
k++;
if (c<cmin) { cmin=c; pcmin=k; }
if (c>cmax) { cmax=c; pcmax=k; }
x/=10;
}

if (pcmin>pcmax) { tip1++; u=p=1; }


else { tip2++; u=p=2; }

for (i=2; i<=n; i++)


{
f>>x;
k=0; cmin=10; cmax=0;
CAPITOLUL 8. OJI 2016 8.1. COLIER 100

while (x)
{
c=x%10;
k++;
if (c<cmin) { cmin=c; pcmin=k; }
if (c>cmax) { cmax=c; pcmax=k; }
x/=10;
}

if (pcmin>pcmax)
{
tip1++;
if (u!=1) {nr++; u=1;}
}
else
{
tip2++;
if (u!=2) {nr++; u=2;}
}
}

if (u==p) nr--;
if (t==1)
g<<tip1<<’\n’;
else
g<<nr<<’\n’;

return 0;
}

Listing 8.1.4: colier sanda.cpp


#include <iostream>
#include <fstream>

using namespace std;

ifstream f("colier.in");
ofstream out("colier.out");

int main()
{
int n,m,x,y,a,b,c,T,maxim,minim,maxi,mini,tipa,tipb,tipul,tip1=0,i,k;

ifstream in("colier.in");

in>>T;
in>>n;m=n;
in>>a;
y=a; maxim=0; maxi=0; minim=999999999; mini=0, k=0;
while(y)
{
c=y%10;k++;
if(c>maxim)
maxim=c,maxi=k;
if(c<minim)
minim=c,mini=k;
y/=10;
}

if(mini>maxi)
tip1++,tipa=1;
else
tipa=2;

tipul=tipa;
// cout<<"a="<<a<<endl;
// cout<<"*"<<n<<" "<<tip1<<" "<<tipa<<endl;

for(i=2;i<=m;i++)
{
in>>b; // cout<<"b="<<b<<endl;
y=b;maxim=0;maxi=0;minim=999999999; mini=0;k=0;
while(y)
CAPITOLUL 8. OJI 2016 8.2. PALINDROM 101

{
c=y%10;k++;
if(c>maxim) maxim=c, maxi=k;
if(c<minim) minim=c, mini=k;
y/=10;
}
if(mini>maxi)
tip1++,tipb=1;
else
tipb=2;
if(tipa==tipb) n--;
//cout<<"!"<<n<<" "<<tip1<<" "<<tipb<<endl;
a=b,tipa=tipb;
}

if(tipb==tipul) n--;
// cout<<"*"<<n<<" "<<tip1<<" "<<tipb<<" "<<tipul<<endl;
if(T==1)
out<<tip1;
else
out<<n;

return 0;
}

8.1.3 *Rezolvare detaliată

8.2 Palindrom
Problema 2 - Palindrom 90 de
puncte
Un număr se numeşte palindrom dacă prima lui cifră este egală cu ultima, a doua cu penultima
şi aşa mai departe. De exemplu numerele 1221, 505 şi 7 sunt palindromuri, ı̂n vreme ce 500, 1410
şi 2424 nu sunt palindromuri.
Similar, un număr se numeşte aproape palindrom dacă are aceleaşi perechi de cifre identice
ca un palindrom, mai puţin o pereche ı̂n care cifrele diferă. De exemplu numerele 500, 1411,
2444, 1220, 53625, 14 şi 4014 sunt numere aproape palindromuri (cu perechea de cifre neidentice
ı̂ngroşată), ı̂n vreme ce 1221, 1410, 6, 505, 22 şi 512125 nu sunt numere aproape palindromuri
deoarece fie sunt palindromuri, fie au prea multe perechi de cifre diferite.
Mai definim palindromul asociat al unui număr x ca fiind cel mai mic număr palindrom p
strict mai mare decât x (p % x). De exemplu palindromul asociat al lui 5442 este 5445, palindromul
asociat al lui 2445 este 2552, al lui 545 este 555, al lui 39995 este 40004, al lui 500 este 505, iar al
lui 512125 este 512215.

Cerinţe

Scrieţi un program care citind un număr natural nenul n şi apoi un şir de n numere naturale
determină:
1. câte dintre cele n numere sunt palindrom
2. câte dintre cele n numere sunt aproape palindrom
3. palindromurile asociate pentru cele n numere citite.

Date de intrare

Fişierul de intrare palindrom.in conţine pe prima linie un număr C. Pentru toate testele, C
poate lua numai valorile 1, 2 sau 3. Pe a doua linie se află numărul n, iar pe a treia linie cele n
numere naturale despărţite prin câte un spaţiu.

Date de ieşire

Fişierul de ieşire palindrom.out:


a dacă C 1, va conţine un singur număr natural reprezentând numărul de numere palindrom
din şir
CAPITOLUL 8. OJI 2016 8.2. PALINDROM 102

a dacă C 2, va conţine numărul de numere din şir care sunt aproape palindrom
a dacă C 3, va conţine numerele palindrom asociate celor n numere din şir, separate prin
câte un spaţiu

Restricţii şi precizări

a 1 & n & 10000


a 1 & numerele din şir & 2000000000
a Pentru rezolvarea corectă a primei cerinţe se acordă 20 de puncte, pentru rezolvarea corectă
a celei de a doua cerinţe se acordă 30 de puncte, iar pentru rezolvarea corectă a celei de a treia
cerinţe se acordă 50 de puncte.

Exemple

palindrom.in palindrom.out
1 5
7
1221 500 53635 505 7 4004 1410
Explicaţie: Cele 5 numere palindrom sunt 1221, 53635, 505, 7 şi 4004
(C fiind 1, se rezolvă doar prima cerinţă).
2 3
4
5442 2445 545 39995
Explicaţie: Cele 3 numere aproape palindrom sunt 5442, 2445 şi 39995
(C fiind 2, se rezolvă doar a doua cerinţă).
3 7 1441 2552 1331 515 1221 53635 22 4114 1441 33
11
6 1411 2444 1221 505 1220 53625 14 4014 1410 22
Explicaţie: Palindromul asociat lui 6 este 7, al lui 1411 este 1441, al lui 2444 este 2552 etc.
(C fiind 3, se rezolvă doar a treia cerinţă).

Timp maxim de executare/test: 0.5 secunde


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

8.2.1 Indicaţii de rezolvare

autor Cristian Francu

Cerinta 1
Punctul 1 al problemei este relativ banal, cerand sa spunem cate numere palindrom exista
intr-un sir de numere. Cu toate acestea trebuie avut grija deoarece algoritmul standard calculeaza
rasturnatul numarului, care poate sa depaseasca valoarea maxima a unui intreg, de circa doua
miliarde (de exemplu numarul 1234554327). Pentru a nu depasi intregul putem proceda in mai
multe moduri:
1. Putem sa extragem cifrele din capetele opuse ale numarului, spre a le compara, iar apoi le
eliminam. Pentru aceasta vom calcula p10, puterea maxima a lui 10 care este mai mica sau egala
cu numarul nostru, x. Apoi avem:

prima_cifra = x / p10;
ultima_cifra = x % 10;
x = x % p10 / 10;
p10 = p10 / 100;

2. Putem sa rasturnam numarul doar pana la jumatatea sa. Facem acest lucru la fel ca in
algoritmul clasic, adaugand cifrele de la coada lui x la coada lui y, cu diferenta ca ne vom opri
atunci cand x ¡= y.
CAPITOLUL 8. OJI 2016 8.2. PALINDROM 103

Cerinta 2
Cerinta 2 se rezolva similar cu punctul 1, numai ca de data aceasta vom numara cate diferente
avem intre perechile de cifre. Cu algoritmul clasic rasturnam numarul x in y si apoi extragem pe
rand cifre din coada ambelor numere calculand cate perechi diferite avem.
Daca numarul de perechi diferite este 0, numarul este palindrom, iar daca este 2 atunci numarul
este aproape palindrom.
Avem aceeasi problema insa, ca si la punctul 1, anume pe anumite numere vom depasi intregul.
Pentru a nu depasi putem iar aplica metodele descrise la punctul 1.
Cerinta 3
Punctul 3 al problemei se reduce la a calcula pentru un numar x cel mai mic palindrom strict
mai mare ca x. Putem rezolva direct, incrementand x si testand daca este palindrom, avand grija
la depasire. Aceasta metoda este destul de lenta si va depasi timpul la cateva teste. O metoda
mai rapida este urmatoarea:
Vom porni cu numarul x x  1 si vom calcula cel mai mic palindrom mai mare sau egal cu
x.
Pentru aceasta calculam y, simetrizarea lui x, ca fiind copierea primei jumatati in cea de-a
doua, rasturnata. De exemplu pentru 123456 vom calcula 123321, iar pentru 4066345 vom calcula
4066604. Daca palindromul calculat, y, este mai mare sau egal cu x, atunci el este chiar raspunsul.
Altfel, daca este mai mic, va trebui sa calculam numarul z caruia i se aduna unu la ultima cifra
dinainte de jumatatea a doua a numarului. Daca simetrizam z vom obtine raspunsul.

8.2.2 Cod sursă

Listing 8.2.1: palindrom Marius.cpp


#include <fstream>
#include <cstring>

using namespace std;

char s[12];
int t, n, i, j, k, t1, t2, nr;

int main ()
{
ifstream fin("palindrom.in");
ofstream fout("palindrom.out");

fin>>t>>n;

for (i=1;i<=n;i++)
{
fin>>s;
int nr = 0;
for (j=0, k=strlen(s)-1; j<k; j++, k--)
{
if (s[j] != s[k]) nr++;
}
if (nr == 0) t1++;
if (nr == 1) t2++;

if (t == 3)
{
int number = 0;
int noua = 1;
for (j=0;s[j]!=0;j++)
{
if (s[j] != ’9’) { noua = 0; }
number = number*10 + s[j] - ’0’;
}
if (noua)
{
fout<<1;
for (j=0;s[j+1]!=0;j++) fout<<0;
fout<<"1 ";
CAPITOLUL 8. OJI 2016 8.2. PALINDROM 104

continue;
}

if (strlen(s) % 2 == 0)
{
int left = 0;
for (j=0;j<strlen(s)/2;j++)
left = left * 10 + s[j] - ’0’;
int auxleft = left;
int rez = left;
while (left != 0)
{
rez = rez * 10 + left % 10;
left /= 10;
}
if (rez > number)
{
fout<<rez<<" ";
continue;
}
else
{
left = auxleft + 1;
rez = left;
while (left != 0)
{
rez = rez * 10 + left % 10;
left /= 10;
}
fout<<rez<<" ";
continue;
}
}
else
{
int left = 0;
for (j=0;j<=strlen(s)/2;j++)
left = left * 10 + s[j] - ’0’;
int auxleft = left;
int rez = left;
left /= 10;
while (left != 0)
{
rez = rez * 10 + left % 10;
left /= 10;
}
if (rez > number)
{
fout<<rez<<" ";
continue;
}
else
{
left = auxleft + 1;
rez = left;
left /= 10;
while (left != 0)
{
rez = rez * 10 + left % 10;
left /= 10;
}
fout<<rez<<" ";
continue;
}
}
}
}

if (t == 1) fout<<t1<<"\n";
if (t == 2) fout<<t2<<"\n";
return 0;
}

Listing 8.2.2: palindrom Sanda.cpp


CAPITOLUL 8. OJI 2016 8.2. PALINDROM 105

#include <iostream>
#include <fstream>

using namespace std;

ifstream in("palindrom.in");
ofstream out("palindrom.out");

int main()
{
int c,n,i,j,k,d=1, nrap=0,nrpal=0;
long long x,y,z=0,a,b;

in>>c;
in>>n;

for(i=1;i<=n;i++)
{
in>>x;
y=x;
z=k=0;
while(y)
{
z=z*10+y%10;
k++;
y/=10;
}
if(c==1)
{
if(x==z) nrpal++;
}
else
if(c==2)
{
a=x,b=z,d=0;
while(a && d<=2){
if(a%10!=b%10) d++;
a/=10,b/=10;
}
if(d==2)
nrap++;
}
else
{
int m=1,prim,ultim;
for(j=1;j<=k/2;j++) m*=10;

y=x/m*m+z%m;
if(y<=x)
{
if(k%2==0)
a=b=(x/m+1);
else
a=b=(x/m+1)/10;
z=0;
while(b)
{
z=z*10+b%10;
b=b/10;
}
y=(x/m+1)*m+z;
}
out<<y<<’ ’;
}
}
if(c==1) out<<nrpal;
else
if(c==2) out<<nrap;

return 0;
}

8.2.3 *Rezolvare detaliată


Capitolul 9

OJI 2015

9.1 Cuart
Problema 1 - Cuart 100 de puncte
Gina şi Mihai joacă ı̂mpreună jocul Cuart. Ei au la dispoziţie un şir de 2 ˜ N cartonaşe ce conţin
numere naturale. Primele N cartonaşe, de la stânga la dreapta, sunt ale Ginei, iar următoarele
N ale lui Mihai. Gina traveresează şirul, de la stânga la dreapta şi scrie pe o foaie de hârtie, pe
primul rând, un şir de numere obţinut din numerele de pe cartonaşele sale, din care a şters toate
cifrele pare. La fel procedează Mihai care scrie pe foaia sa de hârtie, pe primul rând, şirul de
numere obţinut din numerele de pe cartonaşele sale, din care a şters toate cifrele impare. Dacă
dintr-un număr s-au şters toate cifrele, sau au rămas doar cifre egale cu 0, atunci numărul este
ignorat, deci pe hârtie nu se scrie nimic.
Fiecare copil, notează pe hârtia sa, pe al doilea rând, un alt şir de numere obţinut astfel:
pentru fiecare număr X scris pe primul rând, copilul va scrie cel mai mare număr natural K cu
proprietatea că 1  5  9  13  ...  K & X. În jocul copiilor, numărul X se numeşte cuarţ dacă
1  5  9  13  ...  K X .

Figura 9.1: Cuart

În exemplul de mai sus, Gina nu a scris niciun număr cuarţ pe primul rând, iar Mihai a scris
unul singur (6=1+5). Regulile de câştig ale jocului sunt următoarele:
a Câştigă acel copil care are scrise pe primul rând cele mai multe numere cuarţ. În acest caz,
valoarea de câştig a jocului este egală cu numărul de numere cuarţ scrise de copilul câştigător.
a Dacă cei doi copii au scris acelaşi număr de numere cuarţ, atunci va câştiga cel care are primul
număr scris pe primul rând, mai mare decât al celuilalt. Acest prim număr scris de câştigător va
reprezenta valoarea de câştig.
a Dacă nici Gina şi nici Mihai nu au scris niciun număr pe hârtie, se consideră egalitate şi nu
câştigă niciunul.

Cerinţe

Scrieţi un program care să citească numărul N reprezentând numărul de cartonaşe ale unui
copil şi cele 2 ˜ N numere de pe cartonaşe, ı̂n ordine de la stânga la dreapta şi care să determine:
1) Cel mai mare număr de pe cele 2 ˜ N catonaşe, pentru care nu s-a scris niciun număr pe
primul rând (a fost omis), nici pe hârtia Ginei, nici pe hârtia lui Mihai; dacă nu a fost omis niciun
număr, se va scrie 0;
2) Câştigătorul jocului şi afişează numărul 1 dacă a câştigat Gina, 2 pentru Mihai sau 0 ı̂n caz
de egalitate.
3) Valoarea de câştig a jocului, sau 0, ı̂n caz de egalitate.

Date de intrare

106
CAPITOLUL 9. OJI 2015 9.1. CUART 107

Fişierul de intrare cuart.in conţine pe prima linie un număr natural P . Pentru toate testele
de intrare, numărul P poate avea doar valoarea 1, valoarea 2 sau valoarea 3. Pe a doua linie a
fişierului de intrare cuart.in se găseşte numărul natural N reprezentând numărul de cartonaşe
ale fiecărui copil şi pe a treia linie, ı̂n ordine de la stânga la dreapta, numerele de pe cele 2 ˜ N
cartonaşe, separate prin câte un spaţiu.

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 cuart.out va conţine pe prima linie un număr natural reprezentând răspunsul la cerinţa 1).
Dacă valoarea lui P este 2, se va rezolva numai punctul 2) din cerinţe. În acest caz, fişierul de
ieşire cuart.out va conţine pe prima linie un număr natural reprezentând răspunsul la cerinţa 2).
Dacă valoarea lui P este 3, se va rezolva numai punctul 3) din cerinţe. În acest caz, fişierul de
ieşire cuart.out va conţine pe prima linie un număr natural reprezentând răspunsul la cerinţa 3).

Restricţii şi precizări

a 1 & N & 1000


a 1 & numerele de pe cartonaşe $ 100000000
a Pentru rezolvarea corectă a primei cerinţe se acordă 20 de puncte, pentru rezolvarea corectă
a celei de a doua cerinţe se acordă 30 de puncte, pentru rezolvarea corectă a celei de a treia cerinţe
se acordă 50 de puncte.

Exemple
cuart.in cuart.out Explicaţii
1 284260 P = 1, pentru acest test, se rezolvă cerinţa 1).
4 Gina a scris pe hârtia sa, pe două rânduri nu-
1234 48 284260 75 756 1232515 153 98 merele:
13 75
5 21
Mihai a scris pe hârtie numerele:
6 22 8
595
Cel mai mare număr omis este 284260
2 2 P = 2, pentru acest test, se rezolvă cerinţa 2). A
4 câştigat Mihai deoarece are un număr cuarţ, iar
1234 48 284260 75 756 1232515 153 98 Gina niciunul.
3 28 P = 3, pentru acest test, se rezolvă cerinţa 3).
1 Gina a scris pe hârtia sa, pe două rânduri nu-
154 2181 merele:
15
9
Mihai a scris pe hârtie numerele:
28
13
Ambii copii au scris câte un număr cuarţ, ı̂nsă
a câştigat Mihai care are primul număr scris pe
primul rând mai mare decât al Ginei. Valoarea
de câştig a jocului este 28.

Timp maxim de executare/test: 1.0 secunde


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

9.1.1 Indicaţii de rezolvare

Pentru primele N cartonase:


* se citeste, pe rand, cate un numar (cartonas) si se sterg cifrele sale pare. Daca numarul
ramas X este diferit de 0, atunci:

ˆ daca este primul, il salvez intr-o variabila


CAPITOLUL 9. OJI 2015 9.1. CUART 108

ˆ caut kmax cu proprietatea ca 1+5+9+...+k ¡= X. Cautarea lui k se poate face cu ajutorul


unei formule (1+5+9+...+(4M+1) = (M+1)(2M+1), unde k=4M+1) sau prin calcularea
efectiva a sumei
ˆ daca obtinem egalitate in relatia anterioara, atunci marim numarul de numere cuart ale
Ginei cu 1

Pentru urmatoarele N cartonase se repeta pasii anteriori cu modificarea aferenta.

9.1.2 Cod sursă

Listing 9.1.1: cuart dl.cpp


#include <cstdio>
#include <algorithm>
#include <cassert>

#define MRD 99999999

using namespace std;

int K, N, A, B, N1, N2, Nr, P, first1, first2,


cuart1, cuart2, Max, i, Sum, t, p, x,X, cx, d, u, nr;
bool ok;

int main()
{
freopen("cuart.in", "r",stdin);
freopen("cuart.out","w",stdout);

scanf("%d\n%d",&P, &N);
assert(N<=1000 && N>=1 && P>0 && P<4);

first1=cuart1=0;

for(int i=1; i<=N; i++)


{
scanf("%d",&X);
assert(X<100000000 && X>0);

p=1; x=0; cx=X;


while(cx)
{
if(cx%2) {x=x + cx%10 *p; p*=10;}
cx/=10;
}

if(x)
{
if(!first1) first1=x;
Sum=0; t=1;
while (Sum + t <= x)
{
Sum+=t;
t+=4;
}
if(Sum==x) cuart1++;
}
else Max=max(X, Max);
}

first2=cuart2=0;
for(int i=1; i<=N; i++)
{
scanf("%d",&X);
assert(X<100000000 && X>0);

p=1; x=0; cx=X;


while(cx)
{
if(cx%2==0) {x=x + cx%10 *p; p*=10;}
cx/=10;
CAPITOLUL 9. OJI 2015 9.1. CUART 109

if(x)
{
if(!first2) first2=x;
Sum=0; t=1;
while (Sum + t <= x)
{
Sum+=t;
t+=4;
}
if(Sum==x) cuart2++;
}
else Max=max(X, Max);
}

if(P==1)
printf("%d\n", Max);
else
{
if(cuart1>cuart2)
{
if (P==2) printf("1\n"); else printf("%d\n",cuart1);
}
else
if(cuart1<cuart2)
{
if (P==2) printf("2\n"); else printf("%d\n", cuart2);
}
else
if(first1==0 && first2 ==0)
{
if (P==2) printf("0\n"); else printf("%d\n", 0);
}
else
if (first1>first2)
{
if (P==2) printf("1\n"); else printf("%d\n",first1);
}
else
{
if (P==2) printf("2\n"); else printf("%d\n",first2);
}
}
return 0;
}

Listing 9.1.2: cuart dt.cpp


#include <fstream>
#include<math.h>

using namespace std;

ifstream f("cuart.in");
ofstream g("cuart.out");

int n,x;

int main()
{
int i,max1=0,p=1,nr=0,y,q1=0,q2=0,k,s,
prim1=0, prim2=0,max2=0,nr1=0,nr2=0,P;

f>>P>>n;

for(i=1; i<=n; i++)


{
f>>x;
y=x;
while(x!=0)
{
if(x%10%2)
{
nr=nr+x%10*p;
CAPITOLUL 9. OJI 2015 9.1. CUART 110

p=p*10;
}
x=x/10;
}
if(nr==0&&max1<y) max1=y;
if(nr)
{
nr1++;
if(prim1==0) prim1=nr;
k=1;
s=0;
while (s<nr)
{
s=s+k;
k=k+4;
}
if(s==nr) q1++;
}
nr=0;
p=1;

}
for(i=1; i<=n; i++)
{
f>>x;
y=x;
while(x!=0)
{
if(x%10%2==0)
{
nr=nr+x%10*p;
p=p*10;
}
x=x/10;
}
if(nr==0&&max2<y) max2=y;
if(nr)
{
nr2++;
if(prim2==0) prim2=nr;
k=1;
s=0;
while (s<nr)
{
s=s+k;
k=k+4;
}
if(s==nr) q2++;
}
nr=0;
p=1;

}
if(P==1)
if(max1>max2) g<<max1<<’\n’;
else g<<max2<<’\n’;
else
{
if(nr1==0&&nr2==0) g<<0<<’\n’;
else
{
if(q1>q2) if(P==2) g<<1<<’\n’; else g<<q1<<’\n’;
if(q1<q2) if(P==2) g<<2<<’\n’; else g<<q2<<’\n’;
if(q1==q2)
{
if(prim1>prim2) if(P==2) g<<1<<’\n’; else g<<prim1<<’\n’;
else if(P==2) g<<2<<’\n’; else g<<prim2<<’\n’;
}
}
}

f.close();
g.close();
return 0;
}
CAPITOLUL 9. OJI 2015 9.1. CUART 111

Listing 9.1.3: cuart la.cpp


#include<fstream>

using namespace std;

int main()
{
int pp,n,nr1=0,nr2=0,p1=0,p2=0,max1=0,
nrcuart1=0,nrcuart2=0,c,y,x,p,i,k,s;

ifstream f("cuart.in");
ofstream g("cuart.out");

f>>pp>>n;

for (i=1; i<=n; i++)


{
f>>c;
x=c;
p=1;
y=0;
while (x)
{
if (x%2==1)
{
y=y+x%10*p;
p=p*10;
}
x=x/10;
}

if (y!=0)
{
nr1++;
if (nr1==1) p1=y;
s=1;
k=5;
while (s+k<=y)
{
s=s+k;
k=k+4;
}

if (s==y) nrcuart1++;
}
else if (c>max1) max1=c;
}

for (i=1; i<=n; i++)


{
f>>c;
x=c;
p=1;
y=0;
while (x)
{
if (x%2==0)
{
y=y+x%10*p;
p=p*10;
}
x=x/10;
}

if (y!=0)
{
nr2++;
if (nr2==1) p2=y;
s=1;
k=5;
while (s+k<=y)
{
s=s+k;
k=k+4;
}
CAPITOLUL 9. OJI 2015 9.1. CUART 112

if (s==y) nrcuart2++;
}
else if (c>max1) max1=c;
}

if (pp==1)
g<<max1<<’\n’;
else
if (pp==2)
{
if (nrcuart1>nrcuart2)
g<<"1\n";
else
if (nrcuart2>nrcuart1)
g<<"2\n";
else
{
if (p1>p2)
g<<"1\n";
else
if(p2>p1)
g<<"2\n";
else
g<<"0\n";
}
}
else
{
if (nrcuart1>nrcuart2)
g<<nrcuart1;
else
if (nrcuart2>nrcuart1)
g<<nrcuart2;
else
{
if (p1>p2)
g<<p1<<"\n";
else
if (p2>p1)
g<<p2<<"\n";
else
g<<"0\n";
}
}
return 0;
}

Listing 9.1.4: cuartAI.cpp


#include <fstream>
#include <math.h>

using namespace std;

ifstream f("cuart.in");
ofstream g("cuart.out");

int N,P,B,C,m1,m2,maxo,K,M,q1,q2,
primul1,primul2,k,i,x,p,q,nr1,nr2;

int main()
{
//citire-prelucrare
f>>P>>N;

//Gina
for(i=1;i<=N;i++)
{
f>>K;x=K;p=1;q=0;
while(x>0)
{
if(x%2==1){q+=p*(x%10);p*=10;}
x/=10;
}
if(q==0){if(K>maxo)maxo=K;}
CAPITOLUL 9. OJI 2015 9.1. CUART 113

else
{
nr1++;
if(primul1==0)primul1=q;
//1+5+9+...+(4M+1)=(M+1)(2M+1)
//k=M*4+1;
M=0;
while(2*M*M+3*M+1<q) M++;
if(q==(M+1)*(2*M+1)) q1++;
}
}

//Mihai
for(i=1;i<=N;i++)
{
f>>K;x=K;p=1;q=0;

while(x>0)
{
if(x%2==0){q+=p*(x%10);p*=10;}x/=10;
}

if(q==0){if(K>maxo)maxo=K;}
else
{
nr2++;
if(primul2==0)primul2=q;
//k=M*4+1;
M=0;
while(2*M*M+3*M+1<q )M++;
if(q==(M+1)*(2*M+1))q2++;
}
}

//afisare a)

if(P==1)g<<maxo<<’\n’;

//afisare b) si c)

if(q1<q2)
B=2,C=q2;
else
if(q1>q2)
B=1,C=q1;
else
if(primul1>primul2)
B=1,C=primul1;
else
if(primul1<primul2)
B=2,C=primul2;
else
B=C=0;

if(P==2)g<<B<<’\n’;
if(P==3)g<<C<<’\n’;

f.close();
g.close();
return 0;
}

Listing 9.1.5: cuartAI ecuatie.cpp


#include <fstream>
#include <math.h>

using namespace std;

ifstream f("cuart.in");
ofstream g("cuart.out");

int P,N,m1,m2,maxo,A,B,C,M,q1,q2,
primul1,primul2,k,i,x,q,p,nr1,nr2;
CAPITOLUL 9. OJI 2015 9.1. CUART 114

int main()
{
//citire-prelucrare
f>>P>>N;

//Gina
for(i=1;i<=N;i++)
{
f>>A;x=A;p=1;q=0;
while(x>0)
{
if(x%2==1)
{
q+=p*(x%10);
p*=10;
}
x/=10;
}

if(q==0)
{
if(A>maxo) maxo=A;
}
else
{
nr1++;
if(primul1==0)primul1=q;
//1+5+9+...+(4M+1)=(M+1)(2M+1)
M=(-3+sqrt(1+8*q))/4;
//k=M*4+1;
if(q==(M+1)*(2*M+1))q1++;
}
}

//Mihai
for(i=1;i<=N;i++)
{
f>>A; x=A; p=1; q=0;
while(x>0)
{
if(x%2==0)
{
q+=p*(x%10);
p*=10;
}
x/=10;
}

if(q==0){if(A>maxo)maxo=A;}
else
{
nr2++;
if(primul2==0)primul2=q;
M=(-3+sqrt(1+8*q))/4;
//k=M*4+1;
if(q==(M+1)*(2*M+1))q2++;
}
}

//afisare a)
if(P==1)g<<maxo<<’\n’;

//afisare b) si c)
if(q1<q2) B=2,C=q2;
else if(q1>q2) B=1,C=q1;
else if(primul1>primul2)B=1,C=primul1;
else if(primul1<primul2)B=2,C=primul2;
else B=C=0;

if(P==2)g<<B<<’\n’;
if(P==3)g<<C<<’\n’;

f.close();
g.close();
return 0;
}
CAPITOLUL 9. OJI 2015 9.2. SPECIALE 115

9.1.3 *Rezolvare detaliată

9.2 speciale
Problema 2 - speciale 100 de puncte
Maria a aflat că numerele naturale care ı̂ncep cu cifra 1 şi au toate cifrele ordonate strict
crescător şi consecutive sau ı̂ncep cu cifra 9 şi au toate cifrele ordonate strict descrescător şi
consecutive se numesc numere speciale. Interesată să descopere legătura dintre numerele speciale
cu acelaşi număr de cifre, a observat că poate construi tabelul alăturat.

Figura 9.2: speciale

Cerinţe

Scrieţi un program care citind patru numere naturale K, N , A şi B determină:


1) cel mai mare număr special situat ı̂n tabel pe linia K;
2) numărul special obţinut din numărul N prin ştergerea unei cifre;
3) numărul de numere speciale din mulţimea {A , A  1, A  2, A  3, ..., B  1, B}.

Date de intrare

Fişierul de intrare speciale.in conţine pe prima linie un număr natural P . Pentru toate testele
de intrare, numărul P poate avea doar valoarea 1, valoarea 2 sau valoarea 3. Pe a doua linie a
fişierului speciale.in se găsesc, ı̂n această ordine, numerele naturale K, N , A şi B, separate prin
câte un spaţiu.

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 speciale.out va conţine pe prima linie un număr natural reprezentând cel mai mare număr
special situat ı̂n tabel pe linia K.
Dacă valoarea lui P este 2, se va rezolva numai punctul 2) din cerinţe. În acest caz, fişierul
de ieşire speciale.out va conţine pe prima linie un număr natural reprezentând numărul special
obţinut din numărul N prin ştergerea unei cifre sau 0 dacă un astfel de număr nu se poate obţine;
Dacă valoarea lui P este 3, se va rezolva numai punctul 3) din cerinţe. În acest caz, fişierul de
ieşire speciale.out va conţine pe prima linie un număr natural reprezentând numărul de numere
speciale din mulţimea {A, A  1, A  2, A  3, ..., B  1, B}.

Restricţii şi precizări

a 1&K&9
a 1 & N & 999999999
a 1 & A & B & 999999999
a Pentru rezolvarea corectă a primei cerinţe se acordă 20 de puncte, pentru rezolvarea corectă
a celei de a doua cerinţe se acordă 40 de puncte, pentru rezolvarea corectă a celei de a treia cerinţe
se acordă 40 de puncte.
CAPITOLUL 9. OJI 2015 9.2. SPECIALE 116

Exemple

speciale.in speciale.out Explicaţii


13 125345 320 888888 987 P = 1, pentru acest test, se rezolva cerinţa 1).
Numerele speciale de pe linia a treia a tabelului sunt 123 şi 987,
cel mai mare fiind 987.
23 125345 320 888888 12345 P = 2, pentru acest test, se rezolva cerinţa 2).
Ştergând cifra 5 aflată pe poziţia a treia ı̂n 125345 se obţine
numărul special 12345.
33 125345 320 888888 6 P = 3, pentru acest test, se rezolva cerinţa 3).
Sunt 6 numere speciale ı̂n mulţimea {320, 321,..., 888888} şi
anume 987, 1234, 9876, 12345, 98765, 123456.

Timp maxim de executare/test: 0.5 secunde


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

9.2.1 Indicaţii de rezolvare

Cerinta 1
Se formeaza numarul special care incepe cu cifra 9 si contine k cifre cu ajutorul unei structuri
repetitive.
Cerinta 2
O solutie posibila: numaram cifrele numarului N (nr); construim numarul special cu un numar
de cifre egal cu nr  1; comparam cifrele numarului N cu cifrele numarului special construit (cifra
cu cifra de la dreapta la stanga); daca toate sunt egale (pe aceeasi pozitie) si numai una difera,
atunci afisam numarul special construit, altfel afisam valoarea 0.
Cerinta 3
O solutie posibila: Calculam cate cifre are numrul A. Construim numerele speciale care
sa contina tot atatea cifre cate contine numarul A. Comparam valoarea numerelor speciale cu
valoarea numarului A si B iar apoi construim prin adaugare de cifre crescatore/descrescatore
urmatoarele numere speciale pana cand ajungem la valoarea numarului B.

9.2.2 Cod sursă

Listing 9.2.1: speciale dc.cpp


#include <fstream>

using namespace std;

ifstream fin("speciale.in");
ofstream fout("speciale.out");

int main()
{
unsigned P,N,K,A,B,x,special,i,p,NN,Ncif;

x=special=Ncif=0;

fin>>P>>K>>N>>A>>B; NN=N;

if(P==1)
{
for(i=9;i>=10-K;i--) fout<<i;
fout<<’\n’;
return 0;
}

if(P==2)
{
CAPITOLUL 9. OJI 2015 9.2. SPECIALE 117

///cerinta 2
while(NN)
{
NN/=10;
special=special*10+Ncif;
Ncif++;
}

if(N%10==Ncif-1||N/10%10==Ncif-1)///verific daca N este de forma 1234...


{
NN=N;i=Ncif-1;p=1;
while(NN)
{
if(NN%10!=i)
{
if(N/(p*10)*p+N%p==special) x=special;
break;
}
else {i--;p*=10;NN/=10;}
}
if(NN==0)x=special;
}

//verific daca N este de forma 987...


if(x==0&&(N%10==11-Ncif||N/10%10==11-Ncif))
{
NN=N;i=11-Ncif;p=1;
while(NN)
{
if(NN%10!=i)
{
if(N/(p*10)*p+N%p==special*8+Ncif-1)
x=special*8+Ncif-1;
break;
}
else {i++;p*=10;NN/=10;}
}
if(NN==0) x=special*8+Ncif-1;
}
fout<<x<<’\n’;
return 0;
}

if(P==3)
{

///cerinta 3
for(x=special=0,i=1;special<=B;i++)
{
special=special*10+i;
if(special>=A&&special<=B) x++;
if(special*8+i>=A&&special*8+i<=B) x++;
}
fout<<x<<’\n’;
return 0;
}
return 0;
}

Listing 9.2.2: speciale fin dt.cpp


#include <fstream>

using namespace std;

ifstream f("speciale.in");
ofstream g("speciale.out");

int main()
{
int k,n,a,b,x=0,i,pr,nr=0,nr1=0,p1,fin_nr,ok=0,nr2,p;
f>>p>>k>>n>>a>>b;

if(p==1)
{
CAPITOLUL 9. OJI 2015 9.2. SPECIALE 118

x=0;
for(i=9;i>9-k;i--)
x=i+x*10;
g<<x<<’\n’;
}

//cerinta 2
if(p==2)
{
pr=n;
while(pr)
{
pr=pr/10;
nr++;
}

nr--;
for(i=1;i<=nr;i++)
nr1=i+nr1*10;
p1=0;
pr=n;
fin_nr=nr1;

while(pr)
{
if(pr%10==nr1%10) {pr=pr/10;nr1=nr1/10;}
else {p1++;pr=pr/10;}
}

if(p1==1) {g<<fin_nr<<’\n’;ok=1;}
else
{
nr1=0;
for(i=9;i>9-nr;i--)
nr1=i+nr1*10;

p1=0;
pr=n;
fin_nr=nr1;

while(pr)
{
if(pr%10==nr1%10) {pr=pr/10;nr1=nr1/10;}
else {p1++;pr=pr/10;}
}

if(p1==1) {g<<fin_nr<<’\n’;ok=1;}
}
if(ok==0) g<<0<<’\n’;
}

//cerinta 3
if(p==3)
{
nr=0;
pr=a;
nr1=0;

while(pr){pr=pr/10;nr++;}

for(i=1;i<=nr;i++)
nr1=i+nr1*10;

nr2=0;
for(i=9;i>9-nr;i--)
nr2=i+nr2*10;

x=0;
if(nr1>=a) x++;
if(nr2>=a&&nr2<=b) x++;
nr++;
pr=nr2%10-1;
while(nr2<b && nr1<b)
{
nr2=nr2*10+pr;
nr1=nr1*10+nr;
CAPITOLUL 9. OJI 2015 9.2. SPECIALE 119

nr++;pr--;
if(nr1<=b) x++;
if(nr2<=b) x++;
}
g<<x<<’\n’;
}

f.close();
g.close();
return 0;
}

Listing 9.2.3: speciale SJ.cpp


#include <iostream>
#include <fstream>

using namespace std;

ifstream in("speciale.in");
ofstream out("speciale.out");

int main()
{
int P,k,n,A,B,m,nr=0,nrm=0,mr=0,i,l,sw1,sw2;
in>>P;

in>>k>>n>>A>>B;

if(P==1)
{
//a
for(i=1;i<=k;i++)
nrm=nrm*10+10-i;
out<<nrm<<’\n’;
}
else
if(P==2)
{
//b
nr=0;
m=n,l=0;
while(m)
l++,m/=10;

for(i=1;i<l;i++)
nr=nr*10+i;

mr=nr,sw1=0,m=n;
while(n)
{
if(n%10!=nr%10)
n/=10, sw1++;
else
n/=10,nr/=10;
}

n=m;
if(sw1==1&&nr==0)
out<<mr<<’\n’;
else
if(sw1==0 && n/10==0)
out<<mr<<’\n’;
else
{
nr=0;
for(i=9;i>10-l;i--)
nr=nr*10+i;

mr=nr,sw2=0,m=n;
while(n)
{
if(n%10!=nr%10)
n/=10, sw2++;
else
CAPITOLUL 9. OJI 2015 9.2. SPECIALE 120

n/=10,nr/=10;
}

if(sw2==1&&n==0)
out<<mr<<’\n’;
else
if(sw2==0 && n/10==0)
out<<mr<<’\n’;

if(sw1!=1 && sw2!=1)


out<<0<<’\n’;
}
}
else
{
//c
m=A,l=0,nr=0,k=0;

while(m)
l++,m/=10;

for(i=1;i<=l;i++)
nr=nr*10+i;

if(nr<A)
{
m=nr*8+l;
if(m>=A && m<=B)
k++;
l++, nr=nr*10+l;
}

i=l;
while(nr>=A && nr<=B)
{
k++;
if(nr*8+i>=A && nr*8+i<=B)
k++;
i++;
nr=nr*10+i;
}

out<<k;
}
return 0;
}

Listing 9.2.4: specialedl.cpp


#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cassert>

#define MRD 999999999

using namespace std;

int K, N, A, P, B, N1, N2, Nr, Na1, Na2, Special, i, p, x, d, u, nr;


bool ok;

int main()
{
freopen("speciale.in", "r",stdin);
freopen("speciale.out","w",stdout);

scanf("%d\n",&P);
scanf("%d%d%d%d",&K, &N, &A, &B);

assert(P>0 && P<=3 && K<10 && K>0 && N<=MRD && A<=MRD &&
B<=MRD && N>0 && A>0 && B>0 && A<=B);

if(P==1)
{
for(int i=1; i<=K; i++)
CAPITOLUL 9. OJI 2015 9.2. SPECIALE 121

N2=N2*10 + 10 - i;
printf("%d\n", N2);
}
else
if(P==2)
{
p = 1;
Special=0;
while(N/p>0 && !Special)
{
Nr=N/(p*10)*p + N%p;
int cn=Nr;

while(cn>9) cn/=10;

if(Nr==1 ||Nr == 9)
Special = Nr;
else
{
d=(cn==9? 1: -1);
u=Nr%10;

ok=true;
while (Nr>0)
{
if ( u != Nr % 10 ) ok=false;
Nr/=10; u += d;
}

if (ok && (d==1 && u==10 || d==-1 && u==0))


Special=N/(p*10)*p + N%p;
}

p*=10;
}

printf("%d\n", Special);
}
else
{
Na1=Na2=nr=0;
for(int i=1; i<=9 ; i++ )
{
Na1=Na1*10 + i;
if(Na1>=A&&Na1<=B ) nr++;
Na2=Na2*10 + 10 - i;
if(Na2>=A&&Na2<=B) nr++;
}

printf("%d\n", nr);
}
return 0;
}

9.2.3 *Rezolvare detaliată


Capitolul 10

OJI 2014

10.1 martisoare
Problema 1 - martisoare 100 de puncte
Gică şi Lică lucrează la o fabrică de jucării, ı̂n schimburi diferite. Anul acesta patronul fabricii
a hotărât să confecţioneze şi mărţişoare. Mărţişoarele gata confecţionate sunt puse ı̂n cutii nu-
merotate consecutiv.
Cutiile sunt aranjate ı̂n ordinea strict crescătoare şi consecutivă a numerelor de pe acestea.
Gică trebuie să ia, ı̂n ordine, fiecare cutie, să lege la fiecare mărţişor câte un şnur alb-roşu şi
apoi să le pună la loc ı̂n cutie.
În fiecare schimb, Gică scrie pe o tablă magnetică, utilizând cifre magnetice, ı̂n ordine strict
crescătoare, numerele cutiilor pentru care a legat şnururi la mărţişoare.
Când se termină schimbul lui Gică, Lică, care lucrează ı̂n schimbul următor, vine şi ambalează
cutiile cu numerele de pe tablă şi le trimite la magazine. Totul merge ca pe roate, până ı̂ntr-o zi,
când, două cifre de pe tablă se demagnetizează şi cad, rămânând două locuri goale. Lică observă
acest lucru, le ia de jos şi le pune la ı̂ntâmplare pe tablă, ı̂n cele două locuri goale. Singurul lucru
de care ţine cont este acela că cifra 0 nu poate fi prima cifră a unui număr.

Figura 10.1: martişoare

Cerinţe
Scrieţi un program care să citească numerele naturale N (reprezentând numărul de numere
scrise pe tablă) şi c1 , c2 , ..., cN (reprezentând numerele scrise, ı̂n ordine, pe tablă, după ce Lică a
completat cele două locuri goale cu cifrele căzute) şi care să determine:
a) cele două cifre care au fost schimbate ı̂ntre ele, dacă, după ce au completat locurile goale,
acestea au schimbat şirul numerelor scrise de Gică;
b) numărul maxim scris pe tablă de Gică.
Date de intrare
Fişierul de intrare martisoare.in conţine pe prima linie numărul natural N reprezentând
numărul de numere de pe tablă. A doua linie a fişierului conţine, ı̂n ordine, cele N numere
c1 , c2 , ..., cN , separate prin câte un spaţiu, reprezentând, ı̂n ordine, numerele existente pe tablă,
după ce Lică a completat cele două locuri libere cu cifrele căzute.
Date de ieşire
Fişierul de ieşire martisoare.out va conţine pe prima linie două cifre, ı̂n ordine crescătoare,
separate printr-un spaţiu, reprezentând cele două cifre care au fost schimbate ı̂ntre ele sau 0 0
ı̂n cazul ı̂n care cele două cifre magnetice căzute, după ce au fost puse ı̂napoi pe tablă, nu au
schimbat şirul numerelor scrise de Gică. A doua linie va conţine un număr reprezentând numărul
maxim din secvenţa de numere consecutive scrisă de Gică pe tablă.

122
CAPITOLUL 10. OJI 2014 10.1. MARTISOARE 123

Restricţii şi precizări

a 4 & N & 100000


a 1 & ci & 100000, (1 & i & N )
a N , c1 , c2 , ..., cN sunt numere naturale;
a cele două cifre care cad de pe tablă pot proveni din acelaşi număr;
a Pentru rezolvarea cerinţei a) se acordă 60% din punctaj, iar pentru cerinţa b) se acordă 40%
din punctaj.

Exemple
martisoare.in martisoare.out Explicaţii
5 2 629 Gică a scris pe tablă, ı̂n ordine, numerele: 25 26 27 28 29.
65 22 27 28 29 Au fost schimbate ı̂ntre ele cifra 2 din primul număr şi cifra
6 din al doilea număr. Cel mai mare număr scris de Gică pe
tablă este 29. .
4 8 998 Gică a scris pe tablă, ı̂n ordine, numerele: 95 96 97 98 Au
95 96 97 89 fost schimbate ı̂ntre ele cifrele ultimului număr. Cel mai mare
număr scris de Gică pe tablă este 98.
5 0 039 Gică a scris pe tablă, ı̂n ordine, numerele: 35 36 37 38 39
35 36 37 38 39 şirul numerelor nu a fost schimbat, cel mai mare număr fiind
39.

Timp maxim de executare/test: 0.5 secunde


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

10.1.1 Indicaţii de rezolvare

Solutie - complexitate O(N) - prof. Ana Intuneric


Solutia se bazeaza pe observatia ca este suficient sa determinam primul numar modificat.
Sunt doua cazuri clare
a) primele doua numere sunt nemodificate, caz in care se calculeaza imediat numarul maxim
si se cauta primul numar modificat comparand cifrele sale cu cifrele numarului care trebuia sa fie
pe respectiva pozitie in fisier
b) unul dintre primele doua numere sau amandoua sunt modificate. In acest caz se citesc doar
primele 4 numere si se trateaza combinatiile posibile de numere modificate

10.1.2 Cod sursă

Listing 10.1.1: mAna.cpp


// sursa oficiala - prof.Ana Intuneric
#include <fstream>

using namespace std;

ifstream f("martisoare.in");
ofstream g("martisoare.out");

int N,i,c1,c2,c3,c4,x,y,maxi,gasit;

int main()
{
f>>N;
f>>c1>>c2;

//caut primul numar modificat


if(c2-c1==1)
{
maxi=c1+N-1;
for(i=3;i<=N && !gasit;i++)
{
f>>c3;
CAPITOLUL 10. OJI 2014 10.1. MARTISOARE 124

if(c3-c2!=1)
{
x=c2+1;y=c3;gasit=1;
while(x!=0 && y!=0)
{
if(x%10!=y%10)
{
if(x%10<y%10)
g<<x%10<<’ ’<<y%10<<endl;
else
g<<y%10<<’ ’<<x%10<<endl;
break;
}
else
x/=10,y/=10;
}
}
else
c2=c3;
}
}
else
{
f>>c3>>c4;

//c1 modificat
if(c3-c2==1)
{
x=c2-1;
y=c1;
gasit=1;
maxi=c2+N-2;
}
else
if(c4-c2==2)
{
x=c2-1;
y=c1;
gasit=1;
maxi=c4+N-4;
}
//c2 este modificat
else
if(c4-c3==1)
{
x=c2;
y=c3-1;
gasit=1;
maxi=c3+N-3;
}
else
if(c3-c1==2)
{
x=c2;
y=c3-1;
gasit=1;
maxi=c3+N-3;
}//c2 modificat si c3 este bun
else
{
x=c2;
y=c4-2;
gasit=1;
maxi=c4+N-4;
}//c2 modificat si c4 este bun

while(x!=0 && y!=0)


{
if(x%10!=y%10)
{
if(x%10<y%10)
g<<x%10<<’ ’<<y%10<<endl;
else
g<<y%10<<’ ’<<x%10<<endl;break;
}
else
CAPITOLUL 10. OJI 2014 10.1. MARTISOARE 125

x/=10,y/=10;
}
}

if(!gasit)
g<<"0 0\n";

g<<maxi<<endl;

f.close();
g.close();
return 0;
}

Listing 10.1.2: mCarmen.cpp


#include <iostream>
#include <fstream>

using namespace std;

ifstream f("martisoare.in");
ofstream g("martisoare.out");

int v[100001];

int main()
{
int i,x,k=1,y,n, a=0,b=0;
f>>n>>x;

v[1]=x; y=x;
for(i=2;i<=n;i++)
{
f>>v[i];
x=max(x,v[i]);
y=min(y,v[i]);
}

if(y+n-1==x)
{
for(i=1; i<=n;i++,y++)
if(v[i]!=y)
{
a=v[i];
b=y;
break;
}
}
else
{ int i=1;
if(v[1]!=y && v[2]==y)
{
if(v[3]==y+1)
{
a=v[1];
b=y-1;
x=b+n-1;
}
else
{
x=v[3]+n-3;
a=v[3]-1;
b=y;
}
}
else
{
i=2;
while(y+1==v[i] && i<=n)
{
i++;
y++;
}
CAPITOLUL 10. OJI 2014 10.1. MARTISOARE 126

a=v[i];
b=y+1;
x=y+(n-i+1);
}
}

if(a*b)
{
while(a%10==b%10)
{
a=a/10; b=b/10;
}

a=a%10;
b=b%10;
if(a>b) swap(a,b);
}

g<<a<<" "<<b<<endl<<x<<endl;

return 0;
}

Listing 10.1.3: mCristina.cpp


//martisoare - Cristina Sichim
#include <fstream>
using namespace std;

ifstream f("martisoare.in");
ofstream g("martisoare.out");

int n,a,b,c,d,u;

void cifre(int b, int c)


{
while(b%10==c%10)
b/=10,c/=10;

(b%10 < c%10) ? g<<b%10<<’ ’<<c%10<<’\n’ : g<< c%10<<’ ’<<b%10<<’\n’;


}

int main()
{
f>>n>>a>>b>>c;
if(a+1==b && b+1==c)
{
u=a+n-1; n-=3;
while(n && b+1==c)
f>>c,++b,--n;
if(b+1!=c)
cifre(b+1,c), g<<u<<’\n’;
else
g<<"0 0\n"<<u<<’\n’;
}
else // cifre schimbate in primele 3 numere
if(a+1==b)
cifre(b+1,c), g<<a+n-1<<’\n’;
else
if(b+1==c)
cifre(a,b-1), g<<b+n-2<<’\n’;
else
if(a+2==c)
cifre(a+1,b), g<<a+n-1<<’\n’;
else
{
f>>d;
if(a+3==d)
cifre(a+1,b), g<<a+n-1<<’\n’;
else
if(b+2==d)
cifre(a,b-1), g<<b+n-2<<’\n’;
else
cifre(b,c-1), g<<c+n-3<<’\n’;
}
CAPITOLUL 10. OJI 2014 10.1. MARTISOARE 127

f.close();
g.close();

return 0;
}

Listing 10.1.4: mMarilena.cpp


#include <fstream>

using namespace std;

ifstream f("martisoare.in");
ifstream g("martisoare.in");
ofstream h("martisoare.out");

int n,vmin,vmax,t,x,x1,y,y1,a,b,c,d,i,poz;

int main()
{
f>>n>>a>>b>>c>>d;

// gasesc primul numar corect din sir si


// calculez extremitatile sirului [vmin, vmax]

if(b-a==1){vmin=a; vmax=a+n-1;}
else
if(c-b==1){vmin=b-1; vmax=b+n-2;}
else
if(d-c==1){vmin=c-2; vmax=c+n-3;}
else
if(c-a==2){vmin=a; vmax=a+n-1;}
else
if(d-b==2){vmin=b-1; vmax=b+n-2;}
else
if(d-a==3){vmin=a; vmax=a+n-1;}

f.close();

// caut cele 2 numere gresite


g>>n;
x=x1=vmin;
t=0;
for(i=1;i<=n;i++)
{
x=x1;
g>>y;
if(x!=y)
{
while(x!=0 && y!=0) //caut cifrele incurcate
{
if (x%10!=y%10)
{
t++;
if(t==1) a=x%10;
else b=x%10;
}

x=x/10;y=y/10;
}
}

if (t==2) i=n;
x1++;
}

if(t==0) h<<0<<’ ’<<0<<endl<<vmax;


else
{
if(a>b){t=a ;a=b; b=t;}
h<<a<<’ ’<<b<<endl<<vmax;
}

g.close();
CAPITOLUL 10. OJI 2014 10.1. MARTISOARE 128

h.close();

return 0;
}

Listing 10.1.5: mRaluca.cpp


#include <fstream>

using namespace std;

ifstream f("martisoare.in");
ofstream g("martisoare.out");

int main()
{
int v[4], n, i, max=0, r, c, x, j, nr1=0,
p1, nr2=0, p2, nr, c1=0, c2=0, cc;

f>>n;
for(i=0;i<4;i++)
f>>v[i];

for(i=0; i<3; i++)


{
x=v[i]-i;c=1;
for(j=i+1;j<4; j++)
if(v[j]-j==x)c++;
if(c>max) max=c, r=x;
}

for(i=0;i<4;i++)
if(v[i]-i!=r)
if(nr1==0) nr1=v[i], p1=i;
else
if(nr2==0) nr2=v[i],p2=i;

for(i=4;i<n and nr2==0; i++)


{
f>>nr;
if(nr-i!=r)
if(nr1==0) nr1=nr, p1=i;
else
if(nr2==0) nr2=nr,p2=i;
}

if(nr1)
{
x=r+p1;
while(nr1)
{
c=nr1%10;
cc=x%10;
if(c!=cc)
if(c<cc) c1=c, c2=cc;
else c1=cc, c2=c;
nr1/=10;
x/=10;
}
}

g<<c1<<’ ’<<c2<<’\n’<<r+n-1<<’\n’;

f.close();
g.close();

return 0;
}

10.1.3 *Rezolvare detaliată


CAPITOLUL 10. OJI 2014 10.2. PIRAMIDE 129

10.2 piramide
Problema 2 - piramide 100 de puncte
Fascinat de Egiptul Antic, Rareş vrea să construiască cât mai multe piramide din cartonaşe
pătratice identice. El are la dispoziţie N cartonaşe numerotate de la 1 la N , albe sau gri, aşezate
ı̂n ordinea strict crescătoare a numerelor.
a Prima piramidă o va construi folosind primele trei cartonaşe. Baza piramidei va fi formată
din cartonaşele 1 şi 2 aşezate alăturat, peste care va aşeza cartonaşul 3 (vârful piramidei).
a A doua piramidă va avea baza formată din cartonaşele 4, 5 şi 6 aşezate alăturat, deasupra
cărora se vor aşeza cartonaşele 7 şi 8, alăturate, peste care se va aşeza cartonaşul 9 (vârful
piramidei).
a Mai departe, va construi ı̂n ordine piramidele complete cu bazele formate din 4 cartonaşe
(cu numerele de la 10 la 13), respectiv 5 cartonaşe (cu numerele de la 20 la 24), 6 cartonaşe (cu
numerele de la 35 la 40) etc., cât timp va putea construi o piramidă completă. De exemplu, dacă
Rareş are N 75 cartonaşe atunci el va construi piramidele complete 1, 2, 3, 4 şi 5 din imaginile
următoare. Din cele 75 de cartonaşe el va folosi doar primele 55 de cartonaşe, deoarece ultimele
20 cartonaşe nu sunt suficiente pentru a construi piramida 6, cu baza formată din 7 cartonaşe.

Figura 10.2: Piramide

Cerinţe

Scrieţi un program care să citească numerele naturale N (reprezentând numărul de cartonaşe),
X (reprezentând numărul unui cartonaş), K (reprezentând numărul de cartonaşe albe), numerele
celor K cartonaşe albe c1 , c2 , ..., cK şi care să determine: a) numărul P al piramidei complete
ce conţine cartonaşul numerotat cu X; b) numărul M maxim de piramide complete construite
de Rareş; c) numărul C de cartonaşe nefolosite; d) numărul A al primei piramide complete care
conţine cele mai multe cartonaşe albe.

Date de intrare

Fişierul de intrare piramide.in conţine pe prima linie cele trei numere N , X şi K, separate
prin câte un spaţiu, cu semnificaţia din enunţ. A doua linie a fişierului conţine, ı̂n ordine, cele K
numere c1 , c2 , ..., cK , separate prin câte un spaţiu, reprezentând numerele celor K cartonaşe albe
din cele N .

Date de ieşire

Fişierul de ieşire piramide.out va conţine pe prima linie numărul P sau valoarea 0 (zero)
dacă niciuna dintre piramidele complete construite nu conţine cartonaşul cu numărul X. A doua
linie a fişierului va conţine numărul M . Cea de-a treia linie va conţine numărul C. Cea de-a
patra linie va conţine numărul A sau valoarea 0 (zero) dacă nicio piramidă completă nu conţine
cel puţin un cartonaş alb.

Restricţii şi precizări

a N, X, K, c1 , c2 , ..., cK , P, M, A sunt numere naturale nenule.


a 3 & N & 100000; 1 & X & N ; 1 & K & N ; 1 & c1 $ c2 $ ... $ cK & N
a O piramidă completă cu baza formată din b cartonaşe se construieşte prin aşezarea car-
tonaşelor necesare pe b rânduri: b cartonaşe pe primul rând (al bazei), apoi b  1 cartonaşe pe
rândul al doilea, b  2 pe rândul al treilea, ..., două cartonaşe pe rândul b  1 şi un cartonaş (vârful
piramidei) pe rândul b.
a Pentru rezolvarea cerinţei a) se acordă 20% din punctaj, pentru cerinţa b) 20% din punctaj,
pentru cerinţa c) 20% din punctaj şi pentru cerinţa d) 40% din punctaj.
CAPITOLUL 10. OJI 2014 10.2. PIRAMIDE 130

Exemple
piramide.in piramide.out
75 15 23 3
5 9 11 18 20 21 25 27 28 30 35 37 45 46 51 55 60 65 68 69 70 71 72 5
20
4
Explicaţie: Piramida 3 (P=3) construită conţine cartonaşul cu numărul X 15. Rareş poate
construi doar M 5 piramide complete, rămânând nefolosite 20 cartonaşe (C 20) insuficiente
pentru construirea piramidei 6. Numărul maxim de cartonaşe albe dintr-o piramidă completă
este egal cu 6. Piramidele 4 şi 5 conţin fiecare un număr maxim de cartonaşe albe (6), prima
dintre acestea fiind piramida 4 (A 4). Ultimele 7 cartonaşe albe (cu numerele: 60, 65, 68, 69,
70, 71, 72) nu sunt folosite ı̂n construirea piramidelor complete.

Timp maxim de executare/test: 0.5 secunde


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

10.2.1 Indicaţii de rezolvare

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

O soluţie posibilă se poate obţine fără a utiliza tablouri unidimensionale, prin citirea succesivă
a datelor din fişier combinată cu prelucrarea acestora.
Se observă că pentru construirea piramidei complete care are baza formata din b cartonaşe
sunt necesare: CB b  b  1  b  2  ...  3  2  1 b b  1©2
Simulăm construirea numărului maxim M de piramide complete folosind cele N cartonaşe.
Se citeşte numărul CA al primului cartonaş alb din fişier.
Pornind de la prima piramidă (cea cu baza b 2), construim celelalte piramide cât timp avem
cartonaşe nefolosite suficiente şi numărul cartonaşelor folosite ı̂n construirea acestora este mai mic
ca CA.
Numărăm piramida completă curentă şi verificăm apartenenţa cartonaşului X la piramida
curentă folosindu-ne de numărul primului, respectiv ultimului, cartonaş din piramidă.
La găsirea primei piramide ce conţine cartonaşul alb CA, citim din fişierul de intrare numerele
următoarelor cartonaşe albe cţt timp numerele acestora sunt mai mici sau egale cu numărul
cartonaşului vţrf din piramida curentă. La finalul acestei operaţii vom dispune de numărul car-
tonaşelor albe din piramida curentă. Se compară acest număr cu cel maxim obţinut pţnă ı̂n acest
moment. Se actualizează acest maxim dacă s-a obţinut o valoare mai mare memorţndu-se şi
numărul piramidei curente.
Se trece la ”construirea” următoarei piramide, cu baza b  1 dacă avem suficiente cartonaşe
nefolosite, altfel se ı̂ncheie procesul de construire a piramidei.

10.2.2 Cod sursă

Listing 10.2.1: p s CM.cpp


//sursa oficiala - prof. Carmen Minca - C.N.I.T.Vianu- Bucuresti

#include <fstream>

using namespace std;

/*a) numarul P al piramidei ce c o n i n e cartonasul numerotat cu X;


b) numarul M maxim de piramide construite de Gigel;
c) numarul C de c a r t o n a e nefolosite;
d) numarul A al primei piramide care contine cele mai multe c a r t o n a e albe.
*/

int n, x, k;

ifstream f("piramide.in");
CAPITOLUL 10. OJI 2014 10.2. PIRAMIDE 131

ofstream g("piramide.out");

int main()
{
int p=0, a=0, m=0, c=0,i,ca,b=1,cfol=0,cp,nra, maxnra=0;
f>>n>>x>>k;
i=1;
f>>ca;
do //caut piramida ce contine cartonasul alb cu numarul ca
{ b++;//nr cartonase din baza piramida curenta
nra=0;//caut in piramida curenta cartonasele albe
cp=b*(b+1)/2; //nr cartonase din care e formata piramida curenta

if(cp+cfol<=n) //daca am cele cp cartoane atunci pot construi piramida


{ m++; //numar piramida construita

if(cfol<x && x<=cp+cfol) p=m; //verif daca contine cartonasul x


cfol+=cp;

while(ca<=cfol && i<=k)


{ nra++;f>>ca;i++;} //numar cartonasele albe din piramida

if(nra>maxnra)
{ a=m; maxnra=nra; }
}
else break;
} while (cfol<n);
c=n-cfol;
g<<p<<endl<<m<<endl<<c<<endl<<a<<endl;
return 0;
}

Listing 10.2.2: p v CM.cpp


//prof.Carmen Minca C.N.I.T.Vianu - Bucuresti

#include <fstream>

using namespace std;

/*a) numarul P al piramidei ce c o n i n e cartonasul numerotat cu X;


b) numarul M maxim de piramide construite de Gigel;
c) numarul C de c a r t o n a e nefolosite;
d) numarul A al primei piramide care contine cele mai multe c a r t o n a e albe.
*/

int n, x, k, cart[100];

ifstream f("piramide.in");
ofstream g("piramide.out");

int main()
{
int p=0, a=0, m=0, c,i,ca,b,nra, maxnra=0,j;
f>>n>>x>>k;
b=1;
cart[1]=3;
m=0; b++;
while(cart[m]+b*(b+1)/2<=n)
{
m++;
cart[m]=b*(b+1)/2+cart[m-1];
b++;
if(x>cart[m-1] && x<=cart[m])p=m;
}

c=n-cart[m]; j=1;
i=1; f>>ca;

while(i<=k && j<=m)


{
while(ca>cart[j] && j<=m) j++;
if(j<=m)
{
nra=0;
CAPITOLUL 10. OJI 2014 10.2. PIRAMIDE 132

while(ca<=cart[j] && i<=k)


{
nra++; f>>ca; i++;
}
if(nra>maxnra){a=j; maxnra=nra;}
}
}

g<<p<<endl<<m<<endl<<c<<endl<<a;

return 0;
}

Listing 10.2.3: pAna.cpp


#include <fstream>
using namespace std;

ifstream f("piramide.in");
ofstream g("piramide.out");

int N,X,K,i,ls,ld,P,nrpc,nrc,nrca,maxca,nrpmax,c,S,nr;

int main()
{
//citire
f>>N>>X>>K;

//a)
ls=1;ld=3;nrpc=1;
while(X>ld){nrpc++;ls=ld+1;ld+=(nrpc+1)*(nrpc+2)/2;}
if(N>=ld)g<<nrpc<<endl;
else g<<0<<endl;

//b)
S=0;nrpc=0;nr=1;
while(N>S){nrpc++;nr++;S+=nr*(nr+1)/2;}
if(N<S){S-=nr*(nr+1)/2;nrpc--;}
g<<nrpc<<endl;

//c)
g<<N-S<<endl;

//d)
ls=1;ld=3;nrpc=1;nrc=3;
f>>c;K--;//cartonasul alb curent
do
{
while(c>ld)
{
nrpc++;ls=ld+1;ld+=(nrpc+1)*(nrpc+2)/2;nrca=0;
}
nrca++;f>>c;K--;if(K==0)nrca++;
if(nrca>maxca && ld<=N){maxca=nrca;nrpmax=nrpc;}
}
while(K>0);

//afisare
g<<nrpmax<<endl;

f.close();
g.close();
return 0;
}

Listing 10.2.4: pCristina.cpp


//piramide - Cristina Sichim

#include <fstream>
using namespace std;

ifstream f("piramide.in");
CAPITOLUL 10. OJI 2014 10.2. PIRAMIDE 133

ofstream g("piramide.out");

int n,x,k,p=1,l=2,amax,a,y,pmax=1,prim=1,ultim=3,px;

int main()
{ f>>n>>x>>k>>y;

while(ultim<=n)
{ if(x>=prim && x<=ultim)px=p;

while(k && y>=prim && y<=ultim) {a++,k--;if(k)f>>y;}

if(a>amax) amax=a,pmax=p;

++p;++l;a=0;
prim=ultim+1; ultim+=l*(l+1)/2;
}

if(n<ultim)p--,ultim=prim-1;

g<<px<<’\n’<<p<<’\n’<<n-ultim<<’\n’;

if(amax) g<<pmax<<’\n’;else g<<"0\n";

f.close();
g.close();
return 0;
}

Listing 10.2.5: pGina.cpp


#include <fstream>

using namespace std;

ifstream f("piramide.in");
ofstream g("piramide.out");

long N,X,K,c,k,S,i,A,maxa,P,M,piramida,nca,C;

int main()
{ f>>N>>X>>K;k=1;

while(S<=N)
{ if(P==0 && X<S) P=k-1;
S+=(k+1)*(k+2)/2; k++;
}

g<<P<<endl;

k--;
S=S-(k+1)*(k+2)/2;
k=k-1; C=N-S;

g<<k<<endl<<C<<endl;
// g<<S<<" k="<<k<<" "<<M<<endl;

maxa=0;A=0;nca=0;piramida=0;long cf=N-C;S=0;k=1;
for(i=1;i<=N;i++)
{
f>>c;
if(S>=c) nca++;
else
{ if(maxa<nca){maxa=nca;A=k-1;}

while(S<=cf && S<=c)


{ S+=(k+1)*(k+2)/2; k++;}

if(c<=S) nca=1; else nca=0;


}
}

g<<A<<endl;

return 0;
CAPITOLUL 10. OJI 2014 10.2. PIRAMIDE 134

Listing 10.2.6: pMarilena.cpp


#include <fstream>

using namespace std;

int N,K,S,S1,c,nr,ok,pmax,ppmax,vmin,vmax,np,nrc,i,ok1,x;

ifstream f("piramide.in");
ofstream g("piramide.out");

int main()
{
f>>N>>x>>K>>c;
for(i=2;i<=N;i++)
{
S1=i*(i+1)/2;

// piramida i-1 are numerele in intervalul [vmin,vmax]


vmin=S+1;vmax=S+S1;
S=S+S1;

//verifica daca se formeaza piramida i-1


if(N>=vmin&&N<=vmax){ np=i-2; nrc=N-vmin+1;i=N;ok1=1;}

if(ok1==0)//daca se formeaza piramida i-1


{
//verifica daca numarul x este in piramida i-1
if(x>=vmin&&x<=vmax)ok=i-1;
nr=0;

//numaram cartonasele albe din piramida i-1


while(c>=vmin&&c<=vmax&& !f.eof()){ nr++; f>>c;}
if (nr>pmax) {pmax=nr; ppmax=i-1;}
}
}

g<<ok<<endl<<np<<endl<<nrc <<endl<<ppmax;

f.close();
g.close();

return 0;
}

Listing 10.2.7: pRaluca.cpp


#include <fstream>

using namespace std;

ifstream f("piramide.in");
ofstream g("piramide.out");

int n, x, k, c;

int main()
{
f>>n>>x>>k;

int cp=0, cc=3, pas=3, cn=n, pc=1, uc=3,px=0,c1;

while(cn>=cc)
{
cn-=cc;
cp++;
if(x>=pc and x<=uc) px=cp;
cc+=pas;
pas++;
pc=uc+1;
uc=pc+cc-1;
}
CAPITOLUL 10. OJI 2014 10.2. PIRAMIDE 135

g<<px<<’\n’<<cp<<’\n’<<cn<<’\n’;

f>>c1;
pc=1;uc=3;cc=3;pas=3;
int cpp=1;

while(c1>uc)
{
cpp++;
cc+=pas;
pas++;
pc=uc+1;
uc=pc+cc-1;
}

int max=0, ca=1, pir=0,i;

for(i=2;i<=k and cpp<=cp;i++)


{
f>>c1;
if(c1<=uc)ca++;
else
{
if(ca>max and cpp<=cp)max=ca, pir=cpp;
ca=1;
while(c1>uc)
{
cpp++;
cc+=pas;
pas++;
pc=uc+1;
uc=pc+cc-1;
}
}
}

if(ca>max and cpp<=cp)


max=ca, pir=cp;

g<<pir<<’\n’;

f.close();
g.close();

return 0;
}

10.2.3 *Rezolvare detaliată


Capitolul 11

OJI 2013

11.1 bete
Problema 1 - bete 100 de puncte
Ana şi Bogdan au găsit la bunicul lor o cutie cu N beţe de aceeaşi lungime. După câteva
minute de joacă urmează cearta. Bunicul le-a propus să rupă cele N beţe şi apoi Ana să primească
fragmentele din mâna stângă, iar Bogdan fragmentele din mâna dreaptă. Zis şi făcut. Copiii au
luat fragmentele, le-au numerotat fiecare cu numere de la 1 la N , le-au măsurat şi acum ı̂şi doresc
să lipească fragmentele primite, dar mai au nevoie de câteva informaţii.

Cerinţe

Cunoscând N numărul de beţe, a1 , a2 , ..., aN lungimile fragmentelor primite de Ana şi


b1 , b2 , ..., bN lungimile fragmentelor primite de Bogdan, să se scrie un program care să determine:
a) lungimea iniţială a beţelor;
b) lungimea celui mai lung băţ care se poate obţine prin lipirea unui fragment aparţinând Anei
cu un fragment care aparţine lui Bogdan;
c) numărul beţelor de lungime maximă care se pot obţine prin lipirea unui fragment aparţinând
Anei cu un fragment care aparţine lui Bogdan.

Date de intrare

Fişierul de intrare bete.in conţine pe prima linie numărul natural N reprezentţnd numărul de
beţe. Pe a doua linie sunt N numere naturale a1 , a2 , ..., aN reprezentţnd lungimile fragmentelor
primite de Ana şi pe a treia linie sunt N numere naturale b1 , b2 , ..., bN reprezentţnd lungimile
fragmentelor primite de Bogdan.

Date de ieşire

Fişierul de ieşire bete.out va conţine trei linii. Pe prima linie se va scrie numărul natu-
ral L reprezentând lungimea iniţială a beţelor, pe a doua linie se va scrie numărul natural K
reprezentând lungimea celui mai lung băţ care se poate obţine prin lipirea unui fragment aparţinţnd
Anei cu un fragment care aparţine lui Bogdan, iar pe a treia linie se va scrie numărul natural P
reprezentând numărul beţelor de lungime maximă care se pot obţine prin lipirea unui fragment
aparţinând Anei cu un fragment care aparţine lui Bogdan.

Restricţii şi precizări

a 1 & N & 1000


a 1 & ai & 10000, (1 & i & N )
a 1 & bi & 10000, (1 & i & N )
a 1 & L & 20000
a 1 & K & 20000
a 1 & P & 1000
a Odată lipite două fragmente, acestea nu se pot dezlipi.
a Pentru determinarea corectă a valorii L se acordă 30% din punctaj, pentru determinarea
corectă a valorii K se acordă 30% din punctaj, iar pentru determinarea corectă a valorii P se
acordă 40% din punctaj.

136
CAPITOLUL 11. OJI 2013 11.1. BETE 137

Exemple
bete.in bete.out Explicaţii
6 10 Lungimea iniţială este 10,
267135 16 lungimea maximă este 16
547893 1 şi se poate forma un singur băţ de lungime 16.

Timp maxim de executare/test: 0.5 secunde


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

11.1.1 Indicaţii de rezolvare


prof. Lucia Miron

Pentru a determina lungimea initiala a betelor $L$ vom determina in $S$ suma
numerelor citite. Apoi evident

\hspace{7mm} L = S div N

Determinam maximul elementelor din sirul a si numarul de aparitii al


maximului, notate maxa si nrmaxa, apoi determinam maximul elementelor
din b si numarul de aparitii al acestuia, notate maxb si nrmaxb. Evident

\hspace{7mm} K = maxa + maxb

\hspace{7mm} nrbetemax = min(nrmaxa, nrmaxb)

Toate datele necesare le determinam la citire, nu este necesara utilizarea


tablourilor

11.1.2 Cod sursă

Listing 11.1.1: bete OFICIAL.cpp


//Lucia Miron

#include<fstream>

using namespace std;

ifstream fin("bete.in");
ofstream fout("bete.out");

int n,l,k,a,b,i,j,s,ma,mb,na,nb;

int main()
{
fin>>n;
fin>>a;

ma=a;na=1;s=a;
for(i=2;i<=n;i++)
{
fin>>a;
if(ma<a){ma=a;na=1;}
else if(ma==a)na++;
s+=a;
}

fin>>b;
mb=b;nb=1;s+=b;

for(i=2;i<=n;i++)
{
fin>>b;
CAPITOLUL 11. OJI 2013 11.2. CHIBRITURI 138

if(mb<b){mb=b;nb=1;}
else
if(mb==b) nb++;
s+=b;
}

l=s/n;

fout<<l<<’\n’<<ma+mb<<’\n’<<min(na,nb)<<’\n’;
fout.close();
return 0;
}

Listing 11.1.2: bete vectori.cpp


//octavian dumitrascu

#include<fstream>

using namespace std;

ifstream fin("bete.in");
ofstream fout("bete.out");

int n,l,k,a[1001],b[1001],i,j,s,p;

int main()
{
fin>>n;
s=0;
for(i=1;i<=n;i++)
{
fin>>a[i];
s+=a[i];
}
for(i=1;i<=n;i++)
{
fin>>b[i];
s+=b[i];
}

l=s/n;
k=0;

for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i]+b[j]>k)
k=a[i]+b[j];

for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i]+b[j]==k)
{
p++;
a[i]=-1;
b[j]=-1;
};

fout<<l<<’\n’<<k<<’\n’<<p;
fout<<’\n’;
fout.close();

return 0;
}

11.1.3 *Rezolvare detaliată

11.2 chibrituri
Problema 2 - chibrituri 100 de puncte
CAPITOLUL 11. OJI 2013 11.2. CHIBRITURI 139

Lui Gigel, elev ı̂n clasa a V-a, ı̂i place grozav de tare să se joace cu
cifrele, cu numerele şi creează tot felul de probleme pe care apoi ı̂ncearcă
să le rezolve. Acum se joacă cu o cutie de chibrituri şi formează cu ele
cifre. Apoi privirea i-a căzut pe cadranul unui ceas electronic şi a văzut
că cifrele sunt formate din segmente orizontale şi verticale şi a ı̂nceput să Figura 11.1: chibrit-
formeze cu chibriturile cifrele care indică ora (vezi figura). uri1
Şi imediat şi-a pus o ı̂ntrebare: ”oare dacă am n chibrituri puse ver-
tical şi m chibrituri puse orizontal, care este ora minimă pe care o pot forma cu aceste chibrituri”

Cerinţe

Fiind date un număr n de chibrituri verticale şi un număr m de chibrituri orizontale, să se
scrie un program care determină numărul de ore posibile, ora minimă şi ora maximă care se
pot forma cu aceste chibrituri, ı̂n modul indicat mai sus, utilizând toate chibriturile respective şi
nemodificţnd orientarea acestora.

Date de intrare

Fişierul de intrare chibrituri.in conţine pe prima linie două numere naturale n m, separate
printr-un spaţiu, indicând numărul de chibrituri verticale (n), respectiv orizontale (m).

Date de ieşire

Fişierul de ieşire chibrituri.out va conţine pe prima linie numărul de variante posibile de a


forma o oră corectă, pe a doua linie ora minimă ce poate fi obţinută utilizând toate chibriturile
şi nemodificând orientarea acestora, iar pe a treia linie ora maximă ce poate fi obţinută utilizând
toate chibriturile şi nemodificând orientarea acestora. Ora minimă şi, respectiv, ora maximă se
vor scrie sub forma hh  mm, unde ora hh şi minutul mm vor fi formate din exact două cifre,
separate prin caracterul : (două puncte).

Restricţii şi precizări

Pentru datele de test există ı̂ntotdeauna soluţie. Cifrele sunt formate din chibrituri ı̂n felul
următor:

Figura 11.2: chibrituri2

Pentru determinarea corectă a numărului de variante se va acorda 20% din punctaj, pentru
determinarea corectă a numărului de variante şi a orei minime se va acorda 60% din punctaj, iar
pentru determinarea corectă a numărului de variante, a orei minime şi a orei maxime se va acorda
punctajul maxim.

Exemple

chibrituri.in chibrituri.out Explicaţii


14 10 17 17 variante posibile
00:28 Ora minimă: 00:28
20:08 Ora maximă: 20:08

Timp maxim de executare/test: 0.1 secunde


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

11.2.1 Indicaţii de rezolvare


prof. Marinel Şerban
CAPITOLUL 11. OJI 2013 11.2. CHIBRITURI 140

Numar si retin pentru fiecare cifra numarul de chibrituri verticale si orizontale


necesare.

Retinerea valorilor o fac fie intr-un vector, fie in variabile fie ... pe hartie!

Plec de la ora 00:00, adica 0 minute

Marchez faptul ca inca nu am gasit nicio ora corecta

Parcurg toate orele posibile - intr-o zi sunt 24*60 minute

\begin{verbatim}
calculez ora
calculez minutele
calculez prima si a doua cifra a orei
calculez prima si a doua cifra a minutului

numar chibriturile verticale (fie din vector, fie din variabile, fie direct
ca si constante in instructiuni if sau switch)
numar chibriturile orizontale (la fel)

daca am gasit ambele valori corecte


mai am o solutie, o numar
daca este prima gasita aceasta este ora minima, o retin
daca nu este prima am mai gasit solutie deci aceasta este (deocamdata)
ora maxima, o retin
trec la ora (minutul) urmatoare

Afisez tinand cont ca daca am doar o solutie, aceasta este si ora maxima

11.2.2 Cod sursă

Listing 11.2.1: chibrituri OFICIAL.cpp


//Serban Marinel - ianuarie 2013
//solutie fara utilizarea vectorilor

#include <fstream>

using namespace std;

ifstream fin("chibrituri.in");
ofstream fout("chibrituri.out");

bool OK1;
short int t, h1, h2, m1, m2, v, o, vOK, oOK, Cate;
short int h1min, h2min, m1min, m2min;
short int h1max, h2max, m1max, m2max;

int main()
{
fin >> vOK >> oOK;
t = 0; //plec de la ora 00:00
OK1 = false; //inca nu am gasit nici o ora corecta
Cate = 0;
while (t < 24 * 60) //intr-o zi sunt 24*60 minute
{ //trec pe la fiecare
m1 = t % 60; //ora
h1 = t / 60; //minute
h2 = h1 % 10; //a doua cifra a orei
h1 = h1 / 10; //prima cifra a orei
m2 = m1 % 10; //a doua cifra a minutului
m1 = m1 / 10; //prima cifra a minutului

v = 0; //numar chibrituri verticale


switch (h1)
CAPITOLUL 11. OJI 2013 11.2. CHIBRITURI 141

{
case 1:
case 2:
case 3:
case 5:
case 7: v += 2; break;
case 4:
case 6:
case 9: v += 3; break;
case 0:
case 8: v += 4; break;
}
switch (h2)
{
case 1:
case 2:
case 3:
case 5:
case 7: v += 2; break;
case 4:
case 6:
case 9: v += 3; break;
case 0:
case 8: v += 4; break;
}
switch (m1)
{
case 1:
case 2:
case 3:
case 5:
case 7: v += 2; break;
case 4:
case 6:
case 9: v += 3; break;
case 0:
case 8: v += 4; break;
}
switch (m2)
{
case 1:
case 2:
case 3:
case 5:
case 7: v += 2; break;
case 4:
case 6:
case 9: v += 3; break;
case 0:
case 8: v += 4; break;
}

o = 0; //numar chibrituri orizontale


switch (h1)
{
case 1: o += 0; break;
case 4:
case 7: o += 1; break;
case 0: o += 2; break;
case 2:
case 3:
case 5:
case 6:
case 8:
case 9: o += 3; break;
}
switch (h2)
{
case 1: o += 0; break;
case 4:
case 7: o += 1; break;
case 0: o += 2; break;
case 2:
case 3:
case 5:
case 6:
CAPITOLUL 11. OJI 2013 11.2. CHIBRITURI 142

case 8:
case 9: o += 3; break;
}
switch (m1)
{
case 1: o += 0; break;
case 4:
case 7: o += 1; break;
case 0: o += 2; break;
case 2:
case 3:
case 5:
case 6:
case 8:
case 9: o += 3; break;
}
switch (m2)
{
case 1: o += 0; break;
case 4:
case 7: o += 1; break;
case 0: o += 2; break;
case 2:
case 3:
case 5:
case 6:
case 8:
case 9: o += 3; break;
}

if (v == vOK && o == oOK) //daca am gasit ambele valori corecte


{
Cate++; //mai am o solutie, o numar
if (!OK1) //prima gasita? deci este ora minima, retin
{
h1min = h1, h2min = h2, m1min = m1, m2min = m2;
OK1 = true;
}
else //am mai gasit deci este (deocamdata) ora maxima
h1max = h1, h2max = h2, m1max = m1, m2max = m2;
}
t++; //trec la ora (minutul) urmatoare
}
fout << Cate << ’\n’;
fout << h1min << h2min << ’:’ << m1min << m2min << ’\n’;
if (Cate == 1) //daca am doar o solutie, aceasta este si ora maxima
fout << h1min << h2min << ’:’ << m1min << m2min << ’\n’;
else
fout << h1max << h2max << ’:’ << m1max << m2max << ’\n’;

fout.close();

return 0;
}

Listing 11.2.2: chibrituri v.cpp


//Serban Marinel - ianuarie 2013
//solutie cu utilizarea vectorilor
#include <fstream>

using namespace std;

ifstream fin("chibrituri.in");
ofstream fout("chibrituri.out");

int OK1;
short int t, h1, h2, m1, m2, v, o, vOK, oOK, Cate;
short int h1min, h2min, m1min, m2min;
short int h1max, h2max, m1max, m2max;

short int Vert[] = {4, 2, 2, 2, 3, 2, 3, 2, 4, 3};


short int Oriz[] = {2, 0, 3, 3, 1, 3, 3, 1, 3, 3};

int main()
CAPITOLUL 11. OJI 2013 11.2. CHIBRITURI 143

{
fin >> vOK >> oOK;
t = 0; //plec de la ora 00:00
OK1 = 0; //inca nu am gasit nici o ora corecta
Cate = 0;
while (t < 24 * 60) //intr-o zi sunt 24*60 minute
{ //trec pe la fiecare
m1 = t % 60; //ora
h1 = t / 60; //minute
h2 = h1 % 10; //a doua cifra a orei
h1 = h1 / 10; //prima cifra a orei
m2 = m1 % 10; //a doua cifra a minutului
m1 = m1 / 10; //prima cifra a minutului

//numar chibrite verticale


v = Vert[h1] + Vert[h2] + Vert[m1] + Vert[m2];

//numar chibrite orizontale


o = Oriz[h1] + Oriz[h2] + Oriz[m1] + Oriz[m2];

if (v == vOK && o == oOK) //daca am gasit ambele valori corecte


{
Cate++; //mai am o solutie, o numar
if (OK1 == 0) //prima gasita? deci este ora minima, retin
{
h1min = h1, h2min = h2, m1min = m1, m2min = m2;
OK1 = 1;
}
else //am mai gasit deci este (deocamdata) ora maxima
h1max = h1, h2max = h2, m1max = m1, m2max = m2;
}

t++; //trec la ora (minutul) urmatoare


}

fout << Cate << ’\n’;


fout << h1min << h2min << ’:’ << m1min << m2min << ’\n’;
if (Cate == 1) //daca am doar o solutie, aceasta este si ora maxima

fout << h1min << h2min << ’:’ << m1min << m2min << ’\n’;
else
fout << h1max << h2max << ’:’ << m1max << m2max << ’\n’;

fout.close();
return 0;
}

11.2.3 *Rezolvare detaliată


Capitolul 12

OJI 2012

12.1 alice
Problema 1 - alice 100 de puncte
Într-o zi frumoasă de vară, Alice se juca ı̂n parc. Deodată, văzu un
iepure cu ceas, numit Iepurele Alb, sărind grăbit ı̂n scorbura unui copac.
Curioasă, Alice ı̂l urmări şi sări şi ea ı̂n scorbură. Spre mirarea ei, ajunse
ı̂ntr-o sală mare cu N uşi ı̂ncuiate. Pe fiecare uşă era scris câte un număr
natural. Într-o clipă, lângă ea apăru Iepurele Alb şi-i spuse că doar uşile Figura 12.1: alice
cu numere magice pot fi deschise dacă are cheile potrivite. Pentru a o
ajuta, Iepurele Alb i-a explicat că un număr magic este un număr natural
care poate fi redus la o cifră prin complementarea cifrelor acestuia faţă de cifra sa maximă din
scrierea zecimală, apoi prin complementarea cifrelor numărului obţinut faţă de cifra sa maximă
şi aşa mai departe până când se obţine o cifră. Evident, nu toate numerele naturale sunt numere
magice. De exemplu, uşa cu numărul 1234 poate fi deschisă cu cheia inscripţionată cu cifra 1
deoarece 1234 este un număr magic ce poate fi redus la cifra 1 prin complementări repetate
(1234 3210 123 210 12 10 1), iar uşa cu numărul 1204 nu poate fi deschisă
deoarece 1204 nu este un număr magic (indiferent de câte ori s-ar repeta complementarea nu
poate fi redus la o cifră: 1204 3240 1204 3240 1204.).
Înainte să dispară, Iepurele Alb ı̂i dădu o cheie aurie inscripţionată cu cifra K şi o avertiză că
poate deschide cu această cheie doar uşile cu numere magice ce pot fi reduse la cifra K.

Cerinţe

Scrieţi un program care să citească numerele naturale N , K şi cele N numere naturale scrise
pe cele N uşi, şi care să determine:
a) cel mai mare număr par dintre numerele scrise pe cele N uşi;
b) numărul uşilor care pot fi deschise cu cheia aurie inscripţionată cu cifra K.

Date de intrare

Fişierul alice.in conţine:


- pe prima linie cele două numere naturale N şi K, separate printr-un spaţiu;
- pe a doua linie N numere naturale, separate prin câte un spaţiu, reprezentând numerele scrise
pe cele N uşi.

Date de ieşire

Fişierul alice.out va conţine:


- pe prima linie, un număr natural reprezentând cel mai mare număr par dintre numerele scrise
pe cele N uşi;
- pe a doua linie, un număr natural reprezentând numărul uşilor care pot fi deschise cu cheia
aurie inscripţionată cu cifra K.

Restricţii şi precizări

144
CAPITOLUL 12. OJI 2012 12.1. ALICE 145

- complementarea cifrelor unui număr natural faţă de cifra sa maximă din scrierea zecimală
constă ı̂n ı̂nlocuirea fiecărei cifre c din număr cu diferenţa dintre cifra maximă şi cifra c; de
exemplu, cifra maximă a numărului 1234 este 4 iar prin complementare se ı̂nlocuieşte cifra 1 cu
3( 4  1), cifra 2 cu 2( 4  2), cifra 3 cu 1 ( 4  3) şi cifra 4 cu 0( 4  4) rezultând numărul
3210;
- 7 & N & 10000; 0 & K & 9;
- pe fiecare uşă este scris un singur număr natural;
- există cel puţin o uşă pe care este scris un număr par;
- numărul scris pe oricare uşă (din cele N ) este mai mare sau egal cu 10 şi mai mic sau egal
cu 32800;
- pentru rezolvarea corectă a cerinţei a) se acordă 20% din punctaj, iar pentru rezolvarea
corectă a ambelor cerinţe se acordă 100% din punctaj.

Exemple
alice.in alice.out Explicaţii
71 1234 a) Sunt N=7 uşi pe care sunt scrise numerele 1204, 1234,
1204 1234 13 195 23 10 888 3 13, 195, 23, 10, 888. Cel mai mare număr par dintre cele
scrise pe uşi este 1234, număr care se va scrie pe prima
linie a fişierului alice.out.
b) Cheia primită este inscripţionată cu cifra K=1 şi de-
schide 3 uşi cu numerele 1234, 23 şi 10 deoarece numerele
magice dintre cele scrise pe uşi sunt: 1234 (1234 3210
123 210 12 10 1), 13(13 20 2), 195(195
804 84 4), 23(23 10 1), 10(10 1), 888
(888 0). Numărul 1204 nu este un număr magic. Astfel
numărul 3 se va scrie pe a doua linie a fişierului alice.out.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 10 KB

12.1.1 Indicaţii de rezolvare

Figura 12.2: AliceIR1


CAPITOLUL 12. OJI 2012 12.1. ALICE 146

Figura 12.3: AliceIR2

Figura 12.4: AliceIR3

Figura 12.5: AliceIR4


CAPITOLUL 12. OJI 2012 12.1. ALICE 147

12.1.2 Cod sursă

Listing 12.1.1: alice CM2.cpp


//autor. prof. Carmen Minca

#include <fstream>

using namespace std;

int main()
{
int x,cmax,c,z,nrmax,i,nc=0,a, maxpar=0,n,j,nr=0,k;

ifstream f("alice.in");
ofstream g("alice.out");

f>>n>>k;
for(j=1;j<=n; j++)
{
f>>a;
z=x=a;
if(a%2==0 && maxpar<a)maxpar=a;

do
{
a=z; z=x; cmax=0; nc=0;
while(x)
{
c=x%10; x=x/10;nc++;
if(c>cmax)cmax=c;
}

nrmax=0;
for(i=1;i<=nc;i++)
nrmax=nrmax*10+cmax;

x=nrmax-z;
} while(x>9 && x!=z && x!=a);

if(x==k) nr++;
}

g<<maxpar<<endl<<nr;
return 0;
}

Listing 12.1.2: alice CS.cpp


//prof. Cristina Sichim

#include <fstream>

using namespace std;

ifstream f("alice.in");
ofstream g("alice.out");

int i,n,x,m,k,nr;

int vm(int x)
{
int cmax=0,u=0;

while(x)
{
if(x%10>cmax) cmax=x%10;
x=x/10;
u=u*10+1;
}

return u*cmax;
}
CAPITOLUL 12. OJI 2012 12.1. ALICE 148

int complement(int x)
{
int nr=0,u;

while(x>9 && nr<9)


{
u=vm(x);
x=u-x;
nr++;
}

if(x>9)return -1;
return x;
}

int main()
{
f>>n>>k;
while(n--)
{
f>>x;
if(x%2==0 && x>m) m=x;
if(complement(x)==k) nr++;
}

g<<m<<’\n’<<nr<<’\n’;
f.close();
g.close();

return 0;
}

Listing 12.1.3: alice SJ.cpp


//prof.Sanda Junea
#include <iostream>
#include<fstream>

using namespace std;

ifstream f("alice.in");
ofstream g("alice.out");

int magic(int x);

int n,k,nr,maxim,x;

int main(void)
{
f>>n>>k;

for( int i = 0; i < n; ++i )


{
f>>x;
if(x%2==0 && x>maxim)
maxim=x;
if(magic(x)==k)
nr++;
}

g<<maxim<<endl;
g<<nr;

f.close();
g.close();

return 0;
}

int magic(int x)
{
int y=x,m=0,l=x,r=1,zero=0,ok=1,z=x;
if(x<10)
return x;
CAPITOLUL 12. OJI 2012 12.2. PORUMB 149

while(l>=10 && ok)


{
l=0;r=1,m=0;
y=x;
while(y)
{
if(y%10>m)
m=y%10;
y=y/10;
}

y=x;
while(y)
{
l=l+r*(m-y%10);
r=r*10;
y=y/10;
}

if(l==z)
ok=0;
else
{
ok=1;
z=x;
x=l;
}
}

if(l<10)
return l;
else
return -1;
}

12.1.3 *Rezolvare detaliată

12.2 porumb
Problema 2 - porumb 90 de puncte
Locuitorii planetei Agria, numiţi agri, au hotărât ca ı̂n celebrul an 2012 să le explice
pământenilor cum trebuie cules ”eficient” un rând cu n porumbi, numerotaţi, ı̂n ordine, cu
1, 2, 3, ..., n.
Cei n porumbi sunt culeşi de mai mulţi agri. Primul agri merge de-a lungul rândului, plecând
de la primul porumb şi culege primul porumb ı̂ntâlnit, al treilea, al cincilea şi aşa mai departe
până la capătul rândului. Atunci când ajunge la capătul rândului, porneşte al doilea agri şi culege
porumbi respectând aceeaşi regulă ca şi primul agri.
Metoda se repetă până când toţi porumbii sunt culeşi.
Pământeanul Ionel ı̂ncearcă să descopere ce ascunde această metodă şi se gândeşte câţi porumbi
culege primul agri, câţi agri culeg un rând cu n porumbi, la a câta trecere este cules porumbul cu
numărul x şi care este numărul ultimului porumb cules.
Exemplu: Dacă pe un rând sunt n=14 porumbi atunci sunt 4 agri care culeg porumbii:
a primul agri culege porumbii
1,3,5,7,9,11,13;

a al doilea agri culege porumbii 2,6,10,14;

a al treilea agri culege porumbii 4 şi 12;

a ultimul agri culege porumbul 8.


Figura 12.6: porumbi
Cerinţe
Pentru a-l ajuta pe Ionel să descopere secretul acestei metode, scrieţi un program care citeşte cele
două numere naturale n şi x şi care determină:
CAPITOLUL 12. OJI 2012 12.2. PORUMB 150

a) numărul de porumbi culeşi de primul agri;


b) numărul de agri care culeg şirul de n porumbi;
c) numărul trecerii la care este cules porumbul cu numărul x;
d) numărul ultimului porumb cules.

Date de intrare

Fişierul porumb.in conţine pe prima linie, separate printr-un spaţiu, cele două numere nat-
urale n şi x cu semnificaţia din enunţ.

Date de ieşire

Fişierul de ieşire porumb.out va conţine patru linii:


- pe prima linie se va scrie un număr natural reprezentând numărul de porumbi culeşi de primul
agri;
- pe a doua linie se va scrie un număr natural reprezentând numărul de agri care culeg cei n
porumbi;
- pe a treia linie se va scrie un număr natural, reprezentând numărul trecerii la care este cules
porumbul x;
- pe a patra linie se va scrie un număr natural, reprezentând numărul ultimului porumb cules.

Restricţii şi precizări

- 1 & x & n & 1000000000


- Trecerile se numerotează ı̂n ordine, ı̂ncepând cu valoarea 1.
- Pentru rezolvarea corectă a cerinţei a) se acordă 10% din punctaj.
- Pentru rezolvarea corectă a cerinţelor a) şi b) se acordă 40% din punctaj.
- Pentru rezolvarea corectă a cerinţelor a), b) şi c) se acordă 70% din punctaj.
- Pentru rezolvarea corectă a celor patru cerinţe se acordă 100% din punctaj.

Exemple

porumb.in porumb.out Explicaţii


14 4 7 7 reprezintă numărul de porumbi culeşi de primul agri.
4 Sunt 4 agri care culeg rândul cu n 14 porumbi.
3 Porumbul x 4 este cules la a 3-a trecere iar ultimul
8 porumb cules are numărul 8.

Timp maxim de executare/test: —1.0 secunde


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

12.2.1 Indicaţii de rezolvare


CAPITOLUL 12. OJI 2012 12.2. PORUMB 151

Figura 12.7: porumbIR1

Figura 12.8: P orumbIR2

12.2.2 Cod sursă

Listing 12.2.1: p100 AS.cpp


//prof.Adriana Simulescu

#include<iostream>
#include<fstream>

using namespace std;

int main()
{ofstream out("porumb.out");
ifstream in("porumb.in");

int p=1,n,na=1,x,randx;
in>>n>>x;
out<<(n+1)/2<<endl;

while(p<n)
{p=p*2;
na++;
if((x-p)%(p*2)==0) randx= na;
CAPITOLUL 12. OJI 2012 12.2. PORUMB 152

if(p>n) {p=p/2;na--;}

if(x%2==1) randx=1;
out<<na<<endl<<randx<<endl<<p<<endl;

in.close();
out.close();

return 0;
}

Listing 12.2.2: p100 CL.cpp


//prof. Chira Liliana
#include<cstdio>

using namespace std;

int n,x;

int main()
{
int m=1,k=0,nr=0;

freopen("porumb.in","r",stdin);
freopen("porumb.out","w",stdout);

scanf("%d%d", &n, &x);


printf("%d\n", (n+1)/2);

while(m<=n)
m*=2;

m/=2;

while(x%2==0)
{
x/=2;
k++;
}

while(n!=0)
{
nr++;
n/=2;
}

printf("%d\n%d\n%d\n", nr , k+1, m);

return 0;
}

Listing 12.2.3: p100 CM1.cpp


//prof.Carmen Minca

#include <fstream>
#include <iostream>

using namespace std;

int main()
{
ifstream f("porumb.in");
ofstream g("porumb.out");

int n,x,pas=1,t=0,tx=0,u=0,k=0,m;

f>>n>>x;
g<<(n+1)/2<<endl;

m=n;
CAPITOLUL 12. OJI 2012 12.2. PORUMB 153

while(k!=m)
{ t++; //o noua trecere
k=k+(n+1)/2; //nr.porumbi culesi=nr de nr impare <=n
//sirul: pas(1,2,3,4,5,6,7), pas=2ˆ(t-1)
u=n*pas;
if(n%2==0) u-=pas;
if(x%pas==0)tx=t;
n/=2; pas*=2;
}
if(x%2)tx=1;
g<<t<<endl<<tx<<endl<<u<<endl;
}

Listing 12.2.4: p100 CM2.cpp


//prof. Carmen Mica - o altfel de solutie

#include <fstream>
#include <iostream>
#include <cmath>

using namespace std;

int main()
{
ifstream f("porumb.in");
ofstream g("porumb.out");

int n,x,a,t,ult,u;

f>>n>>x;
g<<(n+1)/2<<endl;

u=log10(n*1.0)/log10(2.); //u<--log2(n)
a=u+1; //a<--2ˆ(u+1)
ult=pow(2.0,u); //ult<--2ˆu

t=1;
while(x%2==0){t++; x>>=1;}

// x este pe randul care incepe cu


// 2ˆ(t-1), t=maximum cu aceasta proprietate

g<<a<<endl<<t<<endl<<ult<<endl;

return 0;
}

Listing 12.2.5: p100 CS.cpp


//autor. prof Cristina Sichim

# include <fstream>

using namespace std;

long n,m,x,nr;

int main()
{ifstream f("porumb.in");
ofstream g("porumb.out");

f>>n>>x;

//a) nr.porumbi la prima trecere


g<<(n+1)/2<<’\n’;

//b) nr trasee
m=n;
while(m>0)nr++,m=m/2;
g<<nr<<’\n’;

//c)cand culege porumbul x


while(x%2==0) x=x/2,m++;
CAPITOLUL 12. OJI 2012 12.2. PORUMB 154

g<<m+1<<’\n’;

//d) ultimul porumb


m=1;
while(m*2<=n)m=m*2;

g<<m<<’\n’;

f.close();
g.close();
return 0;
}

Listing 12.2.6: p100 DT.cpp


//prof. Daniela Tarasa

#include<fstream>
#include<math.h>

using namespace std;

ifstream f("porumb.in");
ofstream g("porumb.out");

int nr,n,x,nr1=1,aux;
long long q;

int main()
{f>>n>>x;
aux=x;

//numarul de porumbi culesi de primul agri


if(n%2==0) g<<n/2<<’\n’;else g<<n/2+1<<’\n’;

//numarul de agri
while(n!=0)
{
n=n/2;
nr++;
}
g<<nr<<’\n’;

//numarul trecerii la care este cules porumbul x


while(x%2==0)
{
x=x/2;
nr1++;
}
if (aux%2!=0) g<<1<<’\n’;
else g<<nr1<<’\n’;

q=pow(2,nr-1);

g<<q<<’\n’;

f.close();
g.close();
return 0;
}

Listing 12.2.7: p100 JIT.cpp


//prof. Jakab Irma Tunde

#include <iostream>
#include <fstream>
#include <conio.h>
#include <math.h>

using namespace std;

int main(void)
{unsigned long n,x,p=1,e=0,a,b;
CAPITOLUL 12. OJI 2012 12.2. PORUMB 155

fstream f,g;
f.open("porumb.in", ios::in);
f>>n>>x;

while (p*2<n)
{
p*=2;
e++;
}

if (x%2)b=1;
else
{
a=p;b=0;
while (x%a!=0)
{
a/=2;
b++;
}
}

cout<<e+1<<’ ’<<e+1-b<<’ ’<<p;

g.open("porumb.out", ios::out);
g<<(n+1)/2<<endl<<e+1<<endl<<e+1-b<<endl<<p;;
g.close();
}

12.2.3 *Rezolvare detaliată


Capitolul 13

OJI 2011

13.1 magic
Problema 1 - magic 100 de puncte
Rămaşi singuri ı̂n pădure, Hansel şi Grettel, ştiu că singura lor şansă de supravieţuire este să
găsească şi să intre ı̂n Castelul de Turtă Dulce. Poarta castelului este ı̂nchisă şi pentru a intra
este nevoie de un cuvânt magic şi de un număr fermecat.
Zâna cea Bună ı̂i vede pe copii şi pentru că vrea să-i ajute le spune: ”Mergeţi tot ı̂nainte,
iar ı̂n drumul vostru o să ı̂ntâlniţi copaci pe a căror trunchiuri sunt scrise caractere reprezentând
litere sau cifre. Cuvântul magic este format din toate caracterele literă ı̂n ordinea ı̂n care apar,
dar scrise toate cu majuscule. Numărul fermecat este cel mai mic număr cu cifre distincte care se
poate forma din caracterele cifră.”
Cerinţe
Pentru a-i ajuta pe Hansel şi Grettel să intre ı̂n Castelul de Turtă Dulce, scrieţi un program
care citeşte un număr natural n, apoi n caractere şi determină:
a) cuvântul magic;
b) numărul fermecat;
Date de intrare
Fişierul magic.in conţine pe prima linie un număr natural n, reprezentând numărul de car-
actere scrise pe copaci. Pe cea de a doua linie sunt n caractere separate prin câte un spaţiu,
reprezentând caracterele scrise pe copaci.
Date de ieşire
Fişierul de ieşire magic.out va conţine două linii:
a) pe prima linie se va scrie un şir de litere mari, reprezentând cuvântul magic;
b) pe a doua linie se va scrie un număr natural cu cifre distincte, reprezentând numărul
fermecat.
Restricţii şi precizări
a 1 & n & 1000
a Caracterele sunt doar cifre sau litere mici ale alfabetului englez.
a Printre cele n caractere se află ı̂ntotdeauna cel puin o literă şi cel puţin o cifră.
a Pe fiecare copac este scris un singur caracter.
a Numărul magic ı̂ncepe ı̂ntotdeauna cu o cifră diferită de zero.
Pentru rezolvarea cerinţei a) se acordă 40% din punctaj, pentru cerinţa b) 60% din punctaj

Exemple
magic.in magic.out Explicaţii
6 CB Cel mai mic număr cu cifre distincte
c255b2 25 ce se poate obţine este 25.
8 CABD 205 Cel mai mic număr cu cifre distincte
ca50b25d ce se poate obţine este 205.
Timp maxim de executare/test: 1.0 secunde

156
CAPITOLUL 13. OJI 2011 13.1. MAGIC 157

13.1.1 Indicaţii de rezolvare

Descriere solutie care utilizeaza vector caracteristic:


Se considera vectorul caracteristic c asociat cifrelor de pe a doua linie a fisierului, vector
construit astfel:

1, daca cifra i se afla pe a doua linie a fisierului


c[i] =
0, altfel

Prin parcurgerea caracterelor de pe a doua linie a fisierului, se determina si se afiseaza ca


majuscule caracterele litera si se completeaza vectorul caracteristic.
Numarul cerut se afiseaza prin parcurgerea vectorului caracteristic de la stanga la dreapta.
Se trateaza separat cazul in care exista cifra 0.
Daca nu exista cifre nenule, se va afisa 0, altfel, aceasta va aparea imediat dupa cifra cea mai
mica, nenula, gasita pe a doua linie a fisierului.
Descriere solutie care nu utilizeaza tablouri:
Fiecarei cifre i se asociaza o variabila care sa memoreze aparitia acesteia pe a doua linie a
fisierului (0 daca nu apare si 1 daca apare).
Prin parcurgerea caracterelor de pe a doua linie a fisierului, se determina si se afiseaza ca
majuscule caracterele litera si se actualizeaza variabilele asociate caracterelor de tip cifra.
Numarul cerut se afiseaza prin cercetarea continuturilor variabilelor asociate cifrelor.
Se trateaza separat cazul in care exista cifra 0.
Daca nu exista cifre nenule, se va afisa 0, altfel, aceasta va aparea imediat dupa cifra cea mai
mica, nenula, gasita pe a doua linie a fisierului.

13.1.2 Cod sursă

Listing 13.1.1: CARACTER.CPP


#include<iostream>
#include<fstream>
#include<ctype.h>

using namespace std;

char s[1001];
int c[10];
int n;

int main()
{
int i,ncifre=0,j;

ifstream f("magic.in");
ofstream g("magic.out");

f>>n;

for(i=1;i<=n;i++)
{
f>>s[i];
s[i]=toupper(s[i]);
if(isdigit(s[i]))
{
ncifre++;
c[s[i]-48]++;
}
}

for(i=1;i<=n;i++)
if(isalpha(s[i]))
g<<s[i];
g<<’\n’;

i=1;
CAPITOLUL 13. OJI 2011 13.1. MAGIC 158

while(c[i]==0) i++;

if(c[0])
g<<i<<0;
else
g<<i;

for(j=i+1;j<=9;j++)
if(c[j])
g<<j;

f.close();
g.close();

return 0;
}

Listing 13.1.2: magic DM.cpp


#include<fstream>
#include<ctype.h>

using namespace std;

char s;
int n;
int c0,c1,c2,c3,c4,c5,c6,c7,c8,c9;

int main()
{
int i;
int nr;

ifstream f("magic.in");
ofstream g("magic.out");

f>>n;

for (i=1;i<=n;i++)
{
f>>s;
if(isalpha(s))
{
s=toupper(s);
g<<s;
}
else
{
nr=int(s)-48;
switch(nr)
{
case 0: c0++;break;
case 1: c1++;break;
case 2: c2++;break;
case 3: c3++;break;
case 4: c4++;break;
case 5: c5++;break;
case 6: c6++;break;
case 7: c7++;break;
case 8: c8++;break;
case 9: c9++;break;
}
}
}
g<<’\n’;

int t=0;

if(c1)
{
g<<1;
if(c0 && t==0)
{
t=1;
g<<0;
CAPITOLUL 13. OJI 2011 13.1. MAGIC 159

}
}

if(c2)
{
g<<2;
if(c0 && t==0)
{
t=1;
g<<0;
}
}

if(c3)
{
g<<3;
if(c0 && t==0)
{
t=1;
g<<0;
}
}

if(c4)
{
g<<4;
if(c0 && t==0)
{
t=1;
g<<0;
}
}

if(c5)
{
g<<5;
if(c0 && t==0)
{
t=1;
g<<0;
}
}

if(c6)
{
g<<6;
if(c0 && t==0)
{
t=1;
g<<0;
}
}

if(c7)
{
g<<7;
if(c0 && t==0)
{
t=1;
g<<0;
}
}

if(c8)
{
g<<8;
if(c0 && t==0)
{
t=1;
g<<0;
}
}

if(c9)
{
g<<9;
CAPITOLUL 13. OJI 2011 13.1. MAGIC 160

if(c0 && t==0)


{
t=1;
g<<0;
}
}

if(t==0 && c0)


g<<0;

f.close();
g.close();

return 0;
}

Listing 13.1.3: MAGIC S.CPP


#include <fstream>

using namespace std;

int x[10];

int main()
{
ifstream fin("magic.in");
ofstream fout("magic.out");

int n, g = 0, i;
char c;

fin >> n;

for( i = 1; i <= n; i++)


{
fin >> c;
if(’a’<= c && c <= ’z’)
{
c = c - 32;

fout << c;
}
else
{
x[c-48]++;
g = 1;
}
}

fout<<’\n’;

i = 1;
while(x[i] == 0)i++;

if(i <= 9) fout <<i, x[i] = 0;

for(i = 0; i <= 9; i++)


if(x[i]) fout << i;
fout << ’\n’;

fin.close();
fout.close();

return 0;
}

Listing 13.1.4: magicAna.cpp


#include <fstream>

using namespace std;

ifstream f("magic.in");
CAPITOLUL 13. OJI 2011 13.1. MAGIC 161

ofstream g("magic.out");

int n,i;
char c;
int x[10];

int main()
{
f>>n;
for(i=1;i<=n;i++)
{
f>>c;
if(c>=’a’ && c<=’z’) g<<(char)(c-32);
else x[c-48]=1;
}
g<<’\n’;

if(x[0]!=0)
{
i=1;
while(x[i]==0 && i<=9)i++;
}

if(i<=9){g<<i;x[i]=0;}

for(i=0;i<=9;i++)
if(x[i]) g<<i;

f.close();
g.close();

return 0;
}

Listing 13.1.5: MAGICDT3.CPP


#include<fstream>

using namespace std;

ifstream f("magic.in");
ofstream g("magic.out");

long nr,nr_fin,m; int x0,x1,x2,x3,x4,x5,x6,x7,x8,x9;

int main()
{
int n,i; char x;

f>>n;
for(i=1;i<=n;i++)
{
f>>x;
if (!(x>=’0’ && x<=’9’)) g<<(char)(x-32);
else
switch (x)
{
case ’0’:x0++; break;
case ’1’: x1++; break;
case ’2’: x2++; break;
case ’3’: x3++; break;
case ’4’: x4++; break;
case ’5’: x5++; break;
case ’6’: x6++; break;
case ’7’: x7++; break;
case ’8’: x8++; break;
case ’9’: x9++; break;
}
}

if(x1!=0 &&x0!=0) {nr=(nr*10+1)*10;x0=0;}


else if(x1!=0) nr=nr*10+1;

if(x2!=0 &&x0!=0) {nr=(nr*10+2)*10;x0=0;}


else if (x2!=0) nr=nr*10+2;
CAPITOLUL 13. OJI 2011 13.2. NUMERUS 162

if(x3!=0 &&x0!=0) {nr=(nr*10+3)*10;x0=0;}


else if(x3!=0) nr=nr*10+3;

if(x4!=0 &&x0!=0) {nr=(nr*10+4)*10;x0=0;}


else if(x4!=0) nr=nr*10+4;

if(x5!=0 &&x0!=0) {nr=(nr*10+5)*10;x0=0;}


else if(x5!=0) nr=nr*10+5;

if(x6!=0 &&x0!=0) {nr=(nr*10+6)*10;x0=0;}


else if(x6!=0) nr=nr*10+6;

if(x7!=0 &&x0!=0) {nr=(nr*10+7)*10;x0=0;}


else if(x7!=0) nr=nr*10+7;

if(x8!=0 &&x0!=0) {nr=(nr*10+8)*10;x0=0;}


else if(x8!=0) nr=nr*10+8;

if(x9!=0 &&x0!=0) {nr=(nr*10+9)*10;x0=0;}


else if(x9!=0) nr=nr*10+9;

if(nr==0) g<<’\n’<<0<<’\n’;
else g<<’\n’<<nr<<’\n’;

f.close();
g.close();
return 0;
}

13.1.3 *Rezolvare detaliată

13.2 numerus
Problema 2 - numerus 100 de puncte
La ora de matematică distractivă, domnul profesor Numerus
propune elevilor săi să completeze cu numere naturale o grilă cu 6
coloane numerotate cu literele A, B, C, D, E şi F şi cu un număr in-
finit de linii. Grila va fi completată cu numere naturale, ı̂ncepând
cu numărul 1. Pe liniile impare completarea se va face de la stânga
la dreapta, iar pe cele pare de la dreapta la stânga. Ultimul număr
de pe o linie va fi identic cu penultimul număr (ı̂n sensul com-
pletării) de pe aceeaşi linie. ı̂n figura alăturată aveţi completate
primele 7 linii ale grilei. Deoarece pe tablă sau pe o foaie de hârtie
numărul de linii este limitat, deci grila poate fi efectiv comple-
tată doar pentru un număr mic de linii, domnul profesor Numerus
Figura 13.1: Numerus
doreşte ca elevii săi să determine, cu ajutorul calculatorului, imag-
inea unei anumite linii a grilei şi locul sau locurile pe care se poate afla un număr natural dat

Cerinţe

Deduceţi regula după care se completează linia k a grilei şi scrieţi un program care să citească
numerele naturale k şi n şi care să determine:
a) numerele naturale de pe linia k, vizualizate de la stânga la dreapta;
b) linia pe care se află ı̂n grilă numărul natural n;
c) coloana sau coloanele pe care se află ı̂n grilă numărul natural n.

Date de intrare

Fişierul numerus.in conţine o singură linie pe care sunt scrise două numere naturale k şi n,
separate pritr-un spaţiu.

Date de ieşire
CAPITOLUL 13. OJI 2011 13.2. NUMERUS 163

Fişierul de ieşire numerus.out va conţine 3 linii:


a) pe prima linie, se vor scrie numerele de pe linia k a grilei;
b) pe a doua linie, se va scrie un număr natural reprezentând linia pe care se află ı̂n grilă
numărul natural n;
c) pe a treia linie, se va scrie litera sau literele care reprezintă coloana, respectiv coloanele pe
care se află ı̂n grilă numărul natural n; În situaţia ı̂n care avem de afişat două litere acestea se vor
afişa cu un spaţiu ı̂ntre ele.

Restricţii şi precizări

a Numerele k şi n sunt naturale nenule


a 5 & k $ 200000000
a 1 & n & 999999999
Pentru rezolvarea cerinţei a) se acordă 40% din punctaj, pentru cerinţa b) 30% din punctaj şi
pentru cerinţa c) 30% din punctaj.

Exemple

Figura 13.2: Numerus - exemple

Timp maxim de executare/test: 1.0 secunde

13.2.1 Indicaţii de rezolvare


a) Numerele de pe linia k sunt:

5* k-4, 5* k-3, 5* k-2, 5* k-1, 5* k, 5*k, daca linia k este impara si


5* k, 5*k, 5* k-1, 5* k-2, 5* k-3, 5* k-4, daca linia k este para

b) Linia pe care se afla numarul n este:

n/5, daca n este multiplu de 5 si


[n/5]+1, altfel

c) Coloana/coloanele pe care se afla numarul n este/sunt:

A B, daca ultima cifra a lui n este 0


A, daca ultima cifra a lui n este 1
B, daca ultima cifra a lui n este 2
C, daca ultima cifra a lui n este 3 sau 9
D, daca ultima cifra a lui n este 4 sau 8
E, daca ultima cifra a lui n este 7
F, daca ultima cifra a lui n este 6
E F, daca ultima cifra a lui n este 5

13.2.2 Cod sursă

Listing 13.2.1: A1 Numer.cpp


#include<fstream>
CAPITOLUL 13. OJI 2011 13.2. NUMERUS 164

using namespace std;

ifstream f("numerus.in");
ofstream g("numerus.out");

long n,i,k,a,b,l,c;

int main()
{
f>>k>>n;
a=5*(k-1)+1;
b=5*k;
if(k%2==1)
{
for(i=a;i<=b;i++) g<<i<<’ ’;
g<<b;
}
else
{
g<<b<<’ ’;
for(i=b;i>=a;i--) g<<i<<’ ’;
}
g<<’\n’;

l=n/5;
if(n%5!=0)l++;
g<<l<<’\n’;

if(n%5==0)
if(l%2==0) g<<’A’<<’ ’<<’B’;
else g<<’E’<<’ ’<<’F’;
else if(l%2==1) {char c=’A’+n%5-1;g<<c;}
else{char c=’F’-n%5+1;g<<c;}
g<<’\n’;

f.close();
g.close();

return 0;
}

Listing 13.2.2: D NUMERU.CPP


#include<fstream>

using namespace std;

ifstream f("numerus.in");
ofstream g("numerus.out");

long n,k;

int main()
{
long lin;
f>>k>>n;

lin=n/5;

//prima cerinta
if(k%2==0)
g<<5*k<<’ ’<<5*k<<’ ’<<5*k-1<<’ ’<<5*k-2<<’ ’<<5*k-3<<’ ’<<5*k-4<<’\n’;
else
g<<5*k-4<<’ ’<<5*k-3<<’ ’<<5*k-2<<’ ’<<5*k-1<<’ ’<<5*k<<’ ’<<5*k<<’\n’;

//a doua cerinta


if(n%5==0) g<<lin<<’\n’;
else {lin++;g<<lin<<’\n’;}

// a treia cerinta
if(lin%2==0)
if(n%5==0) g<<’A’<<’ ’<<’B’;
else g<<(char)(’B’+(5-n%5));
else if(n%5==0) g<<’E’<<’ ’<<’F’;
CAPITOLUL 13. OJI 2011 13.2. NUMERUS 165

else g<<(char)(’E’-(5-n%5));
g<<’\n’;

f.close();
g.close();
return 0;
}

Listing 13.2.3: S Numeru.cpp


#include <fstream>

using namespace std;

int main()
{
long k, n;
long i, r, rd;

ifstream fin("numerus.in");
ofstream fout("numerus.out");

fin >> k >> n;

if(k % 2 == 1)
{
for(i = 1; i<= 5; i++)
fout << (k-1)*5 +i<< " ";
fout << k *5<<"\n";
}
else
{
fout << k*5<< " ";
for(i = 0; i< 5; i++)
fout << k * 5 - i<< " ";
fout << "\n";
}

if( n%5 == 0)
{
rd = n/5;
fout <<rd<<’\n’;
}
else
{
rd = (n/5 +1);
fout << rd<< "\n";
}

if(n%10 == 0 )
fout << ’A’<<" "<<’B’<<"\n";
else
if(n%5 == 0) fout << ’E’<<" "<<’F’<< "\n";

if(rd % 2 == 1)
{
r = n%5;
switch(r)
{
case 1: fout << ’A’<<"\n";break;
case 2: fout << ’B’<<"\n";break;
case 3: fout << ’C’<<"\n";break;
case 4: fout << ’D’<<"\n";break;
}
}
else
{
r = n%5;
switch(r)
{
case 1: fout << ’F’<<"\n";break;
case 2: fout << ’E’<<"\n";break;
case 3: fout << ’D’<<"\n";break;
case 4: fout << ’C’<<"\n";break;
}
CAPITOLUL 13. OJI 2011 13.2. NUMERUS 166

fin.close();
fout.close();

return 0;
}

13.2.3 *Rezolvare detaliată


Capitolul 14

OJI 2010

14.1 sir
Problema 1 - sir 100 de puncte
Se generează un şir de numere naturale ai cărui primi termeni sunt, ı̂n ordine:

1, 12, 21, 123, 231, 312, 1234, 2341, 3412, 4123, 12345, 23451, ...

Cerinţe

Deduceţi regula după care sunt generaţi termenii şirului şi scrieţi un program care să citească
numerele naturale k, x, a şi b şi care să determine:
a) ultima cifră a sumei tuturor termenilor şirului care sunt formaţi din cel mult k cifre;
b) succesorul termenului x ı̂n şirul dat, x fiind un termen al şirului;
c) numărul de termeni ai şirului care au cifra cea mai semnificativă egală cu a şi nu conţin ı̂n
scrierea lor cifra b.

Date de intrare

Fişierul de intrare sir.in conţine o singură linie pe care sunt scrise cele patru numere naturale k,
x, a şi b, separate prin câte un spaţiu.

Date de ieşire

Fişierul de ieşire sir.out va conţine 3 linii:


- pe prima linie se va scrie un număr natural reprezentând ultima cifră a sumei tuturor terme-
nilor şirului care sunt formaţi din cel mult k cifre;
- pe a doua linie se va scrie un număr natural reprezentând succesorul termenului x ı̂n şirul
dat;
- pe a treia linie se va scrie un număr natural reprezentând numărul de termeni ai şirului care
au cifra cea mai semnificativă egală cu a şi nu conţin ı̂n scrierea lor cifra b.

Restricţii şi precizări

a Numerele k, x, a şi b sunt naturale nenule


a 1&k&9
a x este un termen al şirului din enunţ şi are succesor ı̂n şir
a succesorul termenului x ı̂n şir este termenul care urmează imediat după x (de exemplu, dacă
x 2341 atunci succesorului lui x ı̂n şir este 3412)
a 1 & x $ 900000000
a 1 & a & 9; 1 & b & 9; a j b
a cifra cea mai semnificativă a unui număr natural este prima cifră din scrierea sa, de la stânga
la dreapta (de exemplu cifra cea mai semnificativă a numărului 32156 este 3)
a Pentru rezolvarea cerinţei a) se acordă 30% din punctaj, pentru cerinţa b) 40% din punctaj
şi pentru cerinţa c) 30% din punctaj.

167
CAPITOLUL 14. OJI 2010 14.1. SIR 168

Exemple
sir.in sir.out Explicaţii
3 45123 3 6 0 Termenii şirului formaţi fiecare din cel mult k 3 cifre sunt:
51234 1, 12, 21, 123, 231, 312. Suma lor fiind egală cu 700, pe
3 prima linie a fişierului sir.out se va scrie cifra 0 (ultima cifră
a sumei).
Succesorul termenului 45123 este 51234, valoare care se va
scrie pe a doua linie a fişierului sir.out.
Sunt 3 numere care ı̂ncep cu cifra 3 şi care nu conţin cifra 6
şi anume: 312, 3412, 34512. Astfel, numărul 3 se scrie pe a
treia linie a fişierului sir.out.

Timp maxim de executare/test: 1.0 secunde

14.1.1 Indicaţii de rezolvare

Figura 14.1: sirir1

Figura 14.2: sirir2


CAPITOLUL 14. OJI 2010 14.1. SIR 169

Figura 14.3: sirir3

Figura 14.4: sirir4

Figura 14.5: sirir5


CAPITOLUL 14. OJI 2010 14.1. SIR 170

14.1.2 Cod sursă

Listing 14.1.1: sir.CPP


/* autor prof. Minca Carmen
Liceul Teoretic "Ion Neculce" Bucuresti */

#include<fstream>

using namespace std;

int main()
{ofstream g("sir.out");
long x,y,p=1,z;
int k,s=0,a,b,i,c,sa;
ifstream f("sir.in");

f>>k>>x>>a>>b;

s=1; sa=1;
for(i=2;i<=k;i++)
{
s=(s+sa+i)%10;
sa=(sa+i)%10;
}
g<<s<<endl;

//cerinta b)

y=x; k=1;
while(y>9)
{ k++; y/=10; p=p*10; }

if(y==k)
{ z=0;
for(i=1;i<=k+1; i++)
z=z*10+i;
}
else z=(x%p)*10+y;

g<<z<<endl;

//cerinta c)

if(a<b) g<<b-a;
else g<<0;

f.close();
g.close();

return 0;
}

Listing 14.1.2: sirana.cpp


//sursa 100p prof. Ana Intuneric
//CN Ferdinand Bacau

#include <fstream>

using namespace std;

unsigned long s[]={1,12,21,123,231,312,


1234,2341,3412,4123,12345,23451,34512,45123,51234,
123456,234561,345612,456123,561234,612345,
1234567,2345671,3456712,4567123,5671234,6712345,7123456,
12345678,23456781,34567812,45678123,56781234,67812345,78123456,81234567,
123456789,234567891,345678912,456789123,567891234,678912345,789123456,
891234567,912345678};

unsigned k,a,b,uc,i,nr;
unsigned long x;
CAPITOLUL 14. OJI 2010 14.1. SIR 171

ifstream f("sir.in");
ofstream g("sir.out");

int main()
{
f>>k>>x>>a>>b;

//a)
for(i=0;i<k*(k+1)/2;i++)
uc=(uc+s[i]%10)%10;
g<<uc<<’\n’;

//b)
i=0;
while(s[i]<=x) i++;
g<<s[i]<<’\n’;

//c)
if(a<b)g<<(9-a+1)-(9-b+1);
else g<<0;

f.close();
g.close();
return 0;
}

Listing 14.1.3: SIRcris.CPP


// prof.Cristina Sichim
// Colegiul National Ferdinand Bacau

# include <fstream>
# include <math.h>

using namespace std;

int k,a,b,u,i,c;
long x,y,p;

int main()
{ ifstream f("sir.in");
ofstream g("sir.out");
f>>k>>x>>a>>b;

//a
u=0;
for(i=1;i<=k;i++) u=(u+i*(i+1)/2)%10;
g<<u<<endl;

//b
u=0;y=x;
while(y){u++;c=y%10; y=y/10;}

if(c==u)
for(i=1;i<=u+1;i++)y=y*10+i;
else
{
p=pow(10,u-1);
y=x%p*10+x/p;
}
g<<y<<endl;

//c
c=(b>a)?b-a:0;
g<<c;

f.close();
g.close();

return 0;
}

Listing 14.1.4: SIRcris2.CPP


CAPITOLUL 14. OJI 2010 14.1. SIR 172

#include <fstream>

using namespace std;

int k,a,b,u,i,n,v[11];
long x;

int main()
{ ifstream f("sir.in");
ofstream g("sir.out");
f>>k>>x>>a>>b;

//a
u=0;
for(i=1;i<=k;i++) u=(u+i*(i+1)/2)%10;
g<<u<<endl;

//b
n=0;
while(x){n++;v[n]=x%10;x=x/10;}
if(v[n]==n)
for(i=1;i<=n+1;i++)g<<i;
else
{
for(i=n-1;i>=1;i--) g<<v[i];
g<<v[n];
}

g<<endl;

//c
u=(b>a)?b-a:0;
g<<u;

f.close();
g.close();

return 0;
}

Listing 14.1.5: SIRcris2.CPP


//prof Dana Marcu - Suceava

#include<fstream>

using namespace std;

ifstream f("sir.in");
ofstream g("sir.out");

int main()
{
int k,a,b;
long x;
f>>k>>x>>a>>b;

//punctul a)
int i,uc=0;
uc=(k*(k+1)*(k+2)/6)%10;
g<<uc<<"\n";

//punctul b)
long aux=x,p=1;
int nrcif=0,pc;
uc=x%10;
while(aux)
{
nrcif++;
p=p*10;
aux=aux/10;
}
p=p/10;
if(x>1)
{
CAPITOLUL 14. OJI 2010 14.2. TREN 173

if(nrcif-1==uc)
for(i=1;i<=nrcif+1;i++)
g<<i;
else
g<<(x%p)*10+x/p;
}
else
g<<"12";

g<<"\n";

//punctul c)

if(b<=a)
g<<"0";
else
g<<b-a;
return 0;
}

Listing 14.1.6: SIRVECT.CPP


//autor. prof Carmen Minca - Bucuresti

#include <fstream>

using namespace std;

int main()
{ long x; int v[10];
int k,i,s=0,a,b;

ifstream f("sir.in");
ofstream g("sir.out");

f>>k>>x>>a>>b;

for(s=1,i=2;i<=k;i++)
s=(s+i*(i+1)/2)%10;
g<<s<<endl;

k=0;
while(x)
{
k++; v[k]=x%10; x=x/10;
}

if(v[k]==k)
for(i=1;i<=k+1;i++)
g<<i;
else
{ v[0]=v[k];
for(i=k-1;i>=0;i--)
g<<v[i];
}

if(a<b)g<<endl<<b-a;
else g<<endl<<0;

g.close();

return 0;
}

14.1.3 *Rezolvare detaliată

14.2 tren
Problema 2 - tren 100 de puncte
CAPITOLUL 14. OJI 2010 14.2. TREN 174

Un elev ı̂n clasa a V-a, Rareş, s-a gândit să studieze mersul trenurilor ce trec prin gara din
oraşul său, ı̂ntr-o zi. Gara are 2 linii, numerotate cu 1 şi 2, pe care sosesc şi pleacă trenurile. În
acea zi, ı̂n gară sosesc T trenuri. Pentru fiecare tren din cele T , Rareş cunoaşte linia L pe care
va sosi, momentul sosirii, adică ora H şi minutul M , precum şi durata de timp S de staţionare
(exprimată ı̂n minute). El a decis ca perioada de studiu a celor T trenuri să ı̂nceapă cu momentul
sosirii primului tren ı̂n gară din cele T şi să se ı̂ncheie odată cu momentul plecării ultimului tren
din cele T .
Din sala de aşteptare Rareş poate vedea cele 2 linii. Rareş are ı̂nsă o problemă: atunci când
un tren se află ı̂n gară pe linia 1, el nu poate vedea trenul staţionat ı̂n acelaşi timp pe linia 2.
De exemplu, dacă un tren ajunge ı̂n gară pe linia 1 la ora 14  21 şi staţionează 5 minute atunci
trenul va pleca din gară la ora 14  26. Astfel, ı̂n intervalul de timp 14  21  14  26, Rareş nu
poate vedea ce se ı̂ntâmplă pe linia 2. Trenul de pe linia 2 va putea fi vizibil ı̂ncepând cu minutul
următor, adică de la 14  27.

Cerinţe

Scrieţi un program care să determine pentru un număr T de trenuri care trec prin gară ı̂n
perioada de studiu din acea zi:
a numărul maxim de trenuri Z care au staţionat pe aceeaşi linie;
a numărul X de trenuri pe care Rareş le vede;
a durata de timp maximă Y (exprimată ı̂n număr de minute consecutive), din perioada de
studiu, ı̂n care Rareş nu a văzut niciun tren.

Date de intrare

Fişierul de intrare tren.in conţine pe prima linie numărul T de trenuri şi pe fiecare din
următoarele T linii, ı̂n ordinea sosirii trenurilor ı̂n gară, câte patru numere naturale L, H, M
şi S, separate prin câte un spaţiu, ce reprezintă linia L pe care soseşte trenul, momentul sosirii
trenului (ora H şi minutul M ) şi durata de timp S de staţionare.

Date de ieşire

Fişierul de ieşire tren.out conţine pe prima linie, separate prin câte un spaţiu, valorile cerute
Z, X şi Y (ı̂n această ordine).

Restricţii şi precizări

- 2 & T & 100; 0 & H & 23; 0 & M & 59; 1 & S & 9; T , H, M , S sunt numere naturale;
- ı̂n acelaşi moment de timp nu pot pleca/sosi mai multe trenuri;
- ı̂n acelaşi moment de timp nu poate pleca un tren şi altul să sosească;
- pe aceeaşi linie nu pot staţiona mai multe trenuri ı̂n acelaşi moment de timp;
- pentru aflarea corectă a numărului Z se acordă 20% din punctajul pe test;
- pentru aflarea corectă a numărului X se acordă 40% din punctajul pe test;
- pentru aflarea corectă a numărului Y se acordă 40% din punctajul pe test.

Exemple

tren.in tren.out Explicaţii


CAPITOLUL 14. OJI 2010 14.2. TREN 175

8 5 5 11 Pe linia 1 au staţionat 3 trenuri, iar pe linia 2 au staţionat 5 trenuri,


1 14 20 3 astfel Z 5. La ora 14  20 Rareş vede trenul care ajunge pe linia 1
2 14 21 1 şi va staţiona până la ora 14  23. El nu vede trenul care ajunge pe
2 14 24 4 linia 2 la ora 14  21 şi pleacă la 14  22. El vede trenul care ajunge pe
1 14 40 8 linia 2 la 14  24 pentru că ı̂n momentul sosirii nu se află tren pe linia
2 14 41 1 1. De asemenea, el vede trenul care ajunge la 14  40 pe linia 1, dar
2 14 43 1 nu vede următoarele 2 trenuri care ajung pe linia 2 ı̂ntrucât trenul de
2 14 45 5 pe linia 1 pleacă la 14  48. Vede şi ultimul tren de pe linia 2 pentru
1 14 56 1 că el soseşte ı̂nainte de plecarea trenului de pe linia 1 şi pleacă după
acesta. ı̂n total a văzut 5 trenuri.
ı̂n intervalele de timp 14  29  14  39 şi 14  51  14  55,
Rareş nu vede niciun tren, durata de timp maximă fiind de 11 minute
(determinată de trenul care pleacă la 14  28 şi următorul tren care
soseşte la 14  40).

Timp maxim de executare/test: 1.0 secunde

14.2.1 Indicaţii de rezolvare


prof. Cristina Sichim, Colegiul National Ferdinand- Bacau

a) Solutia cu vectori retine in vectorul g starea fiecarui minut de pe parcursul unei zile.
In fiecare moment Rares vede cel mult un tren.
Vectorul v, retine starea fiecarui tren care a trecut prin gara.

# include <fstream.h>
ifstream fi("tren.in"); ofstream fo("tren.out");
int x,t,y,z,u,t1,l,h,m,s,i,j,vine,pleaca,g[1441],v[101],inc=1441,sf;

void main()
{ fi>>t;
for(i=1;i<=t;i++)
{ fi>>l>>h>>m>>s;
vine=h*60+m;pleaca=vine+s;
if(i==1)inc=vine;
if(sf<pleaca) sf=pleaca;
if(l==1) { t1++; for(j=vine;j<=pleaca;j++)g[j]=i;}
else
for(j=vine;j<=pleaca;j++)if(g[j]==0)g[j]=i;
//trenul de pe linia 2 este vizibil numai daca nu avem tren pe linia 1
}

z=(t1>t-t1)?t1:t-t1; //numarul maxim de trenuri de pe o linie


y=0;
for(i=inc;i<=sf;i++)
{ v[g[i]]=1; //trenul care se afla in momentul i in gara este vizibil
if(g[i]==0) u++; //u=numarul de minute consecutive in care
//ambele linii sunt libere
else { if(u>y)y=u;
u=0;
}
}
x=0;
for(i=1;i<=t;i++) x=x+v[i];
fo<<z<<’ ’<<x<<’ ’<<y;
fi.close();fo.close();
}

b) Solutia fara vectori memoreaza in t1 numarul de trenuri care ajung pe linia 1 si actualizeaza
pentru fiecare tren sosit valorile x, y si z. Un tren care ajunge pe linia 1 va fi intotdeauna vizibil.
CAPITOLUL 14. OJI 2010 14.2. TREN 176

Un tren care ajunge pe linia 2 va fi vizibil daca in timpul stationarii exista cel putin un minut in
care linia 1 nu este ocupata.
Pentru determinarea intervalului maxim in care ambele linii sunt libere trebuie sa calculam
cea mai mare diferenta dintre momentul in care a plecat un tren si a sosit altul si in tot acest timp
liniile au fost libere.

# include <fstream.h>

ifstream f("tren.in");
ofstream g("tren.out");

int x=1,t,y,z,t1,l,h,m,sta,s,p,am2,i,p1,p2,u;

void main()
{ f>>t;
f>>l>>h>>m>>sta;
u=h*60+m+sta;
if(l==1) t1++,p1=u;
else p2=u;
for(i=2;i<=t;i++)
{ f>>l>>h>>m>>sta;
s=h*60+m; p=s+sta; //s-momentul sosirii, p-momentul plecarii
if(s-u>y) y=s-u;
if(s>p1+1 && am2==1 && p2>p1) x++,am2=0;
// vad trenul care se afla acum pe linia 2
if(l==1) x++,t1++,p1=p;
else
if (s>p1) x++,am2=0,p2=p;
// vine un tren pe linia 2 si linia 1 este libera
else
if (p>p1) p2=p,am2=1;
// vine un tren pe linia 2 si linia 1 este ocupata
u=(p1>p2)?p1:p2;
}

if(am2)x++;

z = (t1>t-t1) ? t1 : t-t1;

if(y) y--;

g<<z<<’ ’<<x<<’ ’<<y;

f.close();
g.close();
}

14.2.2 Cod sursă

Listing 14.2.1: Ana.CPP


#include <fstream>
#include<math.h>

using namespace std;

int timp[1382];
int t,i,j,l,h,m,s,x,y,z,nrt1,nrt2,ts,tp,tmp;

ifstream f("tren.in");
ofstream g("tren.out");
CAPITOLUL 14. OJI 2010 14.2. TREN 177

int main()
{
f>>t;
for(i=1;i<=t;i++)
{
f>>l>>h>>m>>s;
if(l==1) nrt1++;
else nrt2++;
ts=h*60+m;tp=ts+s;
for(j=ts;j<=tp;j++)
if(l==1) timp[j]=i;
else if(l==2 && timp[j]==0) timp[j]=i;
}

//b)
for(i=1;i<=1381;i++)
if(timp[i]!=timp[i-1] && timp[i]!=0) x++;

//c)
i=0;while(timp[i]==0) i++;
for(;i<=1381;i++)
if(timp[i]==0) tmp++;
else
{
if(tmp>y) y=tmp; tmp=0;
}
z=(nrt1+nrt2+abs(nrt1-nrt2))/2;
g<<z<<" "<<x<<" "<<y;

f.close();
g.close();
return 0;
}

Listing 14.2.2: Carmen.CPP


#include <fstream>

using namespace std;

ifstream fi("tren.in");
ofstream fo("tren.out");
long lin[1441];

int main()
{ long t,z,x,y,h,m,s,i,os,op,l;
fi>>t;
long n1,n2,j,pi=1441,pf=0;
n1=0; n2=0;

for(i=1;i<=t;i++)
{
fi>>l>>h>>m>>s;
os=h*60+m;
op=os+s;
if(pi>os)pi=os;
if(pf<op)pf=op;
if(l==1)n1++; else n2++;

for(j=os;j<=op;j++)
{ if(l==1) lin[j]=lin[j]+n1;
else lin[j]=n2*1000+lin[j];
}
}

z=n1;
if(z<n2) z=n2;
y=0;
x=0;
long val=lin[pi],t1,t2;
unsigned long d=0;
t1=t2=0;
i=pi;
CAPITOLUL 14. OJI 2010 14.2. TREN 178

while(i<=pf)
{
if(lin[i]==0){i++;d++;}
else
{ val=lin[i];
if(val%1000)
{ if(t1!=val%1000)
{
t1=val%1000;
x++;
}
if((lin[i]%1000==val%1000)&&(i<=pf))i++;
}
else
{ if(t2!=val/1000)
{
t2=val/1000;
x++;
}
if((lin[i]/1000==val/1000)&&(val%1000==0)&&(i<=pf))i++;
}

if(d>y)y=d;
d=0;
}
}

fo<<z<<’ ’<<x<<’ ’<<y;

fo.close();
fi.close();

return 0;
}

Listing 14.2.3: Cris1.CPP


# include <fstream>

using namespace std;

ifstream f("tren.in");
ofstream g("tren.out");

int x=1,t,y,z,t1,l,h,m,sta,s,p,am2,i,p1,p2,u;
int main()
{ f>>t;
f>>l>>h>>m>>sta;
u=h*60+m+sta;
if(l==1) t1++,p1=u;
else p2=u;

for(i=2;i<=t;i++)
{
f>>l>>h>>m>>sta;
s=h*60+m; p=s+sta;
if(s-u>y) y=s-u;
if(s>p1+1 && am2==1 && p2>p1) x++,am2=0;
if(l==1) x++,t1++,p1=p;
else if (s>p1) x++,am2=0,p2=p;
else if (p>p1) p2=p,am2=1;

u=(p1>p2)?p1:p2;
}

if(am2)x++;
z=(t1>t-t1)?t1:t-t1;
if(y)y--;

g<<z<<’ ’<<x<<’ ’<<y;

f.close();
g.close();
return 0;
}
CAPITOLUL 14. OJI 2010 14.2. TREN 179

Listing 14.2.4: Cris2.CPP


# include <fstream>

using namespace std;

ifstream fi("tren.in");
ofstream fo("tren.out");

int x,t,y,z,u,t1,l,h,m,s,i,j,vine,pleaca,g[1441],v[101],inc=1441,sf;

int main()
{ fi>>t;

for(i=1;i<=t;i++)
{ fi>>l>>h>>m>>s;
vine=h*60+m;pleaca=vine+s;
if(i==1)inc=vine;
if(sf<pleaca) sf=pleaca;
if(l==1) { t1++; for(j=vine;j<=pleaca;j++)g[j]=i;}
else for(j=vine;j<=pleaca;j++)if(g[j]==0)g[j]=i;
}

z=(t1>t-t1) ? t1:t-t1;

y=0;
for(i=inc;i<=sf;i++)
{ v[g[i]]=1;
if(g[i]==0) u++;
else
{
if(u>y)y=u;
u=0;
}
}

x=0;
for(i=1;i<=t;i++) x=x+v[i];

fo<<z<<’ ’<<x<<’ ’<<y;

fi.close();
fo.close();
return 0;
}

Listing 14.2.5: Cris3.CPP


# include <fstream>

using namespace std;

ifstream f("tren.in");
ofstream g("tren.out");

int x,t,y,z,u,t1,l,h,m,s,i,j,vine,pleaca,l1[1441],l2[1441],v[101],inc=1441,sf;

int main()
{ f>>t;

for(i=1;i<=t;i++)
{ f>>l>>h>>m>>s;
vine=h*60+m;pleaca=vine+s;
if(inc>vine) inc=vine;
if(sf<pleaca) sf=pleaca;
if(l==1) { t1++; for(j=vine;j<=pleaca;j++)l1[j]=i;}
else for(j=vine;j<=pleaca;j++)l2[j]=i;
}

z=(t1>t-t1) ? t1 : t-t1;

y=0;
for(i=inc;i<=sf;i++)
{ v[l1[i]]=1;
if(l1[i]==0)v[l2[i]]=1;
CAPITOLUL 14. OJI 2010 14.2. TREN 180

if(l1[i]+l2[i]==0) u++;
else
{
if(u>y)y=u;
u=0;
}
}

x=0;
for(i=1;i<=t;i++) x=x+v[i];
g<<z<<’ ’<<x<<’ ’<<y;

f.close();
g.close();
return 0;
}

Listing 14.2.6: Dana.cpp


#include<fstream>

using namespace std;

ifstream f("tren.in");
ofstream g("tren.out");

int t,l,h,m,s;
int nr1,nr2,z,gasit,ultim;
int tp,x;
int maxx,y,timpc,poz;

int main()
{
int i;
f>>t;
for(i=1;i<=t;i++)
{
f>>l>>h>>m>>s;
/*Daca exista un tren pe linia 2, iar pe linia 1 sosesc trenuri
la interval de o secunda unul de altul, trenul de pe linia 2 nu se vede
si deci va fi scazut din numaratoare (o singura data!: ultim=tp;)
ultim reprezinta timpul de plecare din statie al trenului de pe linia 2*/
if(gasit)
{
gasit=0;
x--;
ultim=tp;
}
if(l==1)
{
nr1++;
x++;
if(ultim>h*60+m && h*60+m-tp==1 && i>1)
gasit=1;
tp=h*60+m+s;
}
else
{
nr2++;
if(h*60+m>tp||h*60+m+s>tp)
{
x++;
ultim=h*60+m+s;
}

}
if(h*60+m>maxx)
{
timpc=h*60+m-maxx;
maxx=h*60+m+s+1;
if(timpc>y && i>1) y=timpc;
}
else
if(h*60+m+s>maxx)
maxx=h*60+m+s+1;
CAPITOLUL 14. OJI 2010 14.2. TREN 181

if(nr1>nr2) z=nr1; else z=nr2;

g<<z<<" "<<x<<" "<<y;

return 0;
}

14.2.3 *Rezolvare detaliată


Part II

ONI - Olimpiada naţională de


informatică

182
Capitolul 15

ONI 2023

15.1 cadouri
Problema 1 - Cadouri 100 de puncte
Înaintea vacanţei de Paşte, la şcoală, s-au primit cadouri pentru elevii din clasa a V-a. Sunt
N cutii cu bomboane şi se cunoaşte numărul de bomboane din fiecare cutie. Numărul de cutii
de bomboane primite de fiecare copil trebuie să fie acelaşi. Acest număr trebuie să
fie mai mare sau egal cu 2.
Cutiile cu bomboane vor fi oferite ı̂n ordinea primirii, primele cutii primului copil, următoarele
cutii celui de al doilea copil, următoarele cutii celui de al treilea copil etc.
Se doreşte să se ı̂mpartă cutiile cu bomboane unui număr cât mai mare de copii. De asemenea,
mai este o condiţie: să se ı̂mpartă copiilor toate cutiile, sau cel mult una dintre cutii să rămână
neoferită.
În cazul că se ia decizia ca o cutie să nu fie dată copiilor, aceasta se păstrează de către doamna
dirigintă pentru a-i servi pe aceştia la ı̂ntoarcerea la şcoală, iar restul cutiilor cu bomboane se pun
pe catedră ı̂n ordinea ı̂n care au fost primite, fără ca elevii să ştie despre cea păstrată.
Alegerea acestei cutii trebuie făcută astfel ı̂ncât numărul total de bomboane care se
ı̂mpart să fie cât mai mare.

Cerinţe

1. Care este numărul maxim de copii care vor primi cadouri?


2. Care este numărul maxim posibil de bomboane pe care le poate primi un copil ı̂n condiţiile
descrise mai sus?

Pentru ambele cerinţe trebuie determinat şi numărul de bomboane din cutia care eventual se
păstrează.

Date de intrare

Fişierul de intrare cadouri.in conţine pe prima linie un număr C, indicând cerinţa.


Pe linia a doua se află un număr N , reprezentând numărul de cutii de bomboane primite la
şcoală. Pe linia a treia se află N numere, separate prin câte un spaţiu, reprezentând numărul de
bomboane din fiecare cutie, ı̂n ordinea ı̂n care acestea au fost primite.

Date de ieşire

Fişierul de ieşire cadouri.out conţine două numere naturale, separate printr-un singur spaţiu
liber, cu următoarea semnificaţie: pentru C = 1 prima valoare este numărul maxim de copii care
primesc cadouri iar a doua este numărul de bomboane din cutia păstrată; pentru C = 2 prima
valoare este numărul maxim de bomboane primite de un copil iar a doua reprezintă numărul de
bomboane din cutia păstrată.
Dacă nu se păstrează nicio cutie, ı̂n fişierul de ieşire a doua valoare scrisă va fi 0 (atât ı̂n cazul
cerinţei 1 cât şi ı̂n cazul cerinţei 2).

183
CAPITOLUL 15. ONI 2023 15.1. CADOURI 184

Restricţii şi precizări

ˆ 2 & N & 100 000.


ˆ Numerele de pe linia a treia sunt naturale, nenule, formate din cel mult 9 cifre.

# Punctaj Restrictii
1 23 C=1
2 77 C=2

Exemple:

cadouri.in cadouri.out Explicaţii


1 21 Se rezolvă cerinţa 1. Doi copii primesc cadouri. Cutia cu o
5 bomboană nu este dată niciunui copil.
27412
2 91 Se rezolvă cerinţa 2. Doi copii primesc cadouri, primul copil
5 primeşte cutiile cu 2 şi 7 bomboane, iar al doilea copil primeşte
27412 cutiile cu 4 şi 2 bomboane. Deci primul copil primeşte număr
maxim de bomboane, 9. Cutia cu o bomboană nu este dată nici
unui copil.

15.1.1 Indicaţii de rezolvare

Propusa de: prof. Nicoli Marius, Colegiul Naţional Fraţii Buzeşti, Syncro Soft Craiova
Notăm cu n numărul de cutii primite la şcoală. Pentru a oferi cadouri la un număr maxim de
elevi se vor distribui câte două cutii fiecăruia. Dacă numărul de cutii este impar este necesar să
se păstreze una dintre ele. Pentru a asigura distribuirea unui număr total maxim de bomboane,
cutia păstrată trebuie să fie una cu număr minim de bomboane.
Pentru cerinţa 1. Este necesară determinarea valorii minime din şirul dat şi se afişează
valorile n©2 şi acest minim.
Pentru cerinţa 2. Dacă n este par se vor distribui toate cutiile iar soluţia este maximul din
şirul de sume de câte două elemente consecutive, v 1  v 2, v 3  v 4, ... (am notat cu v şirul
dat la intrare).
Pentru cazul cu n impar apar două situaţii care trebuie analizate.
Dacă valoarea minimă din şir este pe poziţie impară, maximul care poate fi dat unui copil
se poate obţine fie dintre valorile v 1  v 2, v 3  v 4, ... formate ı̂nainte de poziţia apariţiei
minimului fie dintre valorile v n  v n  1, v n  2  v n  3 formate după poziţia apariţiei
minimului.
Dacă minimul este pe o poziţie pară (să o notăm ı̂n continuare cu p o poziţie unde se află
minimul), trebuie să mai luâm ı̂n calcul şi valoarea v p  1  v p  1.
Întrucât elementele şirului dat nu sunt distincte, se observă că şi minimul poate apărea de mai
multe ori. Astfel, trebuie realizate cele prezentate mai sus pentru fiecare poziţie unde se găseşte
un element cu valoarea minimă (notăm mai departe cu p o astfel de poziţie).
O abordare care şterge ı̂n mod repetat elementul de pe o poziţie p şi aplică strategia descrisă
pentru cazul cu n par nu se ı̂ncadrează ı̂n timp pe toate testele.
Pentru a obţine un program care rulează mai rapid vom calcula un şir (notat ms) care la
poziţia i curentă memorează cea mai mare sumă a unei valori de forma v 1  v 2, v 3  v 4, ...
cu indici mai mici decât i precum şi un alt şir (notat md) care memorează rezultatele unui calcul
similar din dreapta: la pozit,ia curentă se află maximul sumelor de câte două elemente din perechi
de forma v n  v n  1, v n  2  v n  3, cu indici mai mari ca poziţia curentă. Astfel, la
fiecare poziţie p unde se află un element cu valoare minimă este suficient să luăm ı̂n calcul valorile
msp  1, mdp  1 (dacă p este impar), respectiv msp  2, mdp  2 şi v p  1  v p  1
(dacă p este par).
CAPITOLUL 15. ONI 2023 15.1. CADOURI 185

15.1.2 Cod sursă

Listing 15.1.1: 5 cadouri.cpp


#include <fstream>

using namespace std;

int c, n, minim, i, s, d, sol;

int v[100010], ms[100010], md[100010];

int main ()
{
ifstream fin ("cadouri.in");
ofstream fout("cadouri.out");

fin>>c>>n;

minim = 2000000000;
for (i=1;i<=n;i++)
{
fin>>v[i];
if (v[i] < minim) minim = v[i];
}

for (i=2;i<=n;i+=2)
{
s = v[i] + v[i-1];
ms[i] = max(ms[i-2], s);
}

for (i=n-1;i>=1;i-=2)
{
d = v[i] + v[i+1];
md[i] = max(md[i+2], d);
}

if (c == 1) { fout<<n/2<<" "; }
else
{
if (n%2 == 0) fout<<ms[n]<<" ";
else
{ /// n impar
for (i=1;i<=n;i++)
{
if (v[i] == minim)
{
if (i%2 == 1)
{
/// minim pe pozitie impara
sol = max(sol, ms[i-1]);
sol = max(sol, md[i+1]);
}
else
{
sol = max(sol, v[i-1]+v[i+1]);
sol = max(sol, ms[i-2]);
sol = max(sol, md[i+2]);
}
}
}
fout<<sol<<" ";
}
}

if (n%2 == 1) fout<<minim<<"\n"; else fout<<"0\n";


return 0;
}

15.1.3 *Rezolvare detaliată


CAPITOLUL 15. ONI 2023 15.2. LEGOS 186

15.2 legos
Problema 2 - Legos 100 de puncte
Un joc de lego are P piese care sunt cuburi identice. Dorel se joacă cu ele pentru a construi
diverse jucării, dar pentru aceasta are nevoie de ajutorul vostru.

Cerinţe

Cunoscându-se numărul de piese P pe care le are, Dorel vrea să ştie:


1. Numărul de piese din care poate să construiască cea mai mare fundaţie. O fundaţie are
forma unui pătrat şi are latura formată din cel puţin 3 piese (ca ı̂n figura 1).

Figura 15.1: (Figura 1) O fundaţie de mărime 6 x 6

2. Numărul de piese din cel mai ı̂nalt turn care se poate construi. Un turn din piese de lego
Dorel ı̂l construieşte astfel:
La ı̂nceput va face un pătrat pe care ı̂l numeşte parter (sau etajul 0). Peste acesta va pune 4
piese ı̂n colt,uri pe care le numeşte piloni. Apoi, peste piloni, va pune un nou pătrat pe care ı̂l
numeşte etaj 1.
Peste acesta va pune din nou piloni, peste care va pune etajul 2. şi va continua, până la ultimul
etaj.
Peste ultimul etaj nu pune piloni.
Toate etajele construite au acelaşi număr de piese şi au forma de pătrat cu latura de cel puţin 3
piese. Înălţimea unui turn este dată de numărul de etaje. Pilonii nu sunt consideraţietaje, aceştia
fac parte din structura turnului. Dacă se pot construi mai multe turnuri având aceeaşi ı̂nălţime,
atunci Dorel vrea să ştie numărul de piese al turnului cu cele mai multe piese.(Vezi figura 2).

Figura 15.2: (Figura 2) Un turn de ı̂nalţime 3, fiecare etaj are mărimea 5 x 5

3. Numărul de terenuri de legoball care se pot construi folosind toate piesele de lego. Un teren
de legoball are forma unui dreptunghi ı̂n care fiecare latură este formată din cel puţin 3 piese (ca
ı̂n figura 3).
CAPITOLUL 15. ONI 2023 15.2. LEGOS 187

Figura 15.3: (Figura 3) Un teren de legoball de mărime 6 x 3.

Date de intrare

Fişierul legos.in conţine două numere naturale nenule C şi P , separate printr-un singur spaţiu
liber, reprezentând cerinţa respectiv numărul de piese de lego pe care le are Dorel.

Date de ieşire

Pentru fiecare din cele 3 cerinţe fişierul legos.out va conţine un singur număr care reprezintă
răspunsul la acea cerint,ă.

Restricţii şi precizări

ˆ 1&C&3
ˆ 1 & P & 1 000 000 000
ˆ Pentru cerinţa 2 un turn poate fi format doar din parter, dar nu poate fi format din parter
şi piloni (deoarece ar avea piloni peste ultimul etaj).

# Punctaj Restricţii
1 31 C=1
2 33 C=2
3 36 C=3

Exemple:

legos.in legos.out Explicaţii


1 29 25 Se rezolvă cerinţa 1. Sunt 29 piese de lego. Cea mai mare
fundaţie ce poate fi construită are dimensiunea 5 x 5, este for-
mată din 25 de piese.
2 19 16 Se rezolvă cerinţa 2. Sunt 19 piese de lego. Cel mai ı̂nalt turn
care poate fi făcut este format doar din parter. Există două
astfel de turnuri, unul are 9 piese iar celălalt 16. Dintre acestea
mai multe sunt ı̂n turnul de 16 piese.
3 18 2 Se rezolvă cerinţa 3. Sunt două moduri de a construi un teren
de legoball. Acestea au dimensiunile 3 x 6, respectiv 6 x 3.

15.2.1 Indicaţii de rezolvare

Propusa de: stud. Ilie Dumitru, Universitatea din Bucureşti, Bucureşti


Pentru cerinţa 1 se determină cel mai mare pătrat perfect mai mic decât P .
Pentru a face asta vom itera până când pătratul numărului iterat depăşeşte P .
Acesta este primul pătrat perfect mai mare decât P , ceea ce ı̂nseamnă că precedentul este
răspunsul.
Pentru cerinţa 2 se observă că cel mai ı̂nalt turn se obţine atunci când fiecare etaj are
dimensiunea 3 x 3 sau atunci când fiecare etaj are dimensiunea 4 x 4. O soluţie este să iterăm
numărul de etaje şi să ne oprim atunci când numărul de piese depăşeşte P .
CAPITOLUL 15. ONI 2023 15.2. LEGOS 188

Pentru a optimiza această soluţie se face observaţia adiţională că numărul de piese este de
forma 9  13 nrEtaje  1.
Din aceasta se obtine formula generală a numărului de etaje din cel mai ı̂nalt turn şi apoi
formula pentru numărul de piese din cel mai ı̂nalt turn cu etaje de mărime 3 x 3. Se repetă
raţionamentul pentru 4 x 4.
Pentru cerinţa 3 trebuie să numărăm ı̂n câte moduri poate fi scris P ca produs de două
numere cu menţiunea că nici unul dintre numere să nu fie mai mic decât 3.
Optimizarea este similară cu cea pentru verificarea primalităţii unui număr, vom itera până
când d * d depăşeşte P .
Pentru fiecare divizor vom adăuga 2 la răspuns (corespunzător pentru d x Pd şi Pd x d), cu
menţiunea că dacă divizorul ridicat la puterea a doua este P se va adauga doar 1 la răspuns (Pd
= d deci cele două moduri sunt la fel, d x d şi d x d).

15.2.2 Cod sursă

Listing 15.2.1: 5 legos.cpp


#include<cstdio>

int main()
{
FILE* f=fopen("legos.in", "r");
FILE* g=fopen("legos.out", "w");

int c, P, i, ans=0;

fscanf(f, "%d%d", &c, &P);

if(c==1)
{
for(i=3;i*i<=P;++i);
fprintf(g, "%d\n", (i-1)*(i-1));
}
else if(c==2)
{
if(P<16)
fprintf(g, "%d\n", 9);
else if(P<22)
fprintf(g, "%d\n", 16);
else
fprintf(g, "%d\n", (P-9)/13*13+9);
}
else
{
for(i=3;i*i<P;++i)
if(P%i==0)
ans+=2;
if(i*i==P)
++ans;

fprintf(g, "%d\n", ans);


}

fclose(f);
fclose(g);

return 0;
}

15.2.3 *Rezolvare detaliată


CAPITOLUL 15. ONI 2023 15.3. PATINAJ 189

15.3 patinaj
Problema 3 - Patinaj 100 de puncte
Clubul Sportiv SEPI are şi o secţie de patinaj artistic. Conducerea clubului şi-a propus să
participe la proba de perechi a următoarei olimpiade şi are de luat unele decizii privind echipele
pe care le poate ı̂nscrie.
Fiecare echipă participantă la olimpiadă trebuie să fie formată dintr-o pereche de patinatori
(o fată şi un băiat) şi un antrenor. În plus, valorile membrilor unei echipe trebuie să fie cât mai
apropiate.
Valoarea unui sportiv şi respectiv a unui antrenor este calculată pe baza rezultatelor obţinute
la competiţiile anterioare. Acestea sunt codificate sub forma unui singur număr cu cel mult 9 cifre.
Fiecare cifră a numărului reprezintă un rezultat anterior, iar suma cifrelor reprezintă val-
oarea sportivului, respectiv antrenorului.
De exemplu, numărul 18305 codifică rezultatele 1, 8, 3, 0, 5, obţinute la ultimele 5 concursuri,
ceea ce corespunde valorii 17 (= 1 + 8 + 3 + 0 + 5).
La olimpiadă fiecare sportiv şi fiecare antrenor poate să facă parte din cel mult o echipă ı̂nscrisă.
În plus, pentru fiecare echipă, dacă notăm cu VM maximul dintre valorile antrenorului, fetei şi
băiatului şi cu Vm minimul dintre valorile antrenorului, fetei şi băiatului, ı̂nscrierea ı̂n concurs este
permisă doar dacă VM  Vm & 1.

Cerinţe

Cunoscând numerele care codifică rezultatele antrenorilor, fetelor şi băieţilor, scrieţi un pro-
gram care să determine:

1. Numărul maxim de echipe, NP , pe care le poate ı̂nscrie Clubul Sportiv SEPI la olimpiadă
astfel ı̂ncât acestea să respecte regulile de mai sus.
2. Valoarea maximă, V , a unui antrenor al clubului care poate antrena o pereche de patinatori
(fată, băiat), ce poate fi ı̂nscrisă la olimpiadă conform regulilor de mai sus şi numărul de
variante NV ı̂n care se poate alege o echipă care poate fi pregătită de un antrenor de valoare
V.

Date de intrare

Fişierul text patinaj.in conţine:


ˆ pe prima linie numărul natural C care reprezintă numărul cerint, ei şi poate avea una dintre
valorile 1 sau 2;
ˆ pe cea de-a doua linie, un număr natural N , care reprezintă atât numărul antrenorilor
angajaţi, cât şi al fetelor şi al băieţilor legitimaţi la club;
ˆ pe fiecare dintre următoarele trei linii câte N valori, despărţite prin câte un spaţiu.
Pe cea de-a treia linie, acestea reprezintă codificările rezultatelor anterioare ale celor N
antrenori, pe cea de-a patra linie ele reprezintă codificările rezultatelor anterioare ale celor
N fete, iar valorile de pe cea de-a cincea linie reprezintă codificările rezultatelor anterioare
ale celor N băieţi.

Date de ieşire

În fişierul text patinaj.out se va afişa:


ˆ pentru cerinţa 1: numărul maxim de echipe NP care pot fi ı̂nscrise la olimpiadă conform
regulilor precizate mai sus;
ˆ pentru cerinţa 2: două numere naturale, V şi NV , separate printr-un spaţiu, reprezentând
valoarea maximă a unui antrenor al clubului pentru care există cel puţin o pereche pe care o
poate antrena şi respectiv numărul variantelor ı̂n care clubul poate alege o echipă care poate
fi pregătită de un antrenor cu valoarea V , dacă se rezolvă cerinţa 2.
În cazul ı̂n care clubul nu poate ı̂nscrie nicio pereche, se va afişa un singur număr: -1.
CAPITOLUL 15. ONI 2023 15.3. PATINAJ 190

Restricţii şi precizări

ˆ 1 & N & 100 000


ˆ fiecare dintre numerele citite de pe a treia, a patra şi a cincea linie e fişierului este un număr
natural cu cel mult 9 cifre.
# Punctaj Restrictii
1 51 C = 1
2 49 C = 2

Exemple:

patinaj.in patinaj.out Explicaţii


1 2 Se pot forma cel mult 2 echipe.
4 Prima ar putea fi formată din fata cu codificarea
8093 18305 20009 188 1803 şi băiatul cu codificarea 20009 şi pregătită de
1803 3303331 909 91995 antrenorul cu codificarea 20009. A doua poate fi for-
8017 20009 0 8017 mată din fata 3303331, băiatul 8017 şi pregătită de
antrenorul 18305.
2 17 4 Clubul are 4 antrenori cu valorile 20 = 8 + 0 + 9 +
4 3, 17 = 1 + 8 + 3 + 0 + 5, 11 = 2 + 0 + 0 + 0 + 9
8093 18305 20009 188 şi 17 = 1 + 8 + 8.
1803 3303331 909 91995 Valoarea maximă este 20, dar nu există o pereche
8017 20009 0 8017 pe care să o poată pregăti antrenorul cu valoarea 20
conform regulilor impuse. În schimb, un antrenor
cu valoarea 17 ar putea pregăti o pereche ı̂nscrisă la
olimpiadă.
Sunt 4 variante de alegere a unei echipe pregătite de
un antrenor cu valoarea 17.
Acestea ar putea avea ı̂n component,ă fata 3303331
şi unul dintre cei doi băieţicu codificarea rezultatelor
anterioare 8017.
O astfel de pereche ar putea fi pregătită de antrenorul
18305 sau de 188.

15.3.1 Indicaţii de rezolvare

Propusa de:
prof. Manz Victor-Claudiu, Colegiul Naţional de Informatică Tudor Vianu, Bucureşti
Prima observaţie importantă este că, deşi codificările rezultatelor anterioare pot fi numere
destul de mari, valorile asociate sunt cuprinse ı̂ntre 0 (suma cifrelor lui 0 este 0) şi 81 (suma
cifrelor lui 999999999 este 81). Prin urmare, putem construi vectorii de frecvenţă nra asociat
valorilor antrenorilor, nrf asociat valorilor fetelor şi nrb asociat valorilor băieţilor.
Pentru cerinţa 1, pentru fiecare i cuprins ı̂ntre 0 şi 81 vom aduna la rezultat numărul
echipelor cu valoarea membrilor i sau i  1.
Pentru i cuprins ı̂ntre 0 şi 80 acest număr este min nrai  nrai  1, nrf i  nrf i 
1, nrbi  nrbi  1.
Pentru fiecare i este necesară actualizarea valorilor nrai  1, nrf i  1, nrbi  1, deoarece
atunci când numărăm echipele cu valoarea membrilor i + 1 sau i + 2 trebuie să excludem antrenorii
şi sportivii pe care i-am folosit deja ı̂n echipe luate ı̂n considerare la pasul i.
Pentru echipele cu valoarea tuturor membrilor 81 mai trebuie adunat
min nra81, nrf 81, nrb81.
Pentru cerinţa 2 vom parcurge valorile posibile ale antrenorilor şi vom determina cel mai
mare i cu proprietatea că există cel puţin un antrenor cu valoarea i şi există atât băieţi, cât şi fete
cu valori din mulţimea ri  1, ix sau există atât băieţi, cât şi fete cu valoari din mulţimea ri, i  1x.
CAPITOLUL 15. ONI 2023 15.3. PATINAJ 191

Dacă există un astfel de i, pe care ı̂l notăm cu i0, atunci putem forma echipe cu antrenori
de valoarea i0 luând (ı̂n toate modurile posibile) antrenori cu valoarea i0 şi sportivi cu valori
din mulţimea ri0  1, i0x sau luând antrenori cu valoarea i0 şi sportivi cu valori din mulţimea
ri0, i0  1x.

E nevoie de atenţie pentru a nu număra de două ori echipele ı̂n care toţimembrii au valoarea
exact i0.

15.3.2 Cod sursă

Listing 15.3.1: 5 patinaj.cpp


#include <fstream>

using namespace std;

const int VMAX = 81;

int nr_a[1 + VMAX], nr_f[1 + VMAX], nr_b[1 + VMAX];

int main()
{
ifstream in("patinaj.in");
ofstream out("patinaj.out");

int c, n;
in >> c >> n;

for (int i = 0; i < n; i++)


{
int x; in >> x;
int sc = 0;

do
{
sc += x % 10;
x /= 10;
}
while (x != 0);

nr_a[sc]++;
}

for (int i = 0; i < n; i++)


{
int x; in >> x;
int sc = 0;
do
{
sc += x % 10;
x /= 10;
}
while (x != 0);

nr_b[sc]++;
}// for i

for (int i = 0; i < n; i++)


{
int x; in >> x;
int sc = 0;

do
{
sc += x % 10;
x /= 10;
}
while (x != 0);

nr_f[sc]++;
}// for i
CAPITOLUL 15. ONI 2023 15.3. PATINAJ 192

if (c == 1)
{
int nr = 0;

for (int i = 0; i < VMAX; i++)


{
int minim = min(nr_a[i] + nr_a[i+1], nr_f[i] + nr_f[i+1]);

minim = min(minim, nr_b[i] + nr_b[i+1]);

nr += minim;

if (minim > nr_a[i])


nr_a[i+1] -= min(nr_a[i+1], minim - nr_a[i]);

if (minim > nr_f[i])


nr_f[i+1] -= min(nr_f[i+1], minim - nr_f[i]);

if (minim > nr_b[i])


nr_b[i+1] -= min(nr_b[i+1], minim - nr_b[i]);
}// for i

nr += min(nr_a[VMAX], min(nr_f[VMAX], nr_b[VMAX]));


out << nr << "\n";
}
else // c == 2
{
int v_max_a = -1;
long long nr_var = 0;

for (int i = 0; i <= VMAX; i++)


{
if (nr_a[i] == 0) continue;

bool exista_st = false, exista_dr = false;

long long nr_st = 0, nr_dr = 0;

if (i > 0 && nr_f[i] + nr_f[i-1] != 0 && nr_b[i] + nr_b[i-1] != 0)


{
exista_st = true;
nr_st = (long long)(nr_f[i]+nr_f[i-1]) * (nr_b[i]+nr_b[i-1]);
}

if (i < VMAX && nr_f[i]+nr_f[i+1] != 0 && nr_b[i]+nr_b[i+1] != 0)


{
exista_dr = true;
nr_dr = (long long)(nr_f[i]+nr_f[i+1]) * (nr_b[i]+nr_b[i+1]);
}

if (exista_st || exista_dr || (nr_f[i] != 0 && nr_b[i] != 0))


{
v_max_a = i;
nr_var=(nr_st+nr_dr)*nr_a[i]-
(long long)nr_a[i]*nr_f[i]*nr_b[i];
}
}// for i

out << v_max_a;

if (v_max_a != -1) out << " " << nr_var;

out << "\n";


} // c == 2

in.close();
out.close();

return 0;
}

15.3.3 *Rezolvare detaliată


Capitolul 16

ONI 2022

16.1 Culori
Problema 1 - Culori 100 de puncte
Pe o foaie a unui caiet de matematică sunt N rânduri de
pătrăţele pe care Andrei le-a numerotat de sus ı̂n jos cu valori
de la 1 la N . Pe fiecare rând, Andrei colorează unul sau mai
multe pătrăţele având la dispoziţie un set de 9 creioane de culori
diferite, culori ce sunt codificate cu valori distincte de la 1 la
9. Pentru fiecare rând al caietului, Andrei stabileşte un număr
de pătrăţele alăturate ce le va colora şi procedează astfel: alege
un creion cu care colorează primul pătrăţel (cel din stânga foii
sale), apoi procedează la fel pentru al doilea pătrăţel şi aşa mai
departe până termină de colorat numărul de pătrăţele stabilit de el pentru rândul respectiv (pot
exista două sau mai multe pătrăţele colorate la fel). Lungimea unui rând este astfel determinată
de numărul tuturor pătrăţelelor colorate de pe acel rând.

Cerinţe

Cunoscând numărul N de rânduri cu pătrăţele, numărul de pătrăţele colorate de pe fiecare


rând şi culoarea fiecărui pătrăţel, scrieţi un program care să determine:
1. Lmax si Kmax, două numere naturale, unde Lmax reprezintă lungimea maximă unui rând
ce are proprietatea că oricare două pătrăţele alăturate au culori diferite, iar Kmax reprezintă câte
astfel de rânduri sunt pe foaie.
2. Cel mai mare număr natural ce se poate forma prin lipirea tuturor cifrelor corespunzătoare
culorilor de pe acelaşi rând, parcurse de la stânga la dreapta.

Date de intrare

Fişierul culori.in conţine:


ˆ pe prima linie două numere naturale C şi N , unde C reprezintă numărul cerinţei şi poate
avea valorile 1 sau 2, iar N reprezintă numărul rândurilor din caiet colorate de Andrei;
ˆ pe fiecare din următoarele N linii, numere naturale despărţite prin câte un spaţiu. Fiecare
linie corespunde unui rând al foii de caiet, ı̂n ordinea numerotării rândurilor. Primul număr
de pe fiecare linie reprezintă numărul pătrăţelelor colorate de Andrei pe rândul respectiv, iar
apoi următoarele valori reprezintă codurile culorilor folosite pentru colorarea pătrăţelelor de
pe rândul respectiv, fiecare corespunzând câte unui pătrăţel, ı̂n ordine, ı̂ncepând cu primul
de pe acel rând (cel din stânga), până la ultimul de pe acel rând (cel din dreapta).

Date de ieşire

Fişierul culori.out va conţine pe prima linie:


ˆ pentru cerinţa 1, două numere naturale Lmax şi Kmax, ı̂n această ordine şi despărţite
printr-un spaţiu;
ˆ pentru cerinţa 2, un singur număr natural determinat conform cerinţei.

193
CAPITOLUL 16. ONI 2022 16.1. CULORI 194

Restricţii şi precizări

ˆ 1 & N & 10000;


ˆ 1 & numărul pătrăţelelor colorate de pe fiecare rând & 500;
ˆ pentru rezolvarea corectă a primei cerinţe se acordă 27 de puncte, iar pentru rezolvarea
corectă a celei de-a doua cerinţe se acordă 73 de puncte;
ˆ pentru teste ı̂n valoare de 10 puncte şi C = 2, caietul nu conţine două rânduri cu acelaşi
număr de pătrăţele colorate;
ˆ pentru teste ı̂n valoare de 23 puncte şi C = 2, numărul pătrăţelelor de pe fiecare rând este
mai mic sau egal cu 19.

Exemple:

culori.in culori.out Explicaţii


17 52 Primul exemplu corespunde desenului din imaginea de mai sus.
642311 1 Se va rezolva cerinţa 1. Rândurile 2, 5 şi 7 au proprietatea din
572393 cerinţă. Lungimea rândului 2 este 5, a rândului 5 este 1, iar a
244 rândului 7 este 5, deci lungimea maximă a unui rând este 5 şi
622717 7 sunt 2 rânduri de această lungime. Lmax = 5 şi Kmax = 2.
13
49999
572727
27 423111 In al doilea exemplu se va rezolva cerinţa 2. Numerele natu-
642311 1 rale construite din cifrele fiecărui rând sunt: 423111, 72393, 44,
572393 227177, 3, 9999 şi 72727. Cel mai mare dintre ele este 423111.
244
622717 7
13
49999
572727

16.1.1 Indicaţii de rezolvare

Propusa de: Prof. Iordaiche Eugenia-Cristiana, Liceul Teoretic ”Grigore Moisil” Timişoara
Cerinţa 1. O soluţie posibilă pentru determinarea lungimii maxime a unui rând ce are pro-
prietatea că oricare două pătrăţele alăturate au culori diferite, constă ı̂n parcurgerea liniară a tu-
turor pătrăţelelor fiecărui rând şi compararea succesivă a culorilor pentru oricare două pătrăţele
alăturate. Actualizăm la fiecare pas Lmax cu lungimea rândului corect identificat, conform
cerinţei.
Kmax este o variabilă de tip contor ı̂n care vom număra toate rândurile de pătrăţele ale
caietului, ce au lungimea egală cu Lmax.

if(nrculori > Lmax)


{
Lmax=nr cul o r i ;
Kmax=1;
}
else
if(Lmax==nrculori)
Kmax++;

Cerinţa 2. Pentru a determina cel mai mare număr format prin lipirea tuturor cifrelor unui
rând de pătrăţele, putem utiliza un algoritm de compararea lexicografică a două şiruri de cifre,
parcurgându-le element cu element de la dreapta la stânga. Identificăm astfel, cel mai mare număr
natural ce se poate construi cu cifrele unui rând de pătrăţele. Acest număr va fi memorat cifră cu
cifră ı̂ntr-un tablou unidimensional.
CAPITOLUL 16. ONI 2022 16.2. JOC 195

Parcurgem fiecare rând de pătrăţele de la dreapta la stânga, cifră cu cifră şi comparăm din
punct de vedere lexicografic două şiruri de cifre. In momentul ı̂n care găsim un şir de cifre mai mare
din punct de vedere lexicografic, actualizăm datele memorate ı̂n tabloul ce va memora rezultatul
final şi continuăm până ı̂n momentul ı̂n care vom compara toate şirurile de cifre de pe rândurile
caietului.

16.1.2 *Cod sursă

16.1.3 *Rezolvare detaliată

16.2 Joc
Problema 2 - Joc 100 de puncte
Doi copii vor să joace un joc cu doi pioni şi o tablă formată din N căsuţe numerotate de la 1
la N, aşezate una după cealaltă, pe aceeaşi linie. Jocul are următoarele reguli:
ˆ se aşază pionii pe prima căsuţă de pe tablă (fiecare copil are propriul pion);
ˆ primul copil este cel care ı̂ncepe jocul;
ˆ copiii vin la tabla de joc alternativ;
ˆ cel care este la rând face, după regula de mai josuna sau mai multe mutări ı̂nainte să cedeze
locul celuilalt:
– calculează o valoare X ı̂n modul descris mai jos;
– ı̂şi mută pionul ı̂nainte cu X poziţii iar, dacă valoarea X calculată este 6, are dreptul la
calcularea unei alte valori X, deci la ı̂ncă o mutare, necedând ı̂ncă locul celuilalt copil,
iar dacă valoarea X este diferită de 6 cedează locul la tablă;
ˆ X se calculează după regula:
– dacă numărul mutării este impar atunci:
X = ((numărul mutării + ((numărul căsuţei pionului + N ) mod 10)) mod 6) + 1
– dacă numărul mutării este par atunci:
X=
((((numărul mutării+1) mod 5)+((numărul căsuţei pionului+N ) mod 10)) mod 6)+1
unde N este numărul căsuţelor tablei de joc, numărul mutării semnifică a câta mutare
este, mod este operaţia prin care se obţine restul ı̂mpărţirii ı̂ntregi a două numere, iar
valoarea rezultată, X, este una dintre cifrele 1, 2, 3, 4, 5 sau 6, cum de altfel se deduce
din formulele de mai sus.
ˆ ı̂n urma ı̂naintării, dacă pionul ajunge pe o căsuţă ocupată ı̂n acel moment de celălalt pion, ı̂i
ia locul acestuia, iar pionul care ocupa căsuţa este trimis la căsuţa cu numărul 1 (ı̂ntoarcerea
acestui pion la poziţia 1 nu se contorizează ca mutare);
ˆ dacă un pion, după ı̂naintare, ar ajunge ı̂n afara tablei de joc, este aşezat pe căsuţa N
(ultima);
ˆ este câştigător copilul care ajunge primul cu pionul la căsuţa N de pe tabla de joc, şi atunci
jocul se ı̂ncheie.

Cerinţe

Dându-se numărul N, determinaţi:


1. Numărul divizorilor lui N;
2. Numărul maxim de apariţii ale unei valori calculate ı̂n timpul jocului prin formulele descrise;
3. Numerele căsuţelor ocupate, ı̂n timpul jocului, de pionul câştigătorului ı̂n ordinea ı̂n care
acestea sunt vizitate.
CAPITOLUL 16. ONI 2022 16.2. JOC 196

Date de intrare

Pe prima linie a fişierului joc.in se află două numere naturale, C şi N separate printr-un spaţiu.
Dacă C = 1, atunci se rezolvă doar prima cerinţă, dacă C = 2, atunci se rezolvă doar a doua
cerinţă iar dacă C = 3, atunci se rezolvă doar cea de-a treia cerinţă.

Date de ieşire

Fişierul de ieşire este joc.out


a dacă C = 1 sau C = 2, acesta conţine un număr natural ce reprezintă răspunsul pentru
cerinţa respectivă.
a dacă C = 3, acesta conţine un şir de numere naturale, separate prin câte un spaţiu, care
reprezintă răspunsul pentru a treia cerinţă.

Restricţii şi precizări

ˆ 2 & N & 10.000


ˆ Pentru teste ı̂n valoare de 23 de puncte, C = 1

ˆ Pentru alte teste ı̂n valoare de 33 de puncte, C = 2

ˆ Pentru alte teste ı̂n valoare de 44 de puncte, C = 3

ˆ Se garantează că există un câştigător

ˆ Pe parcursul jocului, copii pot ajunge pe căsuţe pe care le-au mai vizitat

ˆ Se garantează că numărul căsuţelor ocupate de copii este mai mic decât 100.000

ˆ Problema nu urmăreşte găsirea vreunei proprietăţi speciale pentru şirurile de valori calculate
prin formulele date.

Exemple:

joc.in joc.out
1 10 4
2 10 2
3 10 1 4 6 10

Explicaţii
In primul exemplu C = 1 deci se rezolvă prima cerinţă. N = 10 are 4 divizori.
In al doilea exemplu C = 2 deci se rezolvă a doua cerinţă.
CAPITOLUL 16. ONI 2022 16.2. JOC 197

Primul copil este câştigător. Cifrele calculate au fost, ı̂n ordine, 3 5 2 2 6, cifra 2 a apărut de
cele mai multe ori adică de 2 ori.
În al treilea exemplu C=3 deci se rezolvă a treia cerinţă. Primul copil este câştigător, el a
ocupat ı̂n această ordine căsuţele 4 6 10.

16.2.1 Indicaţii de rezolvare

Propusa de: Prof. Dabelea Delia, Colegiul Naţional ”Spiru Haret” Târgu Jiu
Cerinţa 1. O soluţie posibilă ar fi descompunerea ı̂n factori primi ai numărului natural N,
numărul divizorilor acestuia fiind egal cu produsul puterilor factorilori primi crescuţi cu o unitate.
Cerinţa 2. Ne putem folosi de un vector de frecvenţă cu doar 7 elemente, indexate de la 0 la
6, ı̂n care, contorizăm fiecare cifră X calculată. După construirea acestuia, valoarea maximă din
el reprezintă numărul maxim de apariţii căutat. Un rezultat corect depinde, evident, de simularea
corectă a jocului.
Cerinţa 3. Pentru gestionarea corectă a mutărilor alternative a pionilor pe tablă, vom folosi
două variabile (să le notăm a pentru primul copil şi b pentru al doilea copil), variabile, care nu vor
avea niciodată valoare identică. Spre exemplu a=1 şi b=0 sau a=0 şi b=1 (1 mută, 0 nu mută)
ı̂n funcţie de copilul care deplasează pionul.
CAPITOLUL 16. ONI 2022 16.3. ROTIRE25 198

Numerele căsuţelor vizitate de pioni ı̂n timpul jocului se păstrează ı̂n doi vectori (un vector
pentru pionul primului copil şi altul pentru pionul celui de-al doilea copil).
Simulăm jocul printr-o structură repetitivă care se ı̂ncheie ı̂n momentul ı̂n care un pion ajunge
pe ultima căsuţă. La fiecare pas ı̂naintăm pionul copilului care este la mutare X căsuţe, păstrăm
numărul noii căsuţe ı̂n vectorul corespunzător şi respectăm celelalte reguli din enunt.

16.2.2 *Cod sursă

16.2.3 *Rezolvare detaliată

16.3 Rotire25
Problema 3 - Rotire25 100 de puncte
George a primit ca temă la matematică următoarea problemă. Se dă un număr X, asupra
acestui număr se pot face următoarele transformări:

1. În această ordine (toţi aceşti 3 paşi reprezintă o transformare):


– se ı̂nmulţeşte numărul cu 5 (de exemplu: X = 416 devine 416 5 = 2080)
– se elimină toate zerourile din număr (2080 devine 28)
– se oglindeşte numărul (28 devine 82)
2. În această ordine (toţi aceşti 3 paşi reprezintă o transformare):
– se ı̂nmulţeşte numărul cu 2 (de exemplu: X = 32 devine 32 2 = 64)
– se elimină toate zerourile din număr (64 rămâne 64)
– se oglindeşte numărul (64 devine 46)

George trebuie să aplice alternativ cele două transformări asupra numărului X. Prima dată
aplică transformarea 1, apoi pe rezultatul obţinut se aplică transformarea 2, apoi pe rezultat se
aplică iar transformarea 1, apoi iar transformarea 2 şi aşa mai departe. George trebuie să aplice
asupra numărului X exact K transformări, ı̂n ordinea descrisă mai sus.

Cerinţe

Dându-se numerele X şi K determinaţi:


1. Produsul dintre ultima cifră a numărului X * X * X * ... * X (de K ori) şi prima cifră a lui
X.
2. Numărul rezultat după aplicarea celor K transformări.

Date de intrare

Pe prima linie a fişierului de intrare rotire25.in se află trei numere separate prin câte un
spaţiu C, X şi K. Dacă C = 1 se va rezolva doar prima cerinţă, iar dacă C = 2 se va rezolva doar
a doua cerinţă.

Date de ieşire

Fişierul rotire25.out va conţine un singur număr. Dacă C = 1, acest număr reprezintă


rezultatul pentru prima cerinţă, iar dacă C = 2, acest număr reprezintă rezultatul pentru a doua
cerinţă.

Restricţii şi precizări

ˆ 1 & X & 999


ˆ 1 & K & 1.000.000.000
ˆ Pentru teste ı̂n valoare de 29 de puncte, C = 1.
CAPITOLUL 16. ONI 2022 16.3. ROTIRE25 199

ˆ Pentru teste ı̂n valoare de 71 de puncte, C = 2.


ˆ Pentru teste ı̂n valoare de 7 puncte, C = 1 şi se garantează că numărul obţinut ı̂n urma
ı̂nmulţirilor este & 10 (1.000.000.000.000.000.000).
18

ˆ Pentru alte teste ı̂n valoare de 11 puncte: C = 1 şi K & 100.000.


ˆ Pentru teste ı̂n valoare de 39 de puncte: C = 2 şi K & 100.000.
ˆ Pentru alte teste ı̂n valoare de 9 puncte: C = 2 şi X & 9.

Exemple:

rotire25.in rotire25.out Explicaţii


1 27 3 6 Pentru primul exemplu, se rezolvă cerinţa 1: X = 27, K = 3. 27
27 27 = 19683 ultima cifră este 3. Prima cifră a lui 27 este 2,
deci rezultatul este 2 3 = 6
2 13 3 551 Pentru al doilea exemplu, se rezolvă cerinţa 2: X = 13, K = 3.
Se fac urmatoărele transformări:
a 13 * 5 = 65, scoatem zerourile si rotim 56
a 56 * 2 = 112, scoatem zerourile şi rotim 211
a 211 * 5 = 1055, scoatem zerourile 155, rotim 551
2 42 1782321 12 Pentru al treilea exemplu, se rezolvă cerinţa 2: X = 42, K
= 1782321. După ce se fac cele K transformări se ajunge la
numărul 12.

16.3.1 Indicaţii de rezolvare

Propusa de: stud. Banu Denis Andrei - Facultatea de Informatică, Universitatea Alexandru
Ioan Cuza, Iaşi
Cerinţa 1.

Subtask 1 - 7 puncte. Când numărul obţinut ı̂n urma ı̂nmulţirilor este & 10 . Se poate calcula
18

X * X * X * ... * X (de K ori) folosind structura repetitivă for, iar rezultatul poate să fie reţinut
ı̂ntr-o variabilă de tipul long long. Se ia ultima cifră a acestui rezultat şi se ı̂nmulţeşte cu prima
cifră a lui X.

Subtask 2 - 11 puncte. Când K 100.000. Trebuie să observăm că atunci când ı̂nmulţim două
numere, ultima cifră a rezultatului este dată de ı̂nmulţirea ultimei cifre din primul număr cu
ultima cifră din al doilea număr. Este suficient să reţinem ultima cifră a rezultatului după fiecare
ı̂nmulţire. Astfel rezultatul va rămâne mic şi va putea fi stocat ı̂ntr-o variabilă de tip int. Putem
folosi din nou structura repetitivă for, iar la final ı̂nmulţim rezultutatul cu prima cifră a lui X.

Toată cerinţa 1 - 29 de puncte. Când K & 10 . De data aceasta nu mai putem sa iterăm de
9

K ori deoarece ar dura prea mult. Trebuie sa observăm că ı̂nmulţirea unei cifre cu ea ı̂nsăşi de K
ori are o anumită periodicitate astfel:
ˆ 0, 1, 5 şi 6 - au perioada 1. De oricâte ori am ı̂nmulţi una dintre aceste cifre cu ea, rezultatul
va avea ultima cifră egală cu aceasta.
ˆ 4 şi 9 - au perioada 2.
ˆ 2, 3, 7 şi 8 - au perioada 4.
Ca urmare, dacă X are ultima cifră 0, 1, 5, 6 rezultatul va fi tot acea cifră indiferent de valoarea
lui K . Dacă ultima cifră este 4 sau 9, dacă K este impar rezultatul este acea cifră adică 4 respectiv
9, dacă este par rezultatul este ultima cifră ı̂nmulţită o dată cu ea, adică 4*4 = 16 6 respectiv
9 * 9 = 81  1.

Cerinţa 2.
CAPITOLUL 16. ONI 2022 16.3. ROTIRE25 200

Subtask 1 - 39 de puncte. Când K & 100.000. Putem simula transformările şi la final afişăm
rezultatul.

Toată cerinţa 2 - 71 de puncte. Când K & 100.000. Trebuie să observăm că după ce am
făcut primele 2, 3 transformări, şirul rezultat ı̂n urma aplicării transformărilor este periodic. De
exemplu, pentru X = 13:

Numărul de transformări aplicate Numărul rezultat


0 13
1 65
2 211
3 551
4 211
5 511
... ...
K = par 211
K = impar 511

Întotdeauna perioada va fi 2. Putem să facem simularea ı̂ntr-un mod asemănător cu subtaskul
1 şi să reţinem numărul de la transformarea curentă şi numărul din urmă cu două transformări. În
momentul ı̂n care numărul curent ajunge egal cu numărul din urmă cu două transformări, atunci
am găsit numerele din perioadă. Dacă K are aceeaşi paritate cu pasul curent, afişăm numărul
curet, dacă nu, mai facem o transformare şi afişăm numărul obţinut ı̂n urma acestei transformări.
Obs. Pentru a scăpa de cazurile particulare, atunci când K este mic, se poate face simulare
exact ca la subtaskul 1.

16.3.2 *Cod sursă

16.3.3 *Rezolvare detaliată


Capitolul 17

ONI 2021

17.1 ktlon
Problema 1 - ktlon 100 de puncte
Doua echipe, F şi R, formate din n jucători fecare, au participat ı̂n cadrul noii ediţii ktlon la
k probe.
După fecare probă s-au ı̂nregistrat ı̂n registrul ktlon 2 ˜ n valori: primele n reprezintă numărul
de puncte câştigate ı̂n cadrul probei de jucatorii echipei F şi urmu atoarele n reprezintă numărul
de puncte câştigate ı̂n cadrul probei de jucatorii echipei R.
Pentru ca o echipă să câştige o probă este necesar ca cel puţin unul din jucătorii săi să obţină un
număr de puncte strict mai mare decât fecare din punctajele obţinute de către jucătorii celeilalte
echipe.
Echipa câştigătoare a probei primeşte un număr de stele. Pentru a stabili numărul de stele
primite, mai ı̂ntâi se determină numărul M de jucători care au obţinut un număr de puncte
strict mai mare decât fiecare din punctajele obţinute de jucătorii celeilalte echipe. Apoi echipa
câştigătoare primeşte un număr de stele egal cu diferenţa dintre suma celor mai mari M punctaje
obţinute de jucătorii echipei câştigătoare şi suma celor mai mari M punctaje obţinute de jucătorii
celeilalte echipe.
De exemplu, dacă jucătorii celor două echipe au obţinut punctajele (8; 5; 8; 3; 9; 7) şi (5; 7;
5; 4; 5; 1), atunci M 3 deoarece trei punctaje ale jucatorilor echipei F (8, 8, 9) sunt mai mari
decât toate punctajele obţinute de jucătorii echipei R.
Echipa F câştigă proba şi primeşte 8 stele = (9 + 8 + 8) - (7 + 5 + 5).
Dacă niciun jucător al niciunei echipe nu obţine un număr de puncte strict mai mare decât
toate punctajele obţinute de jucătorii celeilalte echipe, proba se ı̂ncheie cu remiza şi nicio echipă
nu primeşte nicio stea (M 0).
Competiţia este câştigată de echipa care acumulează un număr maxim de stele la finalul tuturor
probelor.

Cerinţe

Cunoscând n - numărul de jucători din fiecare echipa, k - numărul de probe şi pentru fiecare
probă punctajele obţinute de cei 2 ˜ n jucători ai celor două echipe, determinaţi:
1. numărul de probe câştigate de echipa R;
2. numărul de stele obţinut de echipa câştigătoare.

Date de intrare

Fişierul de intrare ktlon.in conţine pe prima linie un număr C reprezentând cerinţa care
trebuie să fie rezolvata (1 sau 2). Pe a doua linie se află două numere naturale n şi k, care
reprezintă numărul de jucători ai fiecărei echipe, respectiv numărul de probe, iar pe fiecare din
următoarele k linii, câte 2 ˜ n numere naturale: primele n reprezintă numărul de puncte câştigate
ı̂n cadrul probei curente de jucătorii echipei F şi următoarele n reprezintă numărul de puncte
câştigate ı̂n cadrul probei curente de jucătorii echipei R.
Numerele de pe aceeaşi linie sunt separate prin câte un spaţiu.

Date de ieşire

201
CAPITOLUL 17. ONI 2021 17.1. KTLON 202

Daca C 1, fşierul de ieşire ktlon.out va conţine numărul de probe câştigate de echipa R.


Daca C 2, fşierul de ieşire va conţine numărul de stele obţinute de echipa câştigătoare.

Restricţii şi precizări

a 1 & C & 2.
a 1 & n & 10 000.
a 1 & kle50.
a Punctajele obţinute de concurenţi sunt numere naturale cuprinse ı̂ntre 0 şi 200 000 inclusiv.
a Pentru teste valorând 35 de puncte cerinţa este 1.
a Pentru teste valorând 30 de puncte cerinţa este 2 şi se garanteaza ca 0leM le1 pentru toate
probele aceluiaşi test.
a Pentru teste valorând 35 de puncte cerinţa este 2 şi se garanteaza ca 0 & M & 5 pentru toate
probele aceluiaşi test.

Exemple:

ktlon.in ktlon.out Explicaţii


1) 1 1 Se rezolvă cerinţa 1.
34 Prima probă este câştigată de echipa F deoarece
683776 există un jucător care a obţinut mai multe puncte
123453 (8) decât numărul de puncte câştigat de fiecare din
153452 jucătorii echipei R (7, 7, 6).
153452 A doua probă este câştigată de echipa R deoarece
există doi jucători care au obţinut mai multe puncte
(4 respectiv 5) decât numărul de puncte câştigate de
fiecare din jucătorii echipei F (1, 2, 3).
A treia probă s-a ı̂ncheiat cu remiză deoarece niciun
jucător al niciunei echipe nu obţine un număr
de puncte strict mai mare decât toate punctajele
obţinute de jucătorii celeilalte echipe.
A patra probă s-a ı̂ncheiat tot cu remiză, deoarece
toţi jucătorii au obţinut exact aceleaşi punctaje ca
şi la proba a treia.
Răspunsul este 1 deoarece echipa R a câştigat o sin-
gură probă.
2) 2 7 Se rezolvă cerinţa 2.
3 3 Echipa F câţigă prima probă şi primeşte 2 stele
8 85777 (M 2, (8+8) - (7+7) = 2).
1 23353 Echipa R câştigă a doua probă şi primeşte 2 stele
4 12651 (M 1, 5-3 = 2).
Echipa R câştigă a treia probă şi primeşte 5 stele
(M 2, (6+5) - (4+2) = 5).
În total, echipa F a primit 2 stele iar echipa R a
primit 7 stele.
Competiţia este câştigată de echipa R cu 7 stele.

Timp maxim de executare/test: 0.5 secunde pe Windowş 0.5 secunde pe Linux


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

17.1.1 Indicaţii de rezolvare

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


Pentru rezolvarea cerinţei 1 se determină pentru fiecare din cele k probe cel mai mare punctaj
obţinut de jucătorii echipei F şi apoi cel mai mare punctaj obţinut de jucătorii echipei R. Dacă
punctajul maxim corespunzător echipei R este strict mai mare decât punctajul maxim al echipei
R se incrementează numărul de probe câştigate de echipa R.
CAPITOLUL 17. ONI 2021 17.2. IEPURAS 203

Pentru rezolvarea cerinţ ei 2, o abordare posibilă este următoarea: pentru fiecare din cele k
probe, atât pentru echipa F , cât şi pentru echipa R, se determină cele mai mari cinci punctaje
obţinute de jucătorii echipei, dacă n ' 5, sau primele n punctaje ı̂n caz contrar, ı̂n ordine de-
screscătoare. Cât timp primele cel mult cinci punctaje maxime corespunzătoare unei echipei sunt
strict mai mari decât punctajul maxim obţinut de jucătorii celeilalte echipe se adună la numărul
de stele corespunzător acesteia numărul de stele obţinut la proba curentă, conform enunţului
problemei. Se afişează la final numărul maxim de stele obţinut de o echipă.

17.1.2 *Cod sursă

17.1.3 *Rezolvare detaliată

17.2 iepuras
Problema 2 - iepuras 100 de puncte
Pentru că ı̂i plac cifrele, Skippie, iepuraşul norocos a stabilit cum se obţine cifra de control a
unui număr: se efectuează suma cifrelor sale, apoi suma cifrelor acestei sume, până când suma
obţinută este un număr format dintr-o singură cifră. Această ultimă cifră, spune Skippie, poartă
numele de cifră de control.
Skippie, a ascuns ı̂n padure n oua roşii. Pe fiecare ou a pictat câte un număr natural nenul.
Iar acum se ı̂ntreabă care este suma dintre cel mai mare ş i cel mai mic număr natural care se pot
forma din toate cifrele distincte folosite ı̂n scrierea numărului pictat.
În pluş, pentru ca lui Skippie ı̂i plac problemele complicate, pentru fecare numar pictat pe
câte un ou, el ar vrea să afle şi de câte ori apare cifra de control a numarului ı̂n scrierea tuturor
numerelor naturale mai mici sau egale decât numărul pictat.

Cerinţe

1. Pentru fecare dintre cele n numere pictate de Skippie, aflaţi suma dintre cel mai mare şi cel
mai mic număr natural care se pot forma din toate cifrele distincte folosite ı̂n scrierea numărului
pictat.
2. Pentru fiecare dintre cele n numere pictate de Skippie, aflaţi de câte ori apare cifra de control
a numărului pictat ı̂n scrierea tuturor numerelor naturale mai mici sau egale decât numărul pictat.

Date de intrare

Fişierul de intrare iepuras.in conţine un numar natural C. Acesta poate avea valorile 1 sau
2 ş i reprezintă cerinţa problemei. Cea de-a doua linie a fşierului de intrare conţine un număr
natural n reprezentând numărul de oua roşii pictate de Skippie. Fiecare dintre următoarele n
linii ale fişierului de intrare conţine câte un număr natural nenul reprezentând numerele pictate
de iepuraş pe cele n oua roşii.

Date de ieşire

Fişierul de ieşire iepuras.out va conţine n numere ı̂ntregi, fecare pe o linie separată. În ordinea
apariţiei numerelor pictate de iepuraş ı̂n fişierul de intrare, se afişează răspunsurile la cerinţa C.

Restricţii şi precizări

Pentru teste Cerinţa Numarul de Numerele pictate de iepuraş


ı̂n valoare de este oua este sunt mai mici sau egale cu
9
16 puncte C=1 n 1 10
1 $ n $ 100 000
9
24 de puncte C=1 10
24 de puncte C=2 1 $ n $ 100 2 000
100 $ n $ 100 000
18
36 de puncte C=2 10

Exemple:
CAPITOLUL 17. ONI 2021 17.2. IEPURAS 204

iepuras.in iepuras.out Explicaţii


1) 1 33 Se rezolva cerinţa 1.
2 77 Sunt 2 oua pictate (n = 2). Pentru primul ou, pictat
121 cu numarul 121:
33343 - cel mai mare numar natural cu cifre distincte format
cu toate cifrele distincte ale numarului pictat este 21;
- cel mai mic numar natural cu cifre distincte format
cu toate cifrele distincte ale numarului pictat este 12.
Deci suma celor doua numere este 33(21 + 12 = 33).
Pentru al doilea ou, pictat cu numarul 33343:
- cel mai mare numar natural cu cifre distincte format
cu toate cifrele distincte ale numarului pictat este 43;
- cel mai mic numar natural cu cifre distincte format
cu toate cifrele distincte ale numarului pictat este 34.
Deci suma celor doua numere este 77 (43 + 34 = 77).
2) 2 22 Se rezolva cerinţa 2.
2 39 Sunt 2 oua pictate (n = 2).
123 Pe primul ou este scris numarul 123 iar pe al doilea ou
191 numarul 191.
Cifra de control a numarului 123 este 6 (1+2+3 = 6).
Numarul de apariţii a cifrei 6 ı̂n scrierea a tuturor nu-
merelor naturale mai mici sau egale cu 123 este 22.
Cifra 6 apare ı̂n scrierea numerelor: 6, 16, 26, 36, 46,
56, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 76, 86, 96,
106, 116 de 22 de ori.
Cifra de control a numarului 191 este 2. (1 + 9 + 1 =
11; 1 + 1 = 2).
Numarul de apariţii a cifrei 2 ı̂n scrierea a tuturor nu-
merelor naturale mai mici sau egale cu 191 este 39.
Cifra 2 apare ı̂n scrierea numerelor 2, 12, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 32, 42, 52, 62, 72, 82, 92,
102, 112, 120, 121, 122, 123, 124, 125, 126, 127, 128,
129, 132, 142, 152, 162, 172, 182 de 39 de ori.

Timp maxim de executare/test: 0.5 secunde pe Windowş 0.5 secunde pe Linux


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

17.2.1 Indicaţii de rezolvare

Propunator: prof. Georgeta Iulia Balacea - Colegiul Naţional ”Vasile Alecsandri” Galaţi
Pentru rezolvarea problemei se utilizeaza tipuri de date simple: ı̂ntregi şi un vector de frecvenţă.
În plus se utilizează elemente de matematică din programa şcolară a clasei a V-a. (Operaţii cu
numere naturale, scrierea ı̂n baza 10 a unui număr natural) şi structuri elementare de control
(structura alternativă şi structura repetitivă).
Cerinţa 1
Se descompune ı̂n cifre fiecare număr N dintre cele n numere citite şi se reţine numărul de
apariţii al cifrelor lui N ı̂ntr-un vector cif 10 (cu cel mult 10 elemente).
Pentru determinarea numărului maxim (Nmax ) care se poate obţine din cifrele distincte ale
numărului N se parcurge vectorul de frecvenţă, de la poziţia 9 către poziţia 0. Dacă cifra i apare
ı̂n scrierea zecimală a numărului N (cif i j 0) atunci Nmax Nmax  10  i.
Pentru determinarea numărului minim (Nmin ) care se poate obţine din cifrele distincte ale
numu arului N se parcurge vectorul de frecvenţă, de la poziţia 1 către poziţia 9 şi se caută prima
valoare nenulă. Fie aceasta j. Atunci Nmin j şi se marchează faptul că s-a folosit cifra j,
atribuind lui cif j  valoarea 0. Se parcurge apoi vectorul de frecvenţă de la 0 către 9. Dacă cifra
i apare ı̂n scrierea zecimală a numărului N (cif i j 0) atunci Nmin Nmin  10  i.
Se afişează suma dintre cele două numere obţinute, Nmax şi Nmin .
CAPITOLUL 17. ONI 2021 17.2. IEPURAS 205

Pentru fiecare număr N , dintre cele n numere citite, se iniţializează vectorul de frecvenţă cif 
cu 0.
Cerinţa 2
Pentru a putea rezolva cerinţa a doua, mai ı̂ntâi vom analiza câteva cazuri particulare şi vom
ı̂ncerca să răspundem la câteva ı̂ntrebari:
(1) câte numere mai mici decât 243 au cifra 5 pe poziţia zecilor?
50 51 52 53 54 55 56 57 58 59
150 151 152 153 154 155 156 157 158 159
Raspuns: 20
(2) câte numere mai mici decât 253 au cifra 5 pe poziţia zecilor?
50 51 52 53 54 55 56 57 58 59
150 151 152 153 154 155 156 157 158 159
250 251 252 253
Raspuns: 24
(3) câte numere mai mici decât 263 au cifra 5 pe poziţia zecilor?
50 51 52 53 54 55 56 57 58 59
150 151 152 153 154 155 156 157 158 159
250 251 252 253 254 255 256 257 258 259
Raspuns: 30
Analizând cu atenţie aceste trei exemple, ne dăm seama că se disting trei cazuri. Pentru fiecare
dintre aceste cazuri putem deduce câte o regulă generală prin care să calculăm răspunsurile:
Fie:
a s = cifra sutelor
a z = cifra zecilor
a u = cifra unitaţilor
Atunci:
a dacă z $ 5, atunci răspunsul este s  10
a dacă z 5, atunci răspunsul este s  10  u  1
a dacă z % 5, atunci răspunsul este s  1  10
Dacă vom analiza exemple cu mai multe cifre, putem generaliza următoarele reguli:
Fie un numar care scris pe cifre arată astfel: ss...sszuu...uu.
Fie CC cifra sa de control.
Fie nrU numărul de cifre notate cu u ı̂n scrierea de mai sus.
Atunci:
a dacă z $ CC, atunci numărul de numere mai mici sau egale cu ss...sszuu...uu care conţin
nrU
cifra CC pe poziţia cifrei notată cu z este ss...ss ˜ 10
a dacă z CC, atunci numărul de numere mai mici sau egale cu ss...sszuu...uu care conţin
nrU
cifra CC pe poziţia cifrei notată cu z este ss...ss ˜ 10  uu...uu  1
a dacă z % CC, atunci numărul de numere mai mici sau egale cu ss...sszuu...uu care conţin
nrU
cifra CC pe poziţia cifrei notată cu z este ss...ss  1 ˜ 10
Calculând ı̂n prealabil cifra de control, iterând prin cifrele numarului şi cu ajutorul acestor
reguli, putem calcula răspunsul cerinţei a doua.
Cerinţa 2 (explicaţie alternativa)
Cifra de control a unui număr natural nenul este egală cu 9 dacă numărul este multiplu de 9
sau este egală cu restul ı̂mparţirii la 9 a numărului dat, dacă restul este nenul.
Soluţia problemei se bazează pe scrierea ı̂n baza 10 a unui număr natural.
Pentru fecare dintre cele n numere scrise de iepuraş pe ouă se determină cifra de control.
Numărul de apariţii al cifrei de control ı̂n scrierea tuturor numerelor naturale nenule mai mici
sau egale cu un număr natural N se determină analizând scrierea ı̂n baza 10 a numarului.
Fie n0 cifra unitaţilor, n1 este cifra zecilor, ... şi nk cifra cea mai semnifcativa a numărului
natural N . Atunci
2 k
N n0  n1  10  n2  10  ...  nk  10 .
Notăm cu c cifra de control a numărului natural nenul N .
Soluţia care analizează apariţia cifrei de control c ı̂n scrierea tuturor numerelor naturale nenule
mai mici sau egale cu numărul N descompunând ı̂n cifre toate numerele din interval rezolvă sufcient
de rapid grupa de teste ı̂n valoare de 24 de puncte.
Pentru punctaj maxim ı̂nsă, va trebui să găsim un alt mod de a calcula răspunsul.
Se calculează de câte ori apare cifra c pe poziţia unitaţilor ı̂n toate numerele naturale mai mici
sau egale cu N .
CAPITOLUL 17. ONI 2021 17.3. TAIERI 206

Astfel, cifra c apare pe poziţia unitaţilor de N ©10 ori. Dacă n0 (cifra unităţilor numărului N )
este mai mare sau egal cu c atunci numărul de apariţii al cifrei de control se măreşte cu 1.
Se calculează apoi de câte ori apare cifra c pe poziţia zecilor ı̂n toate numerele naturale mai
mici sau egale cu N .
Astfel, cifra c apare pe poziţia zecilor de N ©100 ori. Dacă n1 (cifra zecilor numărului N ) este
mai mare decât c atunci numărul de apariţii al cifrei de control se măreşte cu 10, ı̂n schimb, dacă
n1 este egală cu cifra de control atunci numărul de apariţii al cifrei de control se măreşte cu n0  1.
În general, se calculează de câte ori apare cifra c pe poziţia p ı̂n toate numerele naturale mai
mici sau egale cu N .
p1
Astfel, cifra c apare pe poziţia p de N ©10 ori. Dacă np este mai mare decât c atunci
p
numărul de apariţii al cifrei de control se măreşte cu 10 , ı̂n schimb, dacă np este egală cu c atunci
p
numărul de apariţii al cifrei de control se măreşte cu N %10   1.
De exemplu, pentru numarul 123, cifra de control este 6.
Cifra 6 apare pe poziţia unitaţilor de 12 ori, pe poziţia zecilor de 1  10 10 ori şi niciodata
pe poziţia sutelor. În total, ı̂n scrierea zecimală a numerelor 1, 2, 3, 4, 5, 6, 7, ... 60, 61, 62, ...
123 cifra 6 apare de 22 de ori.

17.2.2 *Cod sursă

17.2.3 *Rezolvare detaliată

17.3 taieri
Problema 3 - taieri 100 de puncte
Avem la dispoziţie n bare metalice cu aceeaşi grosime, dar lungimi diferite. Putem alege
oricare bară şi să o tăiem, obţinând alte două bare, de lungimi mai mici. Ne dorim ca, folosind
doar această operaţie (deci fără să le putem suda), să obţinem un număr de bare de anumite
lungimi date. Mai exact, dându-se un set de 4 numere a, b, c, d, trebuie să decidem dacă putem
obţine a bare de lungime 1, b bare de lungime 2, c bare de lungime 4 şi d bare de lungime 8.
Odată aplicată o tăiere de lungime L asupra unei bare, restul poate fi ı̂n continuare folosit pentru
a tăia alte bare de oricare dintre lungimile dorite.

Cerinţe

Cunoscând n - numărul de bare metalice şi lungimile celor n bare metalice avute la dispoziţie,
pentru fiecare din seturile de 4 numere a b c d date, determinaţi dacă, pornind de la cele n lungimi
date, se pot obţine barele de lungimile dorite.

Date de intrare

Pe prima linie a fiş ierului de intrare taieri.in se află numărul natural n. Pe linia a doua se află
cele n numere naturale ce reprezintă lungimile barelor iniţiale. Pe linia a treia se află un număr
natural m ce reprezintă numărul de seturi de 4 numere. Pe fiecare din următoarele m linii se află
câte patru numere naturale a b c d cu semnificaţia de mai sus.
Numerele de pe aceeaşi linie sunt separate prin câte un spaţiu.

Date de ieşire

Fişierul de ieşire taieri.out va conţine m valori 0 şi 1, separate prin câte un spaţiu. Pentru
fiecare set de 4 numere, ı̂n ordinea apariţiei lor ı̂n fişierul de intrare, se scrie ı̂n fişierul de ieşire
valoarea 1, dacă se poate obţine numărul dorit de bare pentru toate cele 4 lungimi din setul
corespunzător, respectiv 0 ı̂n caz contrar.

Restricţii şi precizări


CAPITOLUL 17. ONI 2021 17.3. TAIERI 207

a Lungimile barelor sunt numere naturale nenule cel mult egale cu 10 000 000.
a 0 & a, b, c, d & 10 000 000.
a Pentru teste ı̂n valoare de 16 puncte 1 & n & 1 000, 1 & m & 1 000, iar pentru toate seturile
dintr-un test avem b 0, c 0 şi d 0.
a Pentru alte teste ı̂n valoare de 28 puncte 1 & n & 1 000 şi 1 & m & 1 000.
a Pentru alte teste ı̂n valoare de 56 de puncte 1 & n & 100 000 şi 1 & m & 100 000.

Exemple:

taieri.in taieri.out Explicaţii


5 110 La primul set - 2 3 2 2 trebuie obţinute două bare de lungime
10 12 8 3 1 1, trei bare de lungime 2, două de lungime 4 şi două de lungime
3 8. Putem tăia bara de lungime 10 ı̂n una de 8 şi una de 2. Avem
2322 deja a doua bară de lungime 8. Ne mai rămân astfel bare cu
31 0 0 0 lungimile: 2, 12, 3 şi 1. Cele două bare de lungime 4 le putem
1 13 0 1 tăia din cea de lungime 12, rămânându-ne bare de lungimile 2,
4, 3 şi 1. Pentru cele 3 de lungime 2 putem folosi prima bară şi
pe a doua o tăiem ı̂n două bucăţi, iar pe cele 4 de lungime 1 le
putem obţine folosind barele cu lungimile 3 şi 1 rămase.
La al doilea set - 31 0 0 0 putem obţine din prima bară dată
10 bare de lungime 1, din a doua 12 bare de lungime 1, din a
treia ı̂ncă 8 bare de lungime 1 şi mai avem ultima bară deja
de lungime 1, aşadar se pot obţine cele 31 de bare necesare.
Remarcaţi că nu a fost nevoie să folosim bara de lungime 3. Se
observă că nu este nevoie să obţinem bare de lungimile 2, 4, 8.
La al treilea set - 1 13 0 1, oricum am tăia barele avute la
dispoziţie, nu putem obţine ı̂ntreg setul format din: o bară de
lungime 1, 13 bare de lungime 2 şi o bară de lungime 8.

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

17.3.1 Indicaţii de rezolvare

Propunător: prof. Marius Nicoli - Colegiul Naţional ”Fraţii Buzeşti” Craiova


Pentru un set a, b, c, d dat la intrare putem parcurge şirul pentru a determina mai ı̂ntâi dacă se
pot obţine d bare de lungime 8. De exemplu, dacă o bară dată are lungimea V i, din ea putem
obţine V i 8 bare de lungime 8. Înlocuim V i cu valoarea rămasă pentru a putea utiliza acum
V i şi ı̂n scopul tăierii unor bare de lungimi mai mici.
Dacă reuşiim să obţinem din tot ş irul d bare de lungime 8, putem relua procedeul pentru bare
de lungimi 4, apoi 2 şi apoi 1.
Aplicând metoda descrisă mai sus pentru fiecare set din fişierul de intrare obţinem un algoritm
corect dar care nu se ı̂ncadrează ı̂n timp pe testele mari (la fiecare set de la intrare ar fi necesară
traversarea ı̂ntregului şir de valori iniţiale).
Următoarea observaţie ne permite să obţinem o soluţie mai rapidă.
Dacă putem obţine bare de o anumită lungime L ca surplus faţă de ce este necesar, se poate
să le tăiem pe jumătate şi le luăm ı̂n calcul apoi pentru lungimea L 2.
Astfel, fără să ne intereseze pentru ı̂nceput valorile din seturile de câte 4 numere, putem
determina pentru şirul celor n lungimi următoarele valori:

ˆ Numărul maxim de bare de lungime 8 (notat N r8) care se pot obţine (adunăm la o
variabilă valorila V i©8 pentru toate elementele din vector); Înlocuim apoi fiecare valoare
cu V i%8.
ˆ Pe noul vector, reluăm procedeul pentru lungimile 4, 2, 1, calcuând astfel 4 valori.
CAPITOLUL 17. ONI 2021 17.3. TAIERI 208

Apoi, pentru un set de 4 lungimi date a, b, c, d este suficient sa consultăm cele 4 valori calculate
anterior (N r1, N r2, N r4, N r8). Dacă d % N r8, nu avem soluţie. În caz contar adunăm
la N r4 valoarea (N r8  d  2 (surplusul de lungime 8 permite obţinerea de număr dublu de
bare de lungime 4). Acelaşi raţionament ı̂l aplicăm apoi pentru 4, 2, 1, ı̂n această ordine.
Această soluţie permite traversarea vectorului iniţial de un număr constant de valori pentru a
obţine informaţiile N r, iar ı̂n etapa a doua, pentru fiecare set a, b, c, d este sufcient să interogăm
doar cele 4 valori N r.

17.3.2 *Cod sursă

17.3.3 *Rezolvare detaliată


Capitolul 18

ONI 2020 - suspendat !!!

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

209
Capitolul 19

ONI 2019

19.1 Copii
Problema 1 - Copii 100 de puncte
Iliuţă şi Pandele au ı̂nvăţat la şcoală operaţii aritmetice cu numere naturale. Astfel cei doi
fraţi exersează operaţiile folosindu-se de o tablă. Iliuţă spune un număr natural X, iar Pandele
scrie pe tablă rezultatul ı̂nmulţirii tututor numerelor naturale de la 1 la X. Glumeţ, Iliuţă şterge
cifrele egale cu 0 de la finalul numărului scris de Pandele.
Ca să ı̂l ierte, Pandele spune şi el un număr natural Y şi ı̂i cere lui Iliuţă să determine un
număr natural Z care este cel mai mare divizor al lui Y având un număr impar de divizori.

Cerinţe

Cunoscându-se numerele spuse de copii, scrieţi un program care rezolvă următoarele cerinţe:
1) afişează ultimele K cifre ale produsului calculat de Pandele, după ştergerea cifrelor egale cu
0 de la finalul acestuia;
2) afişează numărul Z cu semnificaţia de mai sus şi numărul de divizori ai acestuia.

Date de intrare

Fişierul copii.in conţine pe prima linie numărul C, care reprezintă numărul cerinţei şi poate
avea doar valorile 1 sau 2. Pentru prima cerinţă fişierul conţine pe a doua linie numărul X, iar pe
cea de a treia linie numărul K. Pentru a doua cerinţă fişierul conţine pe a doua linie numărul Y.

Date de ieşire

Pentru cerinţa 1), pe prima linie a fişierului copii.out se vor afişa cele K cifre cerute, fără
spaţii, ı̂n ordine de la stânga la dreapta.
Pentru cerinţa 2), pe prima linie se vor afişa, ı̂n această ordine, numărul Z determinat şi
numărul de divizori ai acestuia. Numerele vor fi separate printr-un spaţiu.

Restricţii şi precizări

1 & X & 10
6
a
1 & Y & 10
12
a
a 1&K&9
a Numărul rămas după ştergerea zerourilor de la finalul produsului are cel puţin K cifre;
a Pentru rezolvarea primei cerinţe se acordă 40 de puncte;
a Pentru rezolvarea celei de a doua cerinţe se acordă 60 de puncte.

Exemple

210
CAPITOLUL 19. ONI 2019 19.1. COPII 211

copii.in copii.out Explicaţii


1 016 Produsul 1*2*3*4*5*6*7*8*9*10*11*12 = 479001600.
12 După ştergerea zerourilor de la finalul produsului,
3 ultimele 3 cifre sunt 016.
2 14641 5 Cel mai mare divizor al lui 14641 care are un număr
14641 impar de divizori este chiar 14641.
1 813433856 Produsul 1*2*3*4*5*6*7*8*9*10*11*12 = 479001600.
723432 După ştergerea zerourilor de la finalul produsului,
9 ultimele 9 cifre sunt 813433856
2 286597481104 105 Cel mai mare divizor cu un număr impar de divizori
573194962208 este 286597481104 care are 105 divizori
Tabelul 19.1: copii

Timp maxim de executare/test: 0.2 secunde


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

19.1.1 Indicaţii de rezolvare

Prof. Lica Daniela, Centrul Judeţean de Excelenţă Prahova - Ploieşti

1) Pentru prima cerinţă se vor contoriza factorii de 5 din descompunerea numerelor de la 1 la


N. Fie Nr5 acest număr. Se vor determina ultimele K cifre ale produsului numerelor, ignorând
factorii de 2 şi de 5, ı̂n număr egal cu Nr5.
2) Numărul Z cerut este pătrat perfect, deci toţi factorii primi ai acestuia apar la puteri pare.
Se va descompune Y ı̂n factori primi şi se va calcul numărul Z, derminând produsul factorilor din
descompunerea lui Y la cea mai mare putere pară mai mică sau egală cu cea din descompunerea
lui Y.

19.1.2 Cod sursă

Listing 19.1.1: copii cpp.cpp


#include <fstream>
#include <algorithm>
#include <cassert>

using namespace std;

long long prim[1000010];


int expp[1000010], p = 0;

int main ()
{
ifstream cin ("copii.in");
ofstream cout ("copii.out");

int c, k;
long long x;
cin >> c >> x;

assert (c == 1 || c == 2);

if (c == 1)
{
cin >> k;

assert (1LL <= x && x <= 1000000LL);


assert (1 <= k && k <= 9);

int m = 1;
for (int i = 1; i <= k; ++i)
CAPITOLUL 19. ONI 2019 19.1. COPII 212

m *= 10;

assert (m > 0);

int nr2 = 0, nr5 = 0;


for (int i = 1; i <= x; ++i)
{
int ci = i;

while (ci % 5 == 0)
{
++nr5;
ci /= 5;
}
}

nr2 = nr5;

long long prod = 1LL;

for (int i = 1; i <= x; ++i)


{
int ci = i;
while (ci % 2 == 0 && nr2 > 0)
{
--nr2;
ci /= 2;
}

while (ci % 5 == 0 && nr5 > 0)


{
--nr5;
ci /= 5;
}

prod *= 1LL * ci;


prod %= 1LL * m;
}

int aux = prod, p = 0;


while (aux > 0)
{
++p;
aux /= 10;
}

for (int i = p + 1; i <= k; ++i) cout << 0;

cout << prod << ’\n’;


}
else
{
assert (1LL <= x && x <= 1000000000000LL);

long long i = 2LL;


while (i * i <= x)
{
if (x % i == 0LL)
{
prim[++p] = i;

while (x % i == 0)
{
x /= i;
++expp[p];
}
}

i += 1LL;
}

if (x > 1LL)
{
prim[++p] = x;
expp[p] = 1;
}
CAPITOLUL 19. ONI 2019 19.1. COPII 213

long long divizor = 1LL, numar = 1LL;


for (int i = 1; i <= p; ++i)
{
if (expp[i] % 2 == 1) --expp[i];

for (int j = 1; j <= expp[i]; ++j)


divizor *= prim[i];

numar *= 1LL * (1 + expp[i]);


}

cout << divizor << " " << numar << ’\n’;
}

return 0;
}

19.1.3 Rezolvare detaliată

Listing 19.1.2: Copii - Etapa nr. 0


#include<iostream> // cout
#include<fstream> // fstream

using namespace std;

ifstream fin("copii.in");
ofstream fout("copii.out");

int C; // nr cerinta

void rezolva1()
{

void rezolva2()
{

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}

return 0;
}

Listing 19.1.3: Copii - Etapa nr. 1


#include<iostream> // cout
#include<fstream> // fstream

using namespace std;

ifstream fin("copii.in");
ofstream fout("copii.out");

int C; // nr cerinta
int X, K; // pentru C=1 ... (K cifre) <=9 ...10ˆ9 ... incape pe int ...
long long Y; // pentru C=2 ... atentie ... Y <= 10ˆ12 ... !!!

int k10; // k10 = 10ˆk ... pentru ultimele k cifre (fac modulo k10)

int nr5; // nr factorilor de 5 pe care ii scot din 1*2*3*...*X (10=2*5)


int nr2; // nr factorilor de 2 pe care ii scot din X (nr2 > nr5 ... sigur!)
CAPITOLUL 19. ONI 2019 19.1. COPII 214

long long p1x; // produs de la 1 la x ... pastrez numai (p1x % k10) ...X*10ˆk =
// = 10ˆ6*10ˆ9 = 10ˆ15 = long long ... !!!

void rezolva1()
{
fin>>X;
fin>>K;
cout<<"X = "<<X<<"\n"; // atentie la X=1 sau X=2 sau X=3 ... !!!
cout<<"K = "<<K<<"\n";

k10=1;
for(int i=1; i<=K; i++) k10=k10*10; // k10 *= 10;
cout<<"\n k10 = "<<k10<<"\n\n";

nr5=0;
for(int i=1; i<=X; i++) // pentru 1*2*3*...*X (nu prea are rost de la 1 ...)
{
int ci=i; // copia lui i ... ca sa nu il stric pe i ...

while(ci%5==0) // atentrie la cele doua = uri !!!


{
nr5++;
ci=ci/5; // ci /= 5;
}
cout<<i<<" : nr5 = "<<nr5<<"\n";
}
cout<<"\n--- nr5 = "<<nr5<<" ---\n\n";

p1x=1LL; // atentie la 1 pentru long long ... !!!


nr2=nr5;
for(int i=2; i<=X; i++)
{
int ci=i; // copia lui i ... ca sa nu il stric pe i ...

while((nr2>0) && (ci%2==0)) // scot 2-urile


{
ci=ci/2; // scot un 2
nr2--;
}

while((nr5>0) && (ci%5==0)) // scot 5-urile


{
ci=ci/5; // scot un 2
nr5--;
}

p1x = p1x * ci;


cout<<i<<" : p1x = "<<p1x;
p1x = p1x % k10;
cout<<"\t = "<<p1x<<"\n";
}

cout<<"\n--- p1x = "<<p1x<<" ---\n\n";

// de pus 0-uri in stanga ... 16 --> 016 ... la test1

int ncp1x=0; // nr cifre p1x


int cp1x=p1x; // copie a lui p1x
while(cp1x>0)
{
ncp1x++;
cp1x=cp1x/10;
}

// scriu (K - ncp1x) zerouri la inceputul rezultatului afisat


for(int i=1; i<=(K-ncp1x); i++)
{
cout<<"0";
}
cout<<p1x<<’\n’;
}

void rezolva2()
{
CAPITOLUL 19. ONI 2019 19.1. COPII 215

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}

return 0;
}

Listing 19.1.4: Copii - Etapa nr. 2


#include<iostream> // cout
#include<fstream> // fstream
#include<stdio.h> // getchar(); // getc(stdin); // in while ... poate sa cicleze "la
infinit" ... !!!

using namespace std;

ifstream fin("copii.in");
ofstream fout("copii.out");

int C; // nr cerinta
int X, K; // pentru C=1 ... (K cifre) <=9 ...10ˆ9 ... incape pe int ...

long long Y; // pentru C=2 ... atentie ... Y <= 10ˆ12 ... !!!

long long Z; // Z divizor <= Y <= 10ˆ12 ... ==> long long
long long ndivz;// nr divizori ai lui Z

int k10; // k10 = 10ˆk ... pentru ultimele k cifre (fac modulo k10)

int nr5; // nr factorilor de 5 pe care ii scot din 1*2*3*...*X (10=2*5)


int nr2; // nr factorilor de 2 pe care ii scot din X (nr2 > nr5 ... sigur!)

long long p1x; // produs de la 1 la x ... pastrez numai (p1x % k10) ...X*10ˆk =
// = 10ˆ6*10ˆ9 = 10ˆ15 = long long ... !!!

void rezolva1()
{
fin>>X;
fin>>K;
cout<<"X = "<<X<<"\n"; // atentie la X=1 sau X=2 sau X=3 ... !!!
cout<<"K = "<<K<<"\n";

k10=1;
for(int i=1; i<=K; i++) k10=k10*10; // k10 *= 10;
cout<<"\n k10 = "<<k10<<"\n\n";

nr5=0;
for(int i=1; i<=X; i++) // pentru 1*2*3*...*X (nu prea are rost de la 1 ... dar...)
{
int ci=i; // copia lui i ... ca sa nu il stric pe i ...

while(ci%5==0) // atentrie la cele doua = uri !!!


{
nr5++;
ci=ci/5; // ci /= 5;
}
cout<<i<<" : nr5 = "<<nr5<<"\n";
}
cout<<"\n--- nr5 = "<<nr5<<" ---\n\n";

p1x=1LL; // atentie la 1 pentru long long ... !!!


nr2=nr5;
for(int i=2; i<=X; i++)
{
int ci=i; // copia lui i ... ca sa nu il stric pe i ...

while((nr2>0) && (ci%2==0)) // scot 2-urile


{
CAPITOLUL 19. ONI 2019 19.1. COPII 216

ci=ci/2; // scot un 2
nr2--;
}

while((nr5>0) && (ci%5==0)) // scot 5-urile


{
ci=ci/5; // scot un 2
nr5--;
}

p1x = p1x * ci;


cout<<i<<" : p1x = "<<p1x;
p1x = p1x % k10;
cout<<"\t = "<<p1x<<"\n";
}

cout<<"\n--- p1x = "<<p1x<<" ---\n\n";

// de pus 0-uri in stanga ... 16 --> 016 ... la test1

int ncp1x=0; // nr cifre p1x


int cp1x=p1x; // copie a lui p1x
while(cp1x>0)
{
ncp1x++;
cp1x=cp1x/10;
}

// scriu (K - ncp1x) zerouri la inceputul rezultatului afisat


for(int i=1; i<=(K-ncp1x); i++)
{
cout<<"0";
}
cout<<p1x<<’\n’;
}

void rezolva2()
{
fin>>Y;
//Y=1LL*2*2*3*3*3*3*5*7*7*7;
cout<<"Y = "<<Y<<"\n\n"; // atentie la Y=1 sau Y=2 sau Y=3 ... !!!
//getchar();

// Z = f1ˆe1 * f2ˆe2 * ... fnˆen unde fi=factor_i si ei=exponent_i


// nr_divizori(Z) = (1+e1)*(1+e2)*...*(1+en) = impar
// ==> toate parantezele sunt impare
// ==> toti exponentii sunt pari
// ==> Z = patrat perfect

// Daca Y=patrat perfect ==> sa ia Z = Y


// Daca Y NU ESTE patrat perfect ==> se ia CEL MAI MARE patrat perfect
// adica, se ia fiecare factor fi la cea mai mare putere para la care apare
...

Z=1LL; // pentru produsul factorilor


ndivz=1LL; // nr divizorilor lui Z

int fp; // factor prim de incercat: 2, 3, 5, 7, 9(?), 11, 13, 15(?), 17, 19,
21(?), ...
int nfp; // de cate ori apare factorul prim fp
long long cy=Y; // copia lui Y ... atentie la ... long long ... !!!

fp=2;
nfp=0;
while((cy > 0) && (cy%fp == 0)) // 2-urile ...
{
nfp++;
cy=cy/fp;
//getchar();
}
if(nfp>0)
cout<<"fp = "<<fp<<" nfp = "<<nfp<<"\n";
//getchar();

if(nfp%2==1) nfp--; // sa apara de nr par de ori ...


CAPITOLUL 19. ONI 2019 19.2. NUMERE 217

for(int i=1; i<=nfp; i++) Z = Z*fp;


ndivz=ndivz*(1+nfp);

cout<<"fp = "<<fp<<" nfp = "<<nfp<<" Z = "<<Z<<


" ndivz = "<<ndivz<<" cy = "<<cy<<"\n\n";

fp=3;
while(fp*fp <= cy)
{
// fp=2; // scapa in bucla infinita ... !!!
nfp=0;

while((cy > 0) && (cy%fp == 0)) // fp-urile ...


{
nfp++;
cy=cy/fp;
//getchar();
}
if(nfp>0)
cout<<"fp = "<<fp<<" nfp = "<<nfp<<"\n";

if(nfp%2==1) nfp--; // sa apara de nr par de ori ...

for(int i=1; i<=nfp; i++) Z = Z*fp;

ndivz=ndivz*(1LL+nfp);

if(nfp>0)
cout<<"fp = "<<fp<<" nfp = "<<nfp<<" Z = "<<Z<<
" ndivz = "<<ndivz<<" cy = "<<cy<<"\n\n";

fp=fp+2;
//getchar();
}
cout<<"\n --- cy = "<<cy<<" --- \n\n"; // ce a ramas ...

cout<<Z<<’ ’<<ndivz<<’\n’;
}

int main()
{
fin>>C;
cout<<"C = "<<C<<"\n";

if(C==1) {rezolva1(); return 0;}


if(C==2) {rezolva2(); return 0;}

return 0;
}

19.2 Numere
Problema 2 - Numere 100 de puncte
Într-o zi, Ioana a scris toate numerele naturale de N cifre fiecare ı̂ndeplinind, simultan, condiţiile:
- numărul format din primele două cifre este pătrat perfect;
- a treia cifră este obligatoriu număr prim;
- nu conţine două cifre pare alăturate şi nici două cifre impare alăturate.
De exemplu, numerele de trei cifre, scrise de Ioana, sunt:
163, 165, 167, 252, 363, 365, 367, 492, 812.

Cerinţe

Cunoscându-se numerele N şi X, scrieţi un program care determină:


1) câte numere de N cifre ı̂ndeplinesc cele trei condiţii din enunţ;
2) care este cel mai apropiat număr de X, diferit de X, care să ı̂ndeplinească cele trei condiţii
din enunţ şi care să aibă acelaşi număr de cifre ca X. Dacă există două astfel de numere, egal
depărtate de X, se va afişa cel mai mic dintre ele.

Date de intrare
CAPITOLUL 19. ONI 2019 19.2. NUMERE 218

Fişierul de intrare numere.in conţine pe prima linie un număr natural C. Numărul C poate
avea doar valorile 1 sau 2. Pe a doua linie se află, ı̂n cazul primei cerinţe, numărul N, iar ı̂n cazul
celei de-a doua cerinţe, numărul X.

Date de ieşire
Dacă valoarea lui C este 1, se va rezolva doar cerinţa 1). În acest caz, fişierul de ieşire
numere.out va conţine pe prima linie un număr natural, reprezentând rezultatul determinat
pentru prima cerinţă.
Dacă valoarea lui C este 2, se va rezolva doar cerinţa 2). În acest caz, fişierul de ieşire
numere.out va conţine pe prima linie un număr natural, reprezentând rezultatul determinat
pentru cea de a doua cerinţă.
Restricţii şi precizări
a 3 & N & 29
a 100 & X & 20 000 000
a Pentru rezolvarea primei cerinţe se acordă 30 de puncte, iar pentru rezolvarea celei de a doua
cerinţe se acordă 70 de puncte.

Exemple
numere.in numere.out Explicaţii
1 45 Numerele de patru cifre, scrise de Ioana, sunt:
4 1630, 1632, 1634, 1636, 1638, 1650, 1652, 1654, 1656,
1658, 1670, 1672, 1674, 1676, 1678, 2521, 2523, 2525,
2527, 2529, 3630, 3632, 3634, 3636, 3638, 3650, 3652,
3654, 3656, 3658, 3670, 3672, 3674, 3676, 3678, 4921,
4923, 4925, 4927, 4929, 8121, 8123, 8125, 8127, 8129.
2 167 Cel mai apropiat număr de 200 este 167 (numerele de
200 trei cifre, scrise de Ioana, sunt: 163, 165, 167, 252, 363,
365, 367, 492, 812).

Timp maxim de executare/test: 0.5 secunde


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

19.2.1 Indicaţii de rezolvare

Prof. Ana-Maria Arişanu, Colegiul Naţional Mircea cel Bătrân, Rm. Vâlcea

a) Numerele ce respectă condiţiile din enunţ pot ı̂ncepe cu 16, 25, 36, 49 sau 81
Caz 1. Dacă ı̂ncep cu 16 sau 36 a treia cifra poate fi 3, 5 sau7.
Caz 2. Dacă ı̂ncep cu 25, 49 sau 81 a treia cifra poate fi doar 2
Începând cu a patra cifra avem câte 5 posibilităţi, respectiv 0, 2, 4, 6 sau 8 (pentru cazul 1) şi
1, 3, 5, 7 sau 9 (pentru cazul 2)
Numărul de numere de N cifre care respectă condiţiile din enunţ este:
2 ˜ 3 ˜ 5 n  3  3 ˜ 5 n  3 9 ˜ 5 n  3
b) Fie k numărul de cifre ale numărului X.
Construim xmin ca fiind cel mai mic număr de k cifre ce respectă condiţiile din enunţ %
xmin = 163010101 ...
Construim xmax ca fiind cel mai mare număr de k cifre ce respectă condiţiile din enunţ %
xmax = 812989898...
Determinăm cel mai mic număr, mai mare decât x ce respectă condiţiile din enunţ (dacă
există). Acest număr nu poate fi mai mare decât xmax.
Determinăm cel mai mare număr, mai mic decât x ce respectă condiţiile din enunţ (dacă
există). Acest număr nu poate fi mai mic decât xmin.
Dintre cele două numere determinate se afişează cel mai aproape de X.
CAPITOLUL 19. ONI 2019 19.2. NUMERE 219

19.2.2 Cod sursă

Listing 19.2.1: numere cpp.cpp


#include <fstream>

using namespace std;

ifstream f("numere.in");
ofstream g ("numere.out");

int main()
{
int p,n,x,dif1=20000000,dif2=20000000,y,xx;
long long xmin,xmax,i, nr1,nr2;
unsigned long long nr;

f>>p;
if (p==1)
{
f>>n;
nr=9;
for (i=1; i<=n-3; i++)
nr=nr*5;
g<<nr<<’\n’;
}
else
{
f>>x;
y=x;
xmin=163;
xmax=812;
i=3;
while (y>999)
{
i++;
if (i%2==0)
{
xmin=xmin*10;
xmax=xmax*10+9;
}
else
{
xmin=xmin*10+1;
xmax=xmax*10+8;
}
y=y/10;
}

if (x<xmin) g<<xmin;
else
if (x>xmax) g<<xmax;
else
{
for (xx=x-1; xx>=xmin; xx--)
{
int v[11],k=0,n2,i,xxx=xx, bun=1;

while (xxx>99)
{
k++;
v[k]=xxx%10;
xxx=xxx/10;
}

if (xxx!=16 && xxx!=25 && xxx!=36 && xxx!=49 && xxx!=81) bun=0;
else if ((xxx==16|| xxx==36)&& (v[k]!=3 && v[k]!=5 && v[k]!=7))
bun=0;
else if ((xxx==25 || xxx==49 ||xxx==81) && v[k]!=2) bun=0;
else
for (i=k-1; i>=1; i--)
if (v[i]%2==v[i+1]%2) bun=0;
if (bun)
{
CAPITOLUL 19. ONI 2019 19.2. NUMERE 220

nr1=xx;
dif1=x-nr1;
break;
}
}

for (xx=x+1; xx<=xmax; xx++)


{
int v[11],k=0,n2,i,xxx=xx, bun=1;
while (xxx>99)
{
k++;
v[k]=xxx%10;
xxx=xxx/10;
}
if (xxx!=16 && xxx!=25 && xxx!=36 && xxx!=49 && xxx!=81) bun=0;
else if ((xxx==16|| xxx==36)&& (v[k]!=3 && v[k]!=5 && v[k]!=7))
bun=0;
else if ((xxx==25 || xxx==49 ||xxx==81) && v[k]!=2) bun=0;
else
for (i=k-1; i>=1; i--)
if (v[i]%2==v[i+1]%2) bun=0;
if (bun)
{
nr2=xx;
dif2=nr2-x;
break;
}
}

if (dif1<=dif2)
g<<nr1<<’\n’;
else
g<<nr2<<’\n’;
}
}
}

19.2.3 Rezolvare detaliată

Atenţie la enunţ: ... ” cel mai apropiat număr de X, diferit de X,” ...
Exemplu pentru 3 cifre:

zona16 zona25 zona36 zona49 zona81

100 163 165 167 252 363 365 367 492 812 999
Figura 19.1: Numere cu 3 cifre

Dacă X este ı̂n stı̂nga zonei zona16 (de exemplu X 150) atunci rezultatul este 163.
Dacă X este ı̂n dreapta zonei zona81 (de exemplu X 900) atunci rezultatul este 812.
Altfel, X are doi vecini, unul ı̂n stânga şi unul ı̂n dreapta.
Dacă, de exemplu, X 166, cei doi vecini sunt 165 şi 167 din accelaşi grup zona16.
Dacă, de exemplu, X 444, cei doi vecini sunt 367 şi 492 din grupuri diferite dar adiacente.
Mai precis, X 444 este ı̂ntre zonele zona36 şi zona49 iar cei doi vecini sunt: cel mai mare din
zona zona36 şi cel mai mic din zona zona49.
Exemplu pentru 4 cifre:

zona16 zona25 zona36 zona49 zona81

1000 1630 16.. 1678 252. 3630 36.. 3678 492. 812. 9999

Figura 19.2: Numere cu 4 cifre

Pentru nc 4 zona zona25 r2521, 2523, 2525, 2527, 2529x.


CAPITOLUL 19. ONI 2019 19.2. NUMERE 221

(celelalte zone sunt deja precizate ı̂n enunţul problemei).


Exemplu pentru 5 cifre:

zona16 zona25 zona36 zona49 zona81

10000 16301 16... 16789 252.. 36301 36... 36789 492.. 812.. 99999

Figura 19.3: Numere cu 5 cifre

Pentru nc 5 zona

zona25 r25210, 25212, 25214, 25216, 25218,


25230, 25232, 25234, 25236, 25238,
25250, 25252, 25254, 25256, 25258,
25270, 25272, 25274, 25276, 25278,
25290, 25292, 25294, 25296, 25298x. (19.2.1)

Celelalte zone NU mai sunt precizate ı̂n enunţul problemei dar sunt uşor de intuit! Pentru
nc 6, 7, 8 zonele sunt tot mai depărtate (de 0) şi conţin tot mai multe numere fiecare!
Pentru nc 8 reprezentarea tabelară ne va ajuta să programăm mai uşor!
Pentru 16:

1 2 3 4 5 6 7 8

pătrat prim paritati diferite


1 6 3 0 1 0 1 0
1 6 3 ... ... ... ... ...
1 6 3 8 9 8 9 8
1 6 5 0 1 0 1 0
1 6 5 ... ... ... ... ...
1 6 5 8 9 8 9 8
1 6 7 0 1 0 1 0
1 6 7 ... ... ... ... ...
1 6 7 8 9 8 9 8

Pentru 25:

1 2 3 4 5 6 7 8

pătrat prim paritati diferite


2 5 2 1 0 1 0 1
2 5 2 ... ... ... ... ...
2 5 2 9 8 9 8 9

Pentru 36:

1 2 3 4 5 6 7 8

pătrat prim paritati diferite


3 6 3 0 1 0 1 0
3 6 3 ... ... ... ... ...
3 6 3 8 9 8 9 8
3 6 5 0 1 0 1 0
3 6 5 ... ... ... ... ...
3 6 5 8 9 8 9 8
3 6 7 0 1 0 1 0
3 6 7 ... ... ... ... ...
3 6 7 8 9 8 9 8

Pentru 49:
CAPITOLUL 19. ONI 2019 19.2. NUMERE 222

1 2 3 4 5 6 7 8

pătrat prim paritati diferite


4 9 2 1 0 1 0 1
4 9 2 ... ... ... ... ...
4 9 2 9 8 9 8 9

Pentru 81:

1 2 3 4 5 6 7 8

pătrat prim paritati diferite


8 1 2 1 0 1 0 1
8 1 2 ... ... ... ... ...
8 1 2 9 8 9 8 9

Pentru 81 puţin mai detaliat la mijlocul zonei:

1 2 3 4 5 6 7 8

pătrat prim paritati diferite


8 1 2 1 0 1 0 1
8 1 2 ... ... ... ... ...
8 1 2 5 0 1 0 1
8 1 2 5 0 1 0 3
8 1 2 5 0 1 0 5
8 1 2 5 0 1 0 7
8 1 2 5 0 1 0 9
8 1 2 5 0 1 2 1
8 1 2 5 0 1 2 3
8 1 2 ... ... ... ... ...
8 1 2 5 8 9 6 7
8 1 2 5 8 9 6 9
8 1 2 5 8 9 8 1
8 1 2 5 8 9 8 3
8 1 2 5 8 9 8 5
8 1 2 5 8 9 8 7
8 1 2 5 8 9 8 9
8 1 2 ... ... ... ... ...
8 1 2 9 8 9 8 9

Mişcarea contorului electric sau a kilometrajului de la maşină!


Când se măreşte valoarea cu o unitate:
1. Se măreşte cu o unitate ultima cifră (cea din dreapta).
2. Dacă nu se poate (pentru că este ”9” = cea mai mare cifră permisă pe poziţia verificată),
se caută spre stânga prima poziţie care se poate mări şi se pun pe ”0” toate poziţiile prin care s-a
trecut. (”0” este cea mai mică cifră permisă pe poziţia verificată).
Când se micşorează valoarea cu o unitate:
1. Se micşorează cu o unitate ultima cifră (cea din dreapta).
2. Dacă nu se poate (pentru că este ”0”), se caută spre stânga prima poziţie care se poate
micşora şi se pun pe ”9” toate poziţiile prin care s-a trecut. (”9” este cea mai mare cifră permisă
pe poziţia verificată).
Un exemplu pentru nc 7 (numărul cifrelor):

1 2 3 4 5 6 7

pătrat prim paritati diferite


1 5 2 7 0 7 0
... ... ... ... ... ... ...
1 6 3 0 0 9 9
... ... ... ... ... ... ...
1 6 3 0 1 0 1 min16 = min163
... ... ... ... ... ... ...
3 6 7 8 9 8 9 max36 = max367
CAPITOLUL 19. ONI 2019 19.2. NUMERE 223

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


4 4 4 4 4 4 4
... ... ... ... ... ... ...
4 9 2 1 0 1 0 min49 = min492
... ... ... ... ... ... ...
8 1 2 9 8 9 8 max81 = max812
... ... ... ... ... ... ...
8 1 2 9 9 0 0
... ... ... ... ... ... ...
8 2 0 0 0 0 0

Un exemplu pentru nc 7 (numărul cifrelor):

1 2 3 4 5 6 7

pătrat prim paritati diferite


... ... ... ... ... ... ...
3 6 3 0 1 0 1 min363
... ... ... ... ... ... ...
3 6 3 8 9 8 9 max363
3 6 5 0 1 0 1 min365
... ... ... ... ... ... ...

3 6 5 4 0 0 0 err!
3 6 5 4 1 0 1
... ... ... ... ... ... ...
3 6 5 8 9 8 9 max365
3 6 7 0 1 0 1 min367
... ... ... ... ... ... ...

Celalalt vecin este:

1 2 3 4 5 6 7

pătrat prim paritati diferite


3 6 5 2 9 8 9
3 6 5 4 1 0 1

Evident, numărul este ı̂ntre cei doi vecini:

1 2 3 4 5 6 7

pătrat prim paritati diferite


... ... ... ... ... ... ...
3 6 5 2 9 8 9
3 6 5 4 0 0 0 err!
3 6 5 4 1 0 1
... ... ... ... ... ... ...

Un exemplu pentru nc 7 (numărul cifrelor):


CAPITOLUL 19. ONI 2019 19.2. NUMERE 224

1 2 3 4 5 6 7

pătrat prim paritati diferite


... ... ... ... ... ... ...
3 6 3 0 1 0 1 min363
... ... ... ... ... ... ...
3 6 3 8 9 8 9 max363
3 6 5 0 1 0 1 min365
... ... ... ... ... ... ...
3 6 5 4 9 8 9
3 6 5 4 9 9 0 err!
... ... ... ... ... ... ...
3 6 5 8 9 8 9 max365
3 6 7 0 1 0 1 min367
... ... ... ... ... ... ...

Celalalt vecin este:

1 2 3 4 5 6 7

pătrat prim paritati diferite


3 6 5 4 9 8 9
3 6 5 6 1 0 1

Evident, numarul este intre cei doi vecini.

1 2 3 4 5 6 7

pătrat prim paritati diferite


... ... ... ... ... ... ...
3 6 5 4 9 8 9
3 6 5 4 9 9 0 err!
3 6 5 6 1 0 1
... ... ... ... ... ... ...

În final se cristalizează următoarea idee de rezolvare:


1. dacă numărul este ı̂ntre grupuri se determină şi se afişează soluţia, v1 sau v2, pentru care
se realizează min(nr-v1, v2-nr) unde v1 = maxGrupStanga şi v2 = minGrupDreapta
2. dacă numărul este ı̂ntr-un grup
2a. se determină unul dintre cei mai apropiaţi vecini (v1 = mai mic sau v2 = mai mare, decât
numărul)
2b. se determină celălalt vecin al numărului (succesor sau predecesor, ı̂n secvenţa numerelor
valabile)
2c. se afişează soluţia, v1 sau v2, pentru care se realizează min(nr-v1, v2-nr)
Obs. Cei mai experimentaţi pot folosi aceste idei şi pot obţine un algoritm apropiat de cei
prezentaţi oficial! Adică,
1. se determină poziţia eronată
2. se construieşte elementul corect ı̂ n secvenţă mai mic (dacă se poate micşora acea valoare
din poziţia eronată) sau mai mare (dacă nu se poate ...)
3. se completează cu ce trebuie ca să fie cât mai mare/mic ... ı̂n funcţie de alegerea facută la
2.
4. se determină succesorul/predecesorul
5. se determină soluţia

Structura generală şi rezolvarea primei cerinţe

Listing 19.2.2: Numere - Etapa nr. 0


#include<iostream> // cout ... afisari pe ecran ... !!!
#include<fstream> // fstream

using namespace std;

ifstream fin("numere.in");
CAPITOLUL 19. ONI 2019 19.2. NUMERE 225

ofstream fout("numere.out");

int C;
int N;
int X; // 20.000.000 incape pe "int"

int nr3c[9] = { 163, 165, 167, 252, 363, 365, 367, 492, 812 };

long long rez1=9; // unsigned long long ... este mai OK!

void rezolva1()
{
fin>>N;

rez1=9LL;
for(int i=1; i<=min(N-3,28-3); i++)// N=28 este ultimul care este ok
rez1=rez1*5;

if(N==29) // trebuie si ultima inmultire cu 5 ... !!!


{
int v[21]; // vector cu cifrele rezultatului
int i; // variabila de lucru ... trebuie si in afara for-ului

int poz=-1; // pozitia in vectorul cifrelor lui rez1


while(rez1>0L)
{
poz++;
v[poz]=rez1%10;
rez1=rez1/10;
}

// inmultirea rez*5
int t=0; // cifra de transport ... la inmultire
for(i=0; i<=poz; i++)
{
int cifra=v[i]*5+t;
v[i]=cifra%10;
t=cifra/10;
}
if(t>0) { v[i]=t; poz++; }
for(i=poz; i>=0; i--) fout<<v[i];
fout<<’\n’;
}
else
fout<<rez1<<’\n’;
}

void rezolva2()
{

int main()
{
fin>>C;

if(C==1) rezolva1();
if(C==2) rezolva2();

return 0;
}

Variabile globale pentru cerinţa 2

Listing 19.2.3: Numere - Etapa nr. 1


int C;
int N;
int X; // 20.000.000 incape pe "int"

int nr3c[9] = { 163, 165, 167, 252, 363, 365, 367, 492, 812 };

long long rez1=9; // unsigned long long ... este mai OK!
int rez2, rez2min, rez2max; // solutie pentru Cerinta 2
CAPITOLUL 19. ONI 2019 19.2. NUMERE 226

int vcifx[9]; // indici 0, 1, ..., 8 ... vcifx[8] EROARE la ncx=8 ...


int vcifxs[9]; // nr mai mic decat X (in stanga) ... predecesor
int vcifxd[9]; // nr mai mare decat X (in dreapta) ... succesor

int ncx; // nr cifre in X


int pozincorecta; // pozitia ... cu cifra incorecta

int x123; // primele 3 cifre


int x12; // primele 2 cifre
int x3; // cifra x3
int x2; // cifra x2

222

Listing 19.2.4: Numere - Etapa nr. 2


void rezolva2()
{
fin>>X;

nrcifrex(X);
vcifrex(X);

x123=X;
for(int i=ncx; i>=4; i--) x123=x123/10;
x12=x123/10;
x3=x123%10;

calcpozincorecta();

if(pozincorecta>ncx) // X este OK ...


{
rez2=X; // ... trebuie sa fie DIFERIT de X ... !!!

int x123min=f123min(x123);
int x123max=f123max(x123);

if(X < x123max) succesorX(); // vcifxd[]


if(X > x123min) predecesorX(); // vcifxs[]

rez2min=rez2max=0;
for(int i=1; i<=ncx; i++)
{
rez2min=rez2min*10+vcifxs[i];
rez2max=rez2max*10+vcifxd[i];
}

if(X == x123min) rez2 = rez2max;


else
if(X == x123max) rez2 = rez2min;
else
{
rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
}
}
else
if(pozincorecta<=3) pozincorecta23();
else pozincorecta45678();

fout<<rez2<<’\n’;
}

333

Listing 19.2.5: Numere - Etapa nr. 3


void nrcifrex(int x)
{
ncx=0;
CAPITOLUL 19. ONI 2019 19.2. NUMERE 227

while(x>0) { ncx++; x=x/10; }


}

void vcifrex(int x)
{
for(int i=1; i<=ncx; i++)
{
vcifx[ncx-i+1]=x%10;
x=x/10;
}
}

void calcpozincorecta()
{
if(x12 != 16 && x12 != 25 && x12 != 36 && x12 != 49 && x12 != 81)
pozincorecta=2;
else
if(!(x3 == 2 || x3 == 3 || x3 == 5 || x3 == 7) && (x3+x2)%2==1)
pozincorecta=3;
else
{
int i=4;
while((i<=ncx) && (vcifx[i]+vcifx[i-1])%2==1) i++;
pozincorecta=i;
}
}

int f123min(int c123)


{
int c123min=c123;
for(int i=4; i<=ncx; i++)
if(c123min%2==0) c123min=c123min*10+1;
else c123min=c123min*10+0;

return c123min;
}

int f123max(int c123)


{
int c123max=c123;
for(int i=4; i<=ncx; i++)
if(c123max%2==0) c123max=c123max*10+9;
else c123max=c123max*10+8;

return c123max;
}

void succesorX() // dupa X = OK


{
for(int i=1; i <= ncx; i++) vcifxd[i]=vcifx[i];

int poz=ncx;
while(vcifxd[poz]>=8) // nu pot sa adun 2 (sa rapana paritatea ok!)
poz=poz-1;

vcifxd[poz]=vcifxd[poz]+2;

// completez spre dreapta cu 0, 1 ...


for(int i=poz+1; i<=ncx; i++)
if(vcifxd[i-1]%2==0) vcifxd[i]=1;
else vcifxd[i]=0;

void predecesorX() // inainte de X = OK


{
for(int i=1; i<=ncx; i++) vcifxs[i]=vcifx[i]; // copie

int poz=ncx;
while(vcifx[poz]<=1) // nu pot sa scad 2 (sa ramana paritatea ok!)
poz=poz-1;

vcifxs[poz]=vcifx[poz]-2;

// completez spre dreapta cu 8, 9 ...


for(int i=poz+1; i<=ncx; i++)
CAPITOLUL 19. ONI 2019 19.2. NUMERE 228

if(vcifxs[i-1]%2==0) vcifxs[i]=9;
else vcifxs[i]=8;
}

444

Listing 19.2.6: Numere - Etapa nr. 4


void pozincorecta23() // 163 165 167 252 363 365 367 492 812
{
if(x123<163) { rez2=f123min(163); return;}
if(x123>812) { rez2=f123max(812); return;}

if(x123<252) // 16 < x12 < 25


{
rez2min=f123max(167); // patrat, prim cel mai mare permis
rez2max=f123min(252); // patrat, prim cel mai mic permis
rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
return;
}

if(x12<36) // 25 < x12 < 36


{
rez2min=f123max(252);
rez2max=f123min(361);
rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
return;
}

if(x12<49) // 36 < x12 < 49


{
rez2min=f123max(367);
rez2max=f123min(492);
rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
return;
}

if(x12<81) // 49 < x12 < 81


{
rez2min=f123max(492);
rez2max=f123min(812);
rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
return;
}
}

void pozincorecta45678()
{
if(vcifx[pozincorecta]>=1) // pot sa scad 1 ... corectez paritatea !!!
{
calcvcifxs();
succesor();
}
else // sigur pot sa adun 1 ... corectez paritatea !!!
{
calcvcifxd();
predecesor();
}

rez2min=rez2max=0;
for(int i=1; i<=ncx; i++)
{
rez2min=rez2min*10+vcifxs[i];
rez2max=rez2max*10+vcifxd[i];
}

rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
}
CAPITOLUL 19. ONI 2019 19.2. NUMERE 229

555

Listing 19.2.7: Numere - Etapa nr. 5


#include<iostream> // cout ... afisari pe ecran ... !!!
#include<fstream> // fstream

using namespace std;

ifstream fin("numere.in");
ofstream fout("numere.out");

int C;
int N;
int X; // 20.000.000 incape pe "int"

int nr3c[9] = { 163, 165, 167, 252, 363, 365, 367, 492, 812 };

long long rez1=9; // unsigned long long ... este mai OK!
int rez2, rez2min, rez2max; // solutie pentru Cerinta 2

int vcifx[9]; // indici 0, 1, ..., 8 ... vcifx[8] EROARE la ncx=8 ...


int vcifxs[9]; // nr mai mic decat X (in stanga) ... predecesor
int vcifxd[9]; // nr mai mare decat X (in dreapta) ... succesor

int ncx; // nr cifre in X


int pozincorecta; // pozitia ... cu cifra incorecta

int x123; // primele 3 cifre


int x12; // primele 2 cifre
int x3; // cifra x3
int x2; // cifra x2

void rezolva1()
{
fin>>N;

rez1=9LL;
for(int i=1; i<=min(N-3,28-3); i++)// N=28 este ultimul care este ok
rez1=rez1*5;

if(N==29) // trebuie si ultima inmultire cu 5 ... !!!


{
int v[21]; // vector cu cifrele rezultatului
int i; // variabila de lucru ... trebuie si in afara for-ului

int poz=-1; // pozitia in vectorul cifrelor lui rez1


while(rez1>0L)
{
poz++;
v[poz]=rez1%10;
rez1=rez1/10;
}

// inmultirea rez*5
int t=0; // cifra de transport ... la inmultire
for(i=0; i<=poz; i++)
{
int cifra=v[i]*5+t;
v[i]=cifra%10;
t=cifra/10;
}
if(t>0) { v[i]=t; poz++; }
for(i=poz; i>=0; i--) fout<<v[i];
fout<<’\n’;
}
else
fout<<rez1<<’\n’;
}

void nrcifrex(int x)
{
ncx=0;
while(x>0) { ncx++; x=x/10; }
}
CAPITOLUL 19. ONI 2019 19.2. NUMERE 230

void vcifrex(int x)
{
for(int i=1; i<=ncx; i++)
{
vcifx[ncx-i+1]=x%10;
x=x/10;
}
}

void predecesorX() // inainte de X = OK


{
for(int i=1; i<=ncx; i++) vcifxs[i]=vcifx[i]; // copie

int poz=ncx;
while(vcifx[poz]<=1) // nu pot sa scad 2 (sa ramana paritatea ok!)
poz=poz-1;

vcifxs[poz]=vcifx[poz]-2;

// completez spre dreapta cu 8, 9 ...


for(int i=poz+1; i<=ncx; i++)
if(vcifxs[i-1]%2==0) vcifxs[i]=9;
else vcifxs[i]=8;
}

void predecesor() // inainte de vcifxd[] = existent deja


{
for(int i=1; i<=ncx; i++) vcifxs[i]=vcifxd[i]; // copie

int poz=ncx;
while(vcifxd[poz]<=1) // nu pot sa scad 2 (sa ramana paritatea ok!)
poz=poz-1;

vcifxs[poz]=vcifxd[poz]-2;

// completez spre dreapta cu 8, 9 ...


for(int i=poz+1; i<=ncx; i++)
if(vcifxs[i-1]%2==0) vcifxs[i]=9;
else vcifxs[i]=8;

void succesorX() // dupa X = OK


{
for(int i=1; i <= ncx; i++) vcifxd[i]=vcifx[i];

int poz=ncx;
while(vcifxd[poz]>=8) // nu pot sa adun 2 (sa ramana paritatea ok!)
poz=poz-1;

vcifxd[poz]=vcifxd[poz]+2;

// completez spre dreapta cu 0, 1 ...


for(int i=poz+1; i<=ncx; i++)
if(vcifxd[i-1]%2==0) vcifxd[i]=1;
else vcifxd[i]=0;

void succesor() // dupa vcifxs[] = existent deja ... !!!


{
for(int i=1; i<=ncx; i++) vcifxd[i]=vcifxs[i]; // copie

int poz=ncx;
while(vcifxd[poz]>=8) // nu pot sa adun 2 (sa ramana paritatea ok!)
poz=poz-1;

vcifxd[poz]=vcifxd[poz]+2;

// completez spre dreapta cu 0, 1 ...


for(int i=poz+1; i<=ncx; i++)
if(vcifxd[i-1]%2==0) vcifxd[i]=1;
else vcifxd[i]=0;

}
CAPITOLUL 19. ONI 2019 19.2. NUMERE 231

int f123min(int c123)


{
int c123min=c123;
for(int i=4; i<=ncx; i++)
if(c123min%2==0) c123min=c123min*10+1;
else c123min=c123min*10+0;

return c123min;
}

int f123max(int c123)


{
int c123max=c123;
for(int i=4; i<=ncx; i++)
if(c123max%2==0) c123max=c123max*10+9;
else c123max=c123max*10+8;

return c123max;
}

calcvcifxs() // pot sa scad ... construiesc vcifxs[] cat mai mare


{
for(int i=1; i<=pozincorecta; i++) vcifxs[i]=vcifx[i]; // copie ...
vcifxs[pozincorecta]-=1; // scad 1 ==> se repara paritatea

for(int i=pozincorecta+1; i<=ncx; i++)


if(vcifxs[i-1]%2==0) vcifxs[i]=9;
else vcifxs[i]=8;

calcvcifxd() // pot sa adun 1 ... construiesc vcifxd[] cat mai mic


{
for(int i=1; i<=pozincorecta; i++) vcifxs[i]=vcifx[i]; // copie ...
vcifxd[pozincorecta]+=1; // adun 1 ==> se repara paritatea

for(int i=pozincorecta+1; i<=ncx; i++)


if(vcifxd[i-1]%2==0) vcifxd[i]=1;
else vcifxd[i]=0;

void calcpozincorecta()
{
if(x12 != 16 && x12 != 25 && x12 != 36 && x12 != 49 && x12 != 81)
pozincorecta=2;
else
if(!(x3 == 2 || x3 == 3 || x3 == 5 || x3 == 7) && (x3+x2)%2==1)
pozincorecta=3;
else
{
int i=4;
while((i<=ncx) && (vcifx[i]+vcifx[i-1])%2==1) i++;
pozincorecta=i;
}
}

void pozincorecta23() // 163 165 167 252 363 365 367 492 812
{
if(x123<163) { rez2=f123min(163); return;}
if(x123>812) { rez2=f123max(812); return;}

if(x123<252) // 16 < x12 < 25


{
rez2min=f123max(167); // patrat, prim cel mai mare permis
rez2max=f123min(252); // patrat, prim cel mai mic permis
rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
return;
}

if(x12<36) // 25 < x12 < 36


{
rez2min=f123max(252);
rez2max=f123min(361);
rez2=rez2min;
CAPITOLUL 19. ONI 2019 19.2. NUMERE 232

if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X


return;
}

if(x12<49) // 36 < x12 < 49


{
rez2min=f123max(367);
rez2max=f123min(492);
rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
return;
}

if(x12<81) // 49 < x12 < 81


{
rez2min=f123max(492);
rez2max=f123min(812);
rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
return;
}
}

void pozincorecta45678()
{
if(vcifx[pozincorecta]>=1) // pot sa scad 1 ... corectez paritatea !!!
{
calcvcifxs();
succesor();
}
else // pot sa adun 1 ... corectez paritatea !!!
{
calcvcifxd();
predecesor();
}

rez2min=rez2max=0;
for(int i=1; i<=ncx; i++)
{
rez2min=rez2min*10+vcifxs[i];
rez2max=rez2max*10+vcifxd[i];
}

rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
}

void rezolva2()
{
fin>>X;

nrcifrex(X);
vcifrex(X);

x123=X;
for(int i=ncx; i>=4; i--) x123=x123/10;
x12=x123/10;
x3=x123%10;

calcpozincorecta();

if(pozincorecta>ncx) // X este OK ...


{
rez2=X; // ... trebuie sa fie DIFERIT de X ... !!!

int x123min=f123min(x123);
int x123max=f123max(x123);

if(X < x123max) succesorX(); // vcifxd[]


if(X > x123min) predecesorX(); // vcifxs[]

rez2min=rez2max=0;
for(int i=1; i<=ncx; i++)
{
rez2min=rez2min*10+vcifxs[i];
rez2max=rez2max*10+vcifxd[i];
CAPITOLUL 19. ONI 2019 19.3. TRIO 233

if(X == x123min) rez2 = rez2max;


else
if(X == x123max) rez2 = rez2min;
else
{
rez2=rez2min;
if(rez2max-X < X-rez2min) rez2=rez2max; // mai aproape de X
}
}
else
if(pozincorecta<=3) pozincorecta23();
else pozincorecta45678();

fout<<rez2<<’\n’;
}

int main()
{
fin>>C;

if(C==1) rezolva1();
if(C==2) rezolva2();

return 0;
}

19.3 Trio
Problema 3 - Trio 100 de puncte
Trio este un joc ce conţine N piese de aceeaşi formă, aşezate una lângă alta pe o tablă de joc
şi numerotate de la stânga la dreapta cu valori de la 1 la N. Fiecare piesă are marcate pe ea trei
zone, iar ı̂n fiecare dintre ele este scrisă câte o cifră. Se consideră că o piesă pe care sunt scrise ı̂n
ordine, de la stânga la dreapta, cifrele C1,C2 şi C3 are următoarele proprietăţi:
este identică cu o altă piesă, dacă această piesă conţine exact aceleaşi cifre, ı̂n aceeaşi ordine
cu ale ei sau ı̂n ordine inversă. Astfel, piesa C1 C2 C3 este identică cu o altă piesă de
forma C1 C2 C3 şi cu o piesă de forma C3 C2 C1 .
este prietenă cu o altă piesă dacă aceasta conţine exact aceleaşi cifre ca piesa dată,
dar nu neapărat ı̂n aceeaşi ordine. Astfel, piesa C1 C2 C3 este prietenă cu piesele:
C1 C2 C3 , C1 C3 C2 , C2 C1 C3 , C2 C3 C1 , C3 C1 C2
şi C3 C2 C1 . Se observă că două piese identice sunt şi prietene!
Un grup de piese prietene este format din TOATE piesele prietene ı̂ntre ele, aflate pe tabla
de joc.

Cerinţe

1) Alegeţi o piesă de pe tabla de joc, astfel ı̂ncât numărul M al pieselor identice cu ea să fie
cel mai mare posibil şi afişaţi numărul M determinat;
2) Afişaţi numărul grupurilor de piese prietene existente pe tabla de joc;
3) Afişaţi numărul maxim de piese dintr-o secvenţă ce conţine piese aşezate una lângă alta pe
tabla de joc, pentru care prima piesă şi ultima piesă din secvenţă sunt prietene.

Date de intrare

- 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 pieselor de joc;
- pe următoarele N linii, câte trei cifre, despărţite prin câte un spaţiu, ce reprezintă, ı̂n ordine,
cifrele scrise pe câte o piesă de joc. Piesele sunt date ı̂n ordinea numerotării acestora pe tabla de
joc.

Date de ieşire
CAPITOLUL 19. ONI 2019 19.3. TRIO 234

Fişierul trio.out va conţine pe prima linie un singur număr natural ce reprezintă rezultatul
determinat conform fiecărei cerinţe.

Restricţii şi precizări

2 & N & 100 000


Există cel puţin două piese identice pe tabla de joc;
O piesă ce nu e prietenă cu nicio altă piesă de pe tabla de joc formează singură un grup;
Pentru rezolvarea cerinţei 1) se acordă 20 de puncte, pentru rezolvarea cerinţei 2) se acordă
30 de puncte iar pentru rezolvarea cerinţei 3) se acordă 50 de puncte.

Exemple
trio.in trio.out Explicaţii
1 2 .
6
133
459
133
954 Se rezolvă cerinţa 1. Alegând oricare din piesele 1, 3 sau 5 există
331 pe tablă dou piese identice cu piesa aleasă. Alegând oricare din piesele
945 2 sau 4 există doar o piesă ce este identică cu piesa aleasă.
Dacă alegem piesa 6 nu există pe tablă piese identice cu ea.
1 2 .
6
1 3 3
4 5 9
1 3 3
9 5 4 Se rezolvă cerinţa 2. Piesele 1 şi 5 formeză un grup de piese prietene.
3 3 1 Piesele 2, 4 şi 6 formează alt grup. Piesa 3 formeaz singură un grup.
9 4 5 În total, pe tablă, sunt 3 grupuri de piese prietene.
1 2 Se rezolvă cerina 3. Identificăm două secvenţe de lungime maximă,
6 egală cu 5, pentru care prima şi ultima piesă sunt prietene:
1 3 3
4 5 9
1 3 3
9 5 4
3 3 1
9 4 5

Timp maxim de executare/test: 0.2 secunde


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

19.3.1 Indicaţii de rezolvare

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

Cerinţa 1
- pentru determinarea numărului M ce reprezintă cel mai mare număr de piese de pe tabla de
joc, identice cu o piesă aleasă, se construieşte un vector de frecvenţă V cu ajutorul căruia se va
contoriza numărul pieselor identice;
- fiecărei piese C1 C2 C3 ı̂i vom asocia o valoare numerică C1*100+C2*10+C3, această
valoare este un număr natural din intervalul [0,999];
- se va ţine cont de faptul că pentru oricare două piese identice C1 C2 C3 şi
C3 C2 C1 vor avea asociată aceeaşi valoare numerică;
- V[C1*100+C2*10+C3] se va incrementa de fiecare dată când este ı̂ntâlnită pe tabla de joc o
piesă ce are asociată valoarea numerică prezizată mai sus;
CAPITOLUL 19. ONI 2019 19.3. TRIO 235

- se va determina valoarea maximă memorată ı̂n vectorul V.


Cerinţa 2
- pentru determinarea numărului de grupe de piese prietene de pe tabla de joc, se vor identifica
toate piesele prietene de pe tabla de joc ce aparţin aceluiaşi grup.
- deoarece piesele C1 C2 C3 , C1 C3 C2 , C2 C1 C3 ,
C2 C3 C1 , C3 C1 C2 şi C3 C2 C1 aparţin aceluiaşi grup de piese
prietene, toate vor avea asociată aceeaşi valoare numerică egală cu C1*100+C2*10+C3. Această
valoare se poate obţine prin ordonarea crescătoare a celor trei cifre C1,C2 şi C3
- se va memora cu ajutorul unui vector de frecvenţă numărul de apariţii al fiecărei valori
numerice din intervalul [0,999]
- se va utiliza o variabilă de tip contor pentru numărarea tuturor grupurilor de piese prietene
Cerinţa 3
- Pentru determinarea celei mai lungi secvenţe de piese aşezate una lângă alta pe tabla de
joc, ı̂n care prima şi ultima piesă sunt prietene, vom memora pentru fiecare valoare din intervalul
[0,999] indicele primei piese şi indicele ultimei piese de pe table joc, ce are asociată acea valoare.

19.3.2 Cod sursă

Listing 19.3.1: trio cpp.cpp


#include <fstream>
#include <iostream>
#include <algorithm> // sort

using namespace std;

ifstream f("trio.in");
ofstream g("trio.out");

int N,C,nr,ap[1000],c[4],max_identice,nr_ord,nr_grupuri;

bool grup[1000]= {0}; //cerinta2

int ultima_poz[1000], prima_poz[1000]={0}, max_echivalente; //cerinta3

int main()
{
int i;
f>>C>>N;

for(int i=1; i<=N; i++)


{
f>>c[1]>>c[2]>>c[3];
if(c[3]>c[1])
swap(c[1],c[3]);

nr=(c[1]*100+c[2]*10+c[3]);
ap[nr]++;

if(ap[nr]>max_identice)
max_identice=ap[nr];

// ordonez cifrele de pe o piesa pentru a determina


// cele ce aprtin aceluiasi grup
sort(c+1,c+4);

nr_ord=c[1]*100+c[2]*10+c[3];
grup[nr_ord]=1;// vector de aparitii ptr grup

if(prima_poz[nr_ord]==0)
//memorez primul nr de ordine al unei piese din grup
prima_poz[nr_ord]=i;
else
//memorez ultimul numar de ordine al unei piese din acelasi grup
ultima_poz[nr_ord]=i;
}

if (C==1)
CAPITOLUL 19. ONI 2019 19.3. TRIO 236

g<<max_identice-1<<’\n’;
else
if (C==2)
{
for(i=0; i<=999; i++)
if(grup[i]) nr_grupuri++;
g<<nr_grupuri<<’\n’;
}
else
{
for(i=0; i<=999; i++)
if(ultima_poz[i]-prima_poz[i]>max_echivalente)
max_echivalente=ultima_poz[i]-prima_poz[i];
g<<max_echivalente+1<<’\n’;
}
return 0;
}

19.3.3 Rezolvare detaliată

Listing 19.3.2: Trio - Etapa nr. 0


#include<iostream> // cout
#include<fstream> // fstream

using namespace std;

ifstream fin("trio.in");
ofstream fout("trio.out");

int C; // nr cerinta
int N;

int c1, c2, c3;

void rezolva1()
{
for(int i=1; i<=N; i++)
{
fin>>c1>>c2>>c3;

}
}

void rezolva2()
{
for(int i=1; i<=N; i++)
{
fin>>c1>>c2>>c3;

}
}

void rezolva3()
{
for(int i=1; i<=N; i++)
{
fin>>c1>>c2>>c3;

}
}

int main()
{
fin>>C;
fin>>N;

if(C==1) rezolva1();
else
if(C==2) rezolva2();
else
if(C==3) rezolva3();
CAPITOLUL 19. ONI 2019 19.3. TRIO 237

return 0;
}

Listing 19.3.3: Trio - Etapa nr. 1


void rezolva1()
{
int nraparitii[1000]={0}; // nu N ... !!!
int p123; // "prieteni": 123 cu 321
int maxp; // raspuns la cerinta 1
int aux; // variabila auxiliara pentru interschimbare

for(int i=1; i<=N; i++)


{
fin>>c1>>c2>>c3;
if(c1>c3) {aux=c1; c1=c3; c3=aux;} // c1 <= c3 "identice" (1,2,3)=(3,2,1)
p123=c1*100+c2*10+c3;
nraparitii[p123]++;
}

maxp=0;
for(int i=0; i<=999; i++)
if(nraparitii[i] > maxp)
maxp=nraparitii[i];

cout<<"maxp-1 = "<<maxp-1<<"\n";
fout<<maxp-1<<’\n’; // Atentie la textul cerintei si exemplul 1
}

Listing 19.3.4: Trio - Etapa nr. 2


void rezolva2()
{
int nraparitii[1000]={0}; // nu N ... !!!
int p123; // "prieteni": 123 cu 321
int nrgp; // nr grupuri de prieteni - raspuns la cerinta 2
int aux; // variabila auxiliara pentru interschimbare

for(int i=1; i<=N; i++)


{
fin>>c1>>c2>>c3;
if(c1>c2) {aux=c1; c1=c2; c2=aux;} // c1 <= c2
if(c1>c3) {aux=c1; c1=c3; c3=aux;} // c1 <= c3 deci c1=min
if(c2>c3) {aux=c2; c2=c3; c3=aux;} // c2 <= c3 deci c3=max

p123=c1*100+c2*10+c3; // c1 <= c2 <= c3


nraparitii[p123]++;
}

nrgp=0;
for(int i=0; i<=999; i++)
if(nraparitii[i] > 0)
nrgp+=1;

cout<<"nrgp = "<<nrgp<<"\n";
fout<<nrgp<<’\n’; // Atentie la textul cerintei si exemplul 2
}

Listing 19.3.5: Trio - Etapa nr. 3


void rezolva3()
{
int primaaparitie[1000]={0}; // nu N ... !!!
int ultimaaparitie[1000]={0}; // nu N ... !!!

int p123; // "prieteni": 123 cu 321


int maxpiese; // nr max piese - raspuns la cerinta 3
int aux; // variabila auxiliara pentru interschimbare

for(int i=1; i<=N; i++)


{
fin>>c1>>c2>>c3;
CAPITOLUL 19. ONI 2019 19.3. TRIO 238

if(c1>c2) {aux=c1; c1=c2; c2=aux;} // c1 <= c2


if(c1>c3) {aux=c1; c1=c3; c3=aux;} // c1 <= c3 deci c1=min
if(c2>c3) {aux=c2; c2=c3; c3=aux;} // c2 <= c3 deci c3=max

p123=c1*100+c2*10+c3; // c1 <= c2 <= c3

if(primaaparitie[p123]==0)
primaaparitie[p123]=i;
else
ultimaaparitie[p123]=i;
}

maxpiese=0;
for(int i=0; i<=999; i++)
if(ultimaaparitie[i] - primaaparitie[i] > maxpiese)
maxpiese=ultimaaparitie[i] - primaaparitie[i];

cout<<"maxpiese = "<<maxpiese+1<<"\n";
fout<<maxpiese+1<<’\n’; // Atentie la textul cerintei si exemplul 3
}
Capitolul 20

ONI 2018

20.1 desen
Problema 1 - desen 100 de puncte
La ora de desen, Gigel a primit ca temă un desen care să
fie realizat după următorul algoritm:
Pas 1: se desenează un triunghi, numerotat cu 1, ca ı̂n
Figura 1;
Pas 2: se ı̂mparte triunghiul 1 ı̂n trei poligoane (un drep-
tunghi şi două triunghiuri numerotate cu 2 şi 3) trasând două
segmente ca ı̂n Figura 2 ;
Pas 3: fiecare triunghi dintre cele două obţinute la Pas
2, se ı̂mparte ı̂n câte un dreptunghi şi câte două triunghiuri
(numerotate cu 4, 5, 6, 7) trasând câte două segmente ca ı̂n
Figura 3 ;
Pas 4: fiecare triunghi dintre cele patru obţinute la Pas
3, se ı̂mparte ı̂n câte un dreptunghi şi câte două triunghiuri
(numerotate cu 8, 9,10, 11, 12, 13, 14, 15) trasând câte două
segmente ca ı̂n Figura 4 ;
.......
Pas N : fiecare triunghi dintre triunghiurile obţinute la
Pas N  1, se ı̂mparte ı̂n câte un dreptunghi şi câte două
triunghiuri trasând câte două segmente.
Dacă valoarea lui K este ultimul număr folosit pentru nu-
merotarea triunghiurilor obţinute la Pas N  1, atunci tri-
unghiurile rezultate la Pas N vor fi numerotate cu numerele
naturale distincte consecutive K  1, K  2, K  3, ..., etc.

Cerinţe

Scrieţi un program care să citească numărul natural K şi


să determine:
1. cel mai mic număr X şi cel mai mare număr Y dintre
numerele folosite pentru numerotarea triunghiurilor obţinute
la pasul ı̂n care este obţinut şi triunghiul numerotat cu K;
2. numerele triunghiurilor care au fost ı̂mpărţite conform
algoritmului din enunţ astfel ı̂ncât să fie obţinut triunghiul
numerotat cu K.
Figura 20.1: desen
Date de intrare

Fişierul de intrare desen.in conţine pe prima linie un număr natural C reprezentând cerinţa
din problemă care trebuie rezolvată (1 sau 2).
Fişierul conţine pe a doua linie numărul natural K.

239
CAPITOLUL 20. ONI 2018 20.1. DESEN 240

Date de ieşire

Dacă C 1, atunci prima linie a fişierului de ieşire desen.out conţine cele două numere
naturale X şi Y , separate printr-un singur spaţiu, reprezentând răspunsul la cerinţa 1 a problemei.
Dacă C 2, atunci prima linie a fişierului de ieşire desen.out conţine un şir de numere
naturale ordonate crescător, separate prin câte un spaţiu, reprezentând răspunsul la cerinţa 2 a
problemei.

Restricţii şi precizări

2 & K & 9223372036854775807 2  1


63
a
a doar triunghiurile sunt numerotate
a pentru rezolvarea corectă a cerinţei 1 se acordă 40 de puncte
a pentru rezolvarea corectă a cerinţei 2 se acordă 60 de puncte.

Exemple
desen.in desen.out Explicaţii
1 13 8 15 Cerinţa este 1, K 13. Aşa cum arată ı̂n Figura 4, la Pas 4
se obţin triunghiurile numerotate cu X 8, 9, 10, 11, 12, 13, 14,
Y 15.
2 13 136 Cerinţa este 2, K 13. Aşa cum arată Figura 4, triunghiul
numerotat cu K 13 se obţine din triunghiul 6. Triunghiul 6
este obţinut din triunghiul 3 care este obţinut din triunghiul 1.

Timp maxim de executare/test: 0.3 secunde


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

20.1.1 Indicaţii de rezolvare


prof. Daniela Tătaru, Colegiul Naţional ”Al. D. Ghica”, Alexandria

Observăm că:

Exemple
Pas Cel mai mic număr folosit Cel mai mare număr folosit Număr triunghiuri
la numerotarea triunghiurilor la numerotarea triunghiurilor obţinute la acest
obţinute la acest pas obţinute la acest pas pas
0
Pas 1: 1 1 2
1
Pas 2: 2 3 2
2
Pas 3: 4 7 2
3
Pas 4: 8 15 2
Pas ...: ... ... ...
N 1 N N 1
Pas N: 2 2 1 2

Cerinţa 1.
Se determină valorile X şi Y cu proprietatea că:
N 1
X 2 & K & Y 2N  1 2 ˜ 2N 1  1 2 ˜ X  1
Cerinţa 2.
Se afişează ı̂n ordine inversă valorile:
x1 K ©2, x2 x1 ©2, x3 x2 ©2, ..., xN 1

20.1.2 *Cod sursă

20.1.3 *Rezolvare detaliată


CAPITOLUL 20. ONI 2018 20.2. MOSTENIRE 241

20.2 mostenire
Problema 2 - mostenire 100 de puncte
Regele Rufus doreşte să stabilească moştenitorul averii sale, adică să ofere parola de la seif
celui mai deştept dintre fiii săi. Iniţial, regele a avut parola X formată din N cifre nenule şi un
cod cheie Q (număr natural cu exact 9 cifre, distincte, toate nenule). În fiecare an din cei K ani
de domnie, folosind codul cheie Q, Rufus a modificat câte o secvenţă de cifre din parolă ajungând
la parola finală P .
Pentru fiecare secvenţă se cunoaşte poziţia S a primei cifre din secvenţă şi poziţia D a ultimei
cifre din secvenţă. Astfel, secvenţa este formată din cifrele situate pe poziţiile S, S  1, S  2, ...,
D ı̂n parola X.
Modificarea unei secvenţe din X constă ı̂n ı̂nlocuirea fiecărei apariţii a cifrei 1 cu prima cifră
a lui Q, apoi a fiecărei apariţii a cifrei 2 cu a doua cifră a lui Q, ..., a fiecărei apariţii a cifrei 9 cu
ultima cifră a lui Q.
Pentru a decide moştenitorul, regele le dă fiilor parola finală P , codul cheie Q, numărul K
de ani de domnie si cele K secvenţe de cifre care au fost modificate şi le cere să găsescă: parola
iniţială X, poziţia minimă Z din parola X care a apărut ı̂n cele mai multe secvenţe dintre cele
modificate de rege de-a lungul celor K ani de domnie şi cifrele distincte care au ocupat poziţia Z
ı̂n cei K ani.

Cerinţe

Scrieţi un program care citeşte numerele Q, N , K, cele N cifre ale parolei finale P şi cele K
perechi de poziţii S şi D, şi care rezolvă următoarele două cerinţe:
1. determină parola iniţială X;
2. determină poziţia minimă Z şi cifrele distincte care au ocupat această poziţie ı̂n cei K ani
de domnie.

Date de intrare

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


cerinţa din problemă care trebuie rezolvată (1 sau 2). A doua linie din fişier conţine cele trei
numere naturale Q, N şi K, separate prin câte un spaţiu. A treia linie din fisier conţine cele N
cifre ale parolei finale P , separate prin câte un spaţiu. Fiecare linie dintre următoarele K, conţine
câte două numere naturale S şi D, separate printr-un singur spaţiu, reprezentând câte o pereche
de poziţii.

Date de ieşire

Dacă C 1, fişierul de ieşire mostenire.out va conţine pe prima linie cele N cifre ale parolei
initiale X, separate prin câte un spaţiu, ı̂n ordinea ı̂n care apar ı̂n X, reprezentând răspunsul la
cerinţa 1.
Dacă C 2, fişierul de ieşire mostenire.out va conţine pe prima linie numărul natural Z, iar
pe a doua linie cifrele distincte care au apărut pe poziţia minimă Z, reprezentând răspunsul la
cerinţa 2. Acestea vor fi afişate ı̂n ordine crescătoare, separate prin câte un spaţiu.

Restricţii şi precizări

a 1 & N & 10000


a numărul natural Q este format din exact 9 cifre, distincte şi nenule
a poziţiile cifrelor din parola X sunt numerotate cu numerele distincte consecutive 1, 2, ..., N
a 1 & K & 100
a pentru toate perechile de poziţii modificate de rege: S & D
a cel puţin o cifră din parola X va fi ı̂nlocuită
a pentru rezolvarea corectă a cerinţei 1 se acordă 50 de puncte
a pentru rezolvarea corectă a cerinţei 2 se acordă 50 de puncte.
CAPITOLUL 20. ONI 2018 20.3. PYK 242

Exemple:
mostenire.in mostenire.out Explicaţii
1 273541337928 Cerinţa este 1, N=12, K=4.
712534698 12 4
147134714818
24
6 11
39
17
2 3 Cerinţa este 2, N=12, K=4.
712534698 12 4 1237 P=(1 4 7 1 3 4 7 1 4 8 1 8)
147134714818 Poziţiile care au apărut ı̂n cele mai multe secvenţe
24 sunt: 3,4,6,7 =¿ Z=3, iar cifrele distincte care au
6 11 ocupat succesiv această pozitie sunt 3,2,1,7. Aceste
39 cifre se vor scrie ı̂n fişier ı̂n ordine crescătoare
17

Timp maxim de executare/test: 0.3 secunde


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

20.2.1 Indicaţii de rezolvare


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

Cerinta 1
Se citesc succesiv intervalele S, D pe care s-au aplicat modificări.
Pentru secvenţa curentă, fiecare cifră poziţionată ı̂n secvenţă se ı̂nlocuieşte cu poziţia acestei
cifre ı̂n codul Q realizându-se astfel transformarea ı̂n sens invers.
Cerinta 2
Se poate utiliza un vector de frecvenţă cu N elemente. Pentru fiecare poziţie i din vector se
determină numărul secvenţelor ı̂n care a apărut acestă poziţie. Apoi, se stabileste pozitia minimă
Z cu număr maxim de apariţii.
După ce s-a stabilit pozitia Z, se determină cifrele ce au ocupat acestă poziţie, realizând de K
ori transformarea ı̂n sens invers. Se poate utiliza un vector de frecvenţă pentru a marca apariţia
acestor cifre şi pentru a le afişa ı̂n ordine strict crescătoare.

20.2.2 *Cod sursă

20.2.3 *Rezolvare detaliată

20.3 pyk
Problema 3 - pyk 100 de puncte
Fie k, n şi y trei numere naturale.
Fie X un şir format din n numere naturale: x1 , x2 , x3 , ..., xn .
Fie P produsul numerelor y, x1 , x2 , x3 , ..., xn , adică: P y ˜ x1 ˜ x2 ˜ x3 ˜ ... ˜ xn .
k
Numărul P este o ”k-putere” dacă există un număr natural z astfel ı̂ncât P z .

Cerinţe

Scrieţi un program care să citească numerele k, n, x1 , x2 , x3 , ..., xn şi care să determine:
1. cel mai mic număr şi cel mai mare număr din şirul X, formate doar din cifre identice;
2. descompunerea ı̂n factori primi a celui mai mic număr natural y (y ' 2) cu proprietatea că
numărul P y ˜ x1 ˜ x2 ˜ x3 ˜ ... ˜ xn este o ”k-putere”.
CAPITOLUL 20. ONI 2018 20.3. PYK 243

Date de intrare

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


a pe prima linie, un număr natural C reprezentând cerinţa din problemă care trebuie rezolvată
(1 sau 2);
a pe a doua linie, numerele naturale k şi n, separate printr-un singur spaţiu;
a pe a treia linie, cele n numere naturale x1 , x2 , x3 , ..., xn , separate prin câte un singur spaţiu.

Date de ieşire

Dacă C 1, atunci prima linie a fişierului de ieşire pyk.out conţine două numere naturale,
separate printr-un singur spaţiu, reprezentând răspunsul la cerinţa 1 a problemei. Dacă nu există
astfel de numere, prima linie a fişierului va conţine valoarea 1.
Dacă C 2, atunci fişierul de ieşire pyk.out conţine:
a pe prima linie, un număr natural m reprezentând numărul de factori primi distincţi din
descompunerea ı̂n factori primi a numărului y, determinat la rezolvarea cerinţei 2;
a pe fiecare dintre următoarele m linii (câte o linie pentru fiecare factor prim din descompunerea
ı̂n factori primi a lui y), câte două valori F şi E, separate printr-un singur spaţiu, reprezentând
factorul prim F şi exponentul E al acestui factor din descompunerea ı̂n factori primi a lui y.
Scrierea ı̂n fişier a acestor factori primi se va face ı̂n ordinea crescătoare a valorii lor.

Restricţii şi precizări

a 2 & n & 50000


a 2 & k & 100
a 2 & x1 , x2 , x3 , ..., xn & 10000
a 2&y
a pentru rezolvarea corectă a cerinţei 1 se acordă 10 puncte
a pentru rezolvarea corectă a cerinţei 2 se acordă 90 de puncte.

Exemple
pyk.in pyk.out Explicaţii
1 4 1111 Cerinţa este 1, k 2, n 7.
27 Numerele din şirul X formate doar din cifre identice sunt:
122 1111 5 4 88 123 999 1111, 5, 4, 88, 999. Cel mai mic număr dintre acestea este
4, iar cel mai mare este 1111.
2 3 Cerinţa este 2, k 3, n 6. Produsul celor 6 numere din
36 21 şir este: 12*5*60*125*4*36=64800000
12 5 60 125 4 36 32 y 90 este cea mai mică valoare pentru care P 90 ˜
3
51 64800000 1800 devine o ”k-putere”.
Descompunerea ı̂n factori primi a lui y conţine m 3
1 2 1
factori primi : 2 ˜ 3 ˜ 5

Timp maxim de executare/test: 0.3 secunde


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

20.3.1 Indicaţii de rezolvare


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

Cerinta 1.
Se pot folosi două variabile xmin şi xmax pentru a memora valorile cerute. Se citesc succesiv
numerele din fişier. Se compară cifrele fiecărui număr. Dacă cifrele sunt identice, atunci numărul
curent se compară cu xmax şi xmin curent, actualizându-se valorile acestora.
Cerinţa 2.
O soluţie se poate obţine fără a calcula produsul numerelor astfel:
a Se determină numerele prime & 10000 folosind eventual Ciurul lui Eratostene (se vor memora
ı̂ntr-un vector v)
a Se citeşte din fişier fiecare număr din şirul X. Se poate determina frecvenţa de apariţie
pentru fiecare număr din şir cu ajutorul unui vector de frecvenţă (vectorul f r).
CAPITOLUL 20. ONI 2018 20.3. PYK 244

a Se parcurge vectorul f r. Pentru fiecare număr cu frecvenţa nenulă se verifică dacă este prim
(adică dacă apare ı̂n vectorul v).
În caz contrar se descompune ı̂n factori primi. Se contorizează fiecare apariţie a fiecărui factor
prim luând ı̂n calcul şi frecvenţa de apariţie a numărului descompus (se utilizează un vector w
ı̂n care elementul wj  memorează produsul dintre frecvenţa de apariţie a factorului prim j şi
exponentul acestuia). Elementele wj  % 0 au semnificaţia: factorul prim j are exponentul wj 
ı̂n descompunerea ı̂n factori primi a lui y.
a Dacă factorii primi din produsul numerelor x1 , x2 , ..., xn au toţi exponenţii multiplu de k,
k
atunci produsul numerelor din şir este o k-putere şi y este 2
În caz contrar, numărul factorilor primi din descompunerea lui y este egal cu numărul valorilor
j din vectorul w, cu proprietatea că wj %k % 0. În y, exponentii acestor factori primi j vor fi
egali cu k  wj %k (se incrementează exponentul până la primul multiplu de k).

20.3.2 *Cod sursă

20.3.3 *Rezolvare detaliată


Capitolul 21

ONI 2017

21.1 prime
Problema 1 - prime 100 de puncte
Eu sunt fascinată de numerele prime. Consider că numerele prime sunt ”scheletul” tuturor
numerelor sau ”atomii” acestora, pentru că orice număr natural mai mare decât 1 poate fi scris
ca un produs de numere prime. Recent am aflat şi alte proprietăţi interesante legate de numerele
prime, de exemplu:
1. În şirul Fibonacci există o infinitate de numere prime. Vă mai amintiţi şirul Fibonacci? 0,
1, 1, 2, 3, 5, 8, 13, ... Este şirul ı̂n care fiecare termen, exceptând primii doi, se obţine ca suma
celor doi termeni care ı̂l precedă.
2. Există numere naturale denumite ”economice”. Un număr natural este economic dacă
numărul de cifre necesare pentru scrierea sa este mai mare decât numărul de cifre necesare pentru
scrierea descompunerii sale ı̂n factori primi (adică decât numărul de cifre necesare pentru scrierea
factorilor primi şi a puterilor acestora). De exemplu 128 este economic pentru că 128 se scrie cu 3
7
cifre, iar descompunerea sa ı̂n factori primi se scrie cu două cifre (2 ); 4374 este economic pentru
7
că se scrie cu 4 cifre, ı̂n timp ce descompunerea sa ı̂n factori primi se scrie cu 3 cifre (2 ˜ 3 )
Observaţi că atunci când un factor prim apare la puterea 1, aceasta nu este necesar să fie scrisă.
3. Multe numere naturale pot fi scrise ca sumă de două numere prime. Dar nu toate. De
exemplu, 121 nu poate fi scris ca sumă de două numere prime.

Cerinţe

Scrieţi un program care citeşte numărul natural n şi o secvenţă de n numere naturale, apoi
rezolvă următoarele cerinţe:
1. determină şi afişează câte dintre numerele din secvenţa dată sunt numere prime din şirul
Fibonacci;
2. determină şi afişează câte dintre numerele din secvenţa dată sunt numere economice;
3. determină şi afişează câte dintre numerele din secvenţa dată nu pot fi scrise ca sumă de
două numere prime.

Date de intrare

Fişierul de intrare prime.in conţine pe prima linie un număr natural c care reprezintă cerinţa
(1, 2 sau 3). Pe a doua linie se află numărul natural n. Pe a treia linie se află o secvenţă de n
numere naturale separate prin spaţii.

Date de ieşire

Fişierul de ieşire prime.out va conţine o singură linie pe care va fi scris răspunsul la cerinţa
din fişierul de intrare.

Restricţii şi precizări

245
CAPITOLUL 21. ONI 2017 21.1. PRIME 246

a 1 $ n & 50
7
a Dacă c 1 sau c 3 numerele naturale din şir sunt mai mari decât 1 şi mai mici decât 10 .
14
a Dacă c 2 numerele naturale din şir sunt mai mari decât 1 şi mai mici decât 10 .
a Pentru rezolvarea corectă a cerinţei 1 se acordă 20 de puncte; pentru rezolvarea corectă a
cerinţei 2 se acordă 50 de puncte, iar pentru rezolvarea corectă a cerinţei 3 se acordă 30 de puncte.

Exemple
prime.in prime.out Explicaţii
1 3 Cerinţa este 1. Cele 3 numere prime din şirul Fibonacci existente
5 ı̂n secvenţă sunt 2, 13 şi 233.
2 10 13 997 233
2 2 Cerinţa este 2. Succesiunea conţine două numere economice
4 (128 şi 4374).
128 25 4374 720
3 4 Cerinţa este 3. Sunt 4 numere naturale din secvenţă care nu pot
5 fi scrise ca sumă de două numere prime: 57, 121, 11, 3.
57 30 121 11 3

Timp maxim de executare/test: 1.2 secunde


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

21.1.1 Indicaţii de rezolvare


prof. Emanuela Cerchez, Colegiul Naţional ”Emil Racoviţă” Iaşi

Vom citi ı̂ntr-un vector a cele n valori şi vom determina vmax cea mai mare valoare din vector.
Pentru o abordare eficientă, pentru toate cele 3 cerinţe, pregenerăm numerele prime & 10
7

(sau & vmax pentru cerinţele 1 şi 3, respectiv sqrt vmax pentru cerinţa 2). Pentru aceasta vom
utiliza ciurul lui Eratostene, apoi vom transfera numerele prime ı̂ntr-un vector denumit prim, care
va avea nrprim elemente. Pentru cerinţa 2 poate fi util să precalculăm şi să reţinem ı̂ntr-un vector
şi lungimea fiecărui număr prim.
Pentru cerinţa 1 este suficient să generăm termenii şirului Fibonacci & vmax şi să memorăm
ı̂ntr-un vector acei termeni care sunt numere prime. Fiindcă numărul de termeni primi din şirul
Fibonacci & 10 este foarte mic, putem să căutăm secvenţial ı̂n acest şir fiecare element din
7

vectorul a şi să-l numărăm ı̂n cazul ı̂n care ı̂l găsim.
Pentru cerinţa 2 vom descompune fiecare număr din vectorul a ı̂n factori primi (eficient!!!
folosiţi numerele prime memorate ı̂n vectorul prim). Dacă numărul de cifre necesare pentru
scrierea factorilor primi şi a puterilor acestora este $ lungimea numărului curent din a, deducem
că este un număr economic şi ı̂l contorizăm.
Pentru cerinţa 3 vom parcurge vectorul a şi pentru fiecare element ai din vector verificăm
dacă poate fi scris ca sumă de două numere prime. Pentru aceasta parcurg vectorul de numere
prime până când se termină (sau, mai eficient, până când numărul prim curent p este mai mare
decât complementarul său ai  p) sau până când găsesc un număr prim p pentru care ai  p
este deasemenea prim. Dacă un astfel de număr prim nu a fost găsit, contorizez pe ai.

Soluţie alternativă (100 puncte)

prof. Şandor Nicoleta, Colegiul Naţional Mihai Eminescu Satu Mare

Pentru fiecare cerinţă se vor prelucra numerele la citire.


Cerinţa 1:
Verificăm dacă numărul citit este termen al şirului lui Fibonacci. În caz afirmativ, verificăm
dacă numărul citit este prim. Dacă este ı̂ndeplinită şi această condiţie contorizăm numărul citit.
Cerinţa 2:
Calculăm numărul de cifre ale valorii citite. Descompunem numărul ı̂n factori primi (eficient)
şi calculăm numărul de cifre ale divizorilor primi şi ale exponenţilor mai mari decât 1 ai acestora.
CAPITOLUL 21. ONI 2017 21.1. PRIME 247

Dacă valoarea citită are numărul de cifre % numărul de cifre necesare pentru scrierea factorilor
primi şi a puterilor acestora, deducem că este un număr economic şi ı̂l contorizăm.
Cerinţa 3:
Aflăm numerele care pot fi scrise ca sumă de două numere prime. Din numărul total de numere
citite vom scădea numărul de numere care pot fi scrise ca sumă de două numere prime. Verificăm
doar numerele mai mari decât 3.
Orice număr par mai mare decât 3 poate fi scris ca sumă de două numere prime, prin
urmare pentru orice număr par mai mare decât 3 decrementăm contorul.
Pentru a găsi numerele impare care verifică această condiţie folosim proprietatea că suma dintre
două numere este impară doar dacă unul dintre cele două numere este par. Singurul număr prim
par este 2. Prin urmare este suficient să verificăm dacă diferenţa dintre numărul citit şi 2 este
număr prim. ı̂n caz afirmativ decrementăm contorul.

21.1.2 Cod sursă

Listing 21.1.1: prime cp.cpp


//Carmen Popescu
#include <iostream>
#include <fstream>
#include <cmath>

using namespace std;

ifstream f("prime.in");
ofstream g("prime.out");

bool ciur[10000001];
int prim[665000],lg[665000];

int main()
{
int i,j,n,c,np,nf,f1,f2,f3;
long long a[51],mx;
int fib[26];
f>>c>>n;
for (i=0;i<n;i++)
{
f>>a[i];
if (a[i]>mx) mx=a[i];
}

if (c==2)
mx=sqrt(mx);
// nr prime cu ciur
ciur[0]=ciur[1]=1;
for (i=2;i*i<=mx;i++)
if (ciur[i]==0)
for (j=i*i;j<=mx;j=j+i)
ciur[j]=1;

np=0;
int p=9,k=1;
for (i=2;i<=mx;i++)
if (ciur[i]==0)
{
prim[np]=i;
while (i>p)
{
p=(p+1)*10-1;
k++;
}
lg[np++]=k;
}

// fibonacci prime
nf=0;
f1=0; f2=1; f3=1;
CAPITOLUL 21. ONI 2017 21.1. PRIME 248

while (f3<=mx)
{
if (ciur[f3]==0)
fib[nf++]=f3;
f1=f2; f2=f3; f3=f1+f2;
}

if (c==1)
{
int k=0;
for (i=0;i<n;i++)
for (j=0;j<nf;j++)
if (a[i]==fib[j])
{
k++;
break;
}
g<<k<<"\n";
}
else
if (c==2)
{
int k=0;
for (i=0;i<n;i++)
{
long long y=a[i],w=a[i];
f1=0;
f2=0;
while (y>0) { f1++; y/=10; }

for(j=0; j<np && prim[j]*prim[j]<=a[i] && f2<f1; j++)


{
p=0;
while (a[i]%prim[j]==0)
{
p++;
a[i]/=prim[j];
}
if (p)
{
f2 += lg[j];
if (p>1)
{
y=p;
while (y>0)
{
f2++; y/=10;
}
}
}
}
if (a[i]>1)
{
y=a[i];
while (y>0)
{
f2++; y/=10;
}
}
if (f2<f1)
k++;
}
g<<k<<"\n";
}
else
{
int k=0;
for (i=0;i<n;i++)
{
if (a[i]%2==1)
{
if (ciur[a[i]-2]==0)
k++;
}
else
{
CAPITOLUL 21. ONI 2017 21.1. PRIME 249

for (j=0;prim[j]<a[i];j++)
if (ciur[a[i]-prim[j]]==0)
{
k++;
break;
}
}
}
g<<n-k<<"\n";
}

return 0;
}

Listing 21.1.2: prime em.cpp


//Emanuela Cerchez
#include <fstream>
#include <cmath>

#define VMAX 10000001


#define PMAX 1000000
#define NMAX 50

using namespace std;

ifstream fin("prime.in");
ofstream fout("prime.out");

bool ciur[VMAX];
int nrprim, nr, n;
int prim[PMAX];
int lgprim[PMAX];
long long int a[NMAX], vmax;
int fib[NMAX];
int nrfib;

int main()
{int cerinta, i, j, d, lg, lgx, f1, f2, f3, p, gasit;
long long int cx;

fin>>cerinta>>n;
for (i=0; i<n; i++)
{
fin>>a[i];
if (a[i]>vmax) vmax=a[i];
}

//ciur
if (cerinta==2) vmax=sqrt((double)vmax);
ciur[0]=ciur[1]=1;
for (d=2; d*d<=vmax; d++)
if (!ciur[d])
for (j=d*d; j<=vmax; j+=d)
ciur[j]=1;

//transfer intr-un vector numerele prime <=vmax


prim[0]=2; nrprim=1; lgprim[0]=1;
for (d=3; d<=vmax; d+=2)
if (!ciur[d])
{prim[nrprim]=d;
cx=d;
do
{
cx/=10;
lgprim[nrprim]++;
} while (cx);
nrprim++;
}
if (cerinta==1)
{
for (f1=f2=1; f1+f2<=vmax; )
{
f3=f1+f2; f1=f2; f2=f3;
if (!ciur[f3]) fib[nrfib++]=f3;
CAPITOLUL 21. ONI 2017 21.1. PRIME 250

}
nr=0;
for (i=0; i<n; i++)
{
for (j=0; j<nrfib && a[i]!=fib[j]; j++);
if (j<nrfib) nr++;
}

fout<<nr<<’\n’;
fout.close();
return 0;
}

if (cerinta==2)
{
nr=0;
//descompunere in factori primi eficient
for (i=0; i<n; i++)
{
cx=a[i]; lgx=0; do {lgx++; cx/=10;} while (cx);
lg=0;
for (j=0; j<nrprim && prim[j]*prim[j]<=a[i] && lg<lgx; j++)
{
for (p=0; a[i]%prim[j]==0; p++,a[i]/=prim[j]);
if (p)
{
lg+=lgprim[j];
if (p>1)
{
cx=p;
do {lg++; cx/=10;} while(cx);
}
}
}
if (a[i]>1)
{cx=a[i]; do {lg++; cx/=10;} while (cx);}
if (lg<lgx)
nr++;
}

fout<<nr<<’\n’;
fout.close();
return 0;
}

//cerinta 3
nr=0;
for (i=0; i<n; i++)
{
for (gasit=j=0; j<nrprim && a[i]>prim[j]; j++)
if (!ciur[a[i]-prim[j]]) {gasit=1; break;}
if (!gasit) nr++;
}

fout<<nr<<’\n’;

fout.close();
return 0;
}

Listing 21.1.3: prime fara ciur sn.cpp


//prof. Sandor Nicoleta
#include <fstream>
#include<iostream>

using namespace std;

ifstream fin("prime.in");
ofstream fout("prime.out");

bool prim(int n)
{
if (n<2) return 0;
if(n==2) return 1;
CAPITOLUL 21. ONI 2017 21.1. PRIME 251

if(n%2==0) return 0;
for(int d=3; d*d<=n; d=d+2)
if(n%d==0)
return 0;
return 1;
}

bool fibo(int n)
{
int a,b,c;
a=b=c=1;
while(c<n)
{
c=a+b;
a=b;
b=c;
}
return c==n;
}

int nrcif(long long n)


{
int c=0;
while(n)
{
n/=10;
c++;
}
return c;
}

int descompun(long long x)


{
int c,s=0;
long long d=2;
while(x > 1)
{
if(x % d == 0)
{
s+=nrcif(d);
c=0;
while(x % d == 0)
x /= d,c++;
if(c>1) s+=nrcif(c);
}
d ++;
// daca x este numar prim ne oprim
if(x > 1 && d * d > x)
{
s+=nrcif(x);
x = 1;
}
}
return s;
}

int main()
{
int i,n,c,v[50],x=0, a;
long long a1,j;
fin>>c>>n;
if(c==1)
{
for(i=0; i<n; i++)
{
fin>>a;
if (fibo(a)&&prim(a))
x++;
}
fout<<x;
}
else if(c==2)
{
for(i=0; i<n; i++)
{
fin>>a1;
CAPITOLUL 21. ONI 2017 21.2. ROBOT 252

if (descompun(a1)<nrcif(a1))
{
x++;
cout<<a1<<"\n";
}
}
fout<<x;
}
else
{
x=n;
for(i=0; i<n; i++)
{
fin>>a;
if(n>3)
{
//orice numar par mai mare dcat 4 se poate scrie
// ca suma a doua numere prime
if(a%2==0) x--;
else if (prim(a-2))
{
x--;
}
}
}
fout<<x;
}
return 0;
}

21.1.3 *Rezolvare detaliată

21.2 robot
Problema 2 - robot 100 de puncte
Vlad a inventat un nou joc. Jocul conţine N standuri aşezate ı̂n linie dreaptă. Fiecare stand
are o etichetă pe care este scris un număr natural. Eticheta este considerată corectă dacă numărul
ı̂ndeplineşte următoarele două condiţii:
- conţine atât cifre pare, cât şi cifre impare;
- ı̂ncepe cu cifrele impare aşezate ı̂n ordine crescătoare, urmate de cifrele pare ı̂n ordine de-
screscătoare.
De exemplu, eticheta 137860 este corectă, dar etichetele 23541, 135, 64 şi 3146 nu sunt corecte.
Pentru jocul său, Vlad a construit robotul reparator care ştie să verifice numere şi să le repare,
dacă este necesar. Robotul reparator se deplasează ı̂n linie dreaptă şi se opreşte pe rând la fiecare
dintre cele N standuri. La fiecare stand, robotul verifică eticheta şi dacă nu este corectă, o
”repară”.
Pentru a repara eticheta, robotul aranjează cifrele impare ı̂n ordine crescătoare, apoi, ı̂n con-
tinuare, aranjează cifrele pare ı̂n ordine descrescătoare; dacă eticheta nu conţine nicio cifră impară,
cea mai mare cifră pară o ı̂nlocuieşte cu 9; dacă eticheta nu conţine nicio cifră pară, cea mai mică
cifră impară o ı̂nlocuieşte cu 0.
Deplasarea de la un stand la altul durează t secunde, verificarea etichetei unui stand durează
v secunde, iar repararea acesteia durează r secunde. Cursa robotului se ı̂ncheie după ce robotul a
verificat toate cele N standuri şi a reparat etichetele incorecte.

Cerinţe

Scrieţi un program care citeşte numărul N de standuri, timpul (ora h, minutul m, secunda
s) când robotul ajunge la primul stand, timpii t, v şi r cu semnificaţia din enunţ şi etichetele
standurilor şi care rezolvă următoarele cerinţe:
1. calculează şi afişează timpul (ora, minutul şi secunda) când robotul a ı̂ncheiat verificarea
tuturor celor N standuri şi repararea etichetelor incorecte;
2. repară (unde este necesar) etichetele standurilor şi afişează etichetele celor N standuri la
final.
CAPITOLUL 21. ONI 2017 21.2. ROBOT 253

Date de intrare

Fişierul de intrare robot.in conţine pe prima linie un număr natural C, reprezentând cerinţa
care urmează să fie rezolvată (1 sau 2).
Pe linia a doua se află numerele naturale N , h, m, s, iar pe linia a treia numerele naturale t,
v, r, cu semnificaţia din enunţ. Numerele aflate pe aceeaşi linie sunt separate prin câte un spaţiu.
Pe următoarele N linii se află etichetele standurilor, ı̂n ordinea aşezării acestora, câte o etichetă
pe o linie.

Date de ieşire

Dacă C 1, fişierul de ieşire robot.out va conţine o singură linie pe care vor fi scrise 3 numere
naturale separate prin câte un spaţiu hf mf sf , reprezentând ora, minutul şi respectiv secunda
la care robotul termină repararea.
Dacă C 2, fişierul de ieşire robot.out va conţine N linii pe care vor fi scrise etichetele
standurilor, ı̂n ordinea aşezării acestora, după ce robotul a ı̂ncheiat verificarea şi repararea, câte
o etichetă pe o linie.

Restricţii şi precizări

a 2 & N & 500


a Etichetele standurilor au cel puţin două şi cel mult nouă cifre.
a Robotul ı̂ncepe şi ı̂ncheie repararea ı̂n aceeaşi zi; 0 & h, hf $ 24; 0 & m, mf, s, sf $ 60
a Pentru rezolvarea corectă a cerinţei 1 se acordă 40 de puncte; pentru rezolvarea corectă a
cerinţei 2 se acordă 60 de puncte.

Exemple
robot.in robot.out Explicaţii
1 11 21 49 Cerinţa este 1. Există 3 standuri.
3 11 20 50 Pentru simplitate notăm cu h:m:s ora h, m minute şi s secunde.
7 5 15 La primul stand robotul ajunge la ora 11:20:50. Primul stand
376572 are eticheta 376572, care este incorectă, deci robotul o repară.
3564 Aici va petrece 5 secunde pentru veri-ficare şi 15 secunde pentru
123 reparare, deci va pleca de aici la ora 11: 21:10.
La al doilea stand va ajunge la ora 11:21:17; eticheta sa 3564
este corectă deci robotul nu o va mo-difica; aici va petrece 5
secunde pentru verificare şi pleacă la ora 11:21:22.
La al treilea stand va ajunge la ora 11:21:29. Al treilea stand
are eticheta incorectă 123, robotul o repară, deci aici va petrece
5+15=20 secunde şi ora la care ı̂ncheie cursa este 11:21:49.
2 357762 Cerinţa este 2. Există 3 standuri.
3 11 20 50 3564 Primul stand are eticheta 376572, care este incorectă, robotul o
7 5 15 130 repară şi aceasta devine 357762.
376572 La al doilea stand eticheta 3564 este corectă. deci robotul nu o
3564 va modifica.
113 Al treilea stand are eticheta incorectă 113, robotul o repară şi
devine 130.

Timp maxim de executare/test: 0.1 secunde


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

21.2.1 Indicaţii de rezolvare


prof. Adriana Simulescu, Liceul Teoretic GRIGORE MOISIL Timişoara

Vom citi pe rând câte un număr.


Pentru fiecare număr citit, pentru a verifica corectitudinea sa, vom construi numărul corect
format din cifrele numărului citit astfel:
- aşezăm cifrele impare ce apar ı̂n număr ı̂n ordine crescătoare şi contorizăm concomitent
numărul lor
CAPITOLUL 21. ONI 2017 21.2. ROBOT 254

- aşezăm ı̂n continuare cifrele pare ce apar ı̂n număr ı̂n ordine descrescătoare şi contorizăm
concomitent numărul lor
Numărul citit este corect dacă ı̂ndeplineşte simultan condiţiile:
- numărul citit este egal cu numărul construit
- numărul este format atât din cifre pare cât şi din cifre impare
Pentru rezolvarea cerinţei 1)
- contorizăm numerele corecte ı̂n variabila ncorecte
- la final, calculăm timpul astfel:
s=s+(N-1)*(t+v)+(N-ncorecte)*r+v;
m=m+s/60;
s=s%60;
h=h+m/60;
m=m%60;
- scriem ı̂n fişier timpul calculat
Pentru rezolvarea cerinţei 2)
După construirea numărului prin aşezarea cifrelor pare şi impare, dacă acesta conţine:
a) doar cifre pare, ı̂nlocuieşte prima cifră a numărului construit cu cifra 9
b) doar cifre impare, şterge prima cifră a numărului construit şi adaugă 0 la sfârşit
Scriem ı̂n fişier numărul calculat

21.2.2 Cod sursă

Listing 21.2.1: robot adriana.cpp


//Adriana Simulescu
#include <fstream>
#include <iostream>
#include <cmath>

using namespace std;

int main()
{ int N,i,cod,h,m,s,ok,cod1,cod2,ap[10],c,c1,j,T,t,v,r,
ncorecte=0,cif,ci,cp,pp,p2,pi;
ifstream in("robot.in");
ofstream out("robot.out");

in>>T;
in>>N>>h>>m>>s;
in>>t>>v>>r;

if(T==2)
for(i=1;i<=N;i++)
{
in>>cod;
cod2=0;
ci=0;cp=0;pp=1;pi=1;
for(cif=1;cif<=9;cif=cif+2)
{
cod1=cod;
while(cod1>0)
{ if(cod1%10==cif)
{
cod2=cod2*10+cif;ci++; pi*=10;
}
cod1/=10;

}
}
for(cif=8;cif>=0;cif=cif-2)
{
cod1=cod;
while(cod1>0)
{ if(cod1%10==cif)
{
cod2=cod2*10+cif;
cp++;
CAPITOLUL 21. ONI 2017 21.2. ROBOT 255

pp*=10;
}
cod1/=10;
}
}

if(cod==cod2&&ci*cp!=0)
out<<cod<<’\n’;
else
{
if(ci*cp!=0)
out<<cod2<<’\n’;
else
{
if(ci==0)
cod2=cod2%(pp/10)+9*(pp/10);
else
cod2=cod2%(pi/10)*10;
out<<cod2<<’\n’;
}
}
}
else
{
for(i=1;i<=N;i++)
{
in>>cod;
cod2=0;
ci=0;cp=0;pp=1;pi=1;

for(cif=1;cif<=9;cif=cif+2)
{
cod1=cod;
while(cod1>0)
{ if(cod1%10==cif)
{
cod2=cod2*10+cif;ci++;
pi*=10;
}
cod1/=10;
}
}

for(cif=8;cif>=0;cif=cif-2)
{
cod1=cod;
while(cod1>0)
{
if(cod1%10==cif)
{
cod2=cod2*10+cif;cp++;
pp*=10;
}
cod1/=10;
}
}

if(cod==cod2&&ci*cp!=0)
{
ncorecte++;
}
}

s=s+(N-1)*(t+v)+(N-ncorecte)*r+v;
m=m+s/60;
s=s%60;
h=h+m/60;
m=m%60;
out<<h<<" "<<m<<" "<<s<<"\n";
}

in.close();
out.close();
return 0;
}
CAPITOLUL 21. ONI 2017 21.2. ROBOT 256

Listing 21.2.2: robot cp.cpp


//Carmen Popescu
#include <fstream>

using namespace std;

ifstream f("robot.in");
ofstream g("robot.out");

long long verif(long long x)


{
int cif[10]={0};
long long y=0;
int np=0,ni=0,i,j;

while (x>0)
{
cif[x%10]++;
if (x%2==0) np++;
else
ni++;
x=x/10;
}

if (np==0)
{
for (i=1;i<=9;i+=2)
if (cif[i]>0)
{
cif[i]--;
cif[0]=1;
break;
}
}
else
if (ni==0)
{
for (i=8;i>=0;i-=2)
if (cif[i]>0)
{
cif[i]--;
cif[9]=1;
break;
}
}

y=0;
for (i=1;i<=9;i+=2)
for (j=0;j<cif[i];j++)
y=y*10+i;

for (i=8;i>=0;i-=2)
for (j=0;j<cif[i];j++)
y=y*10+i;

return y;
}

int main()
{
int c,n,h,m,s,t,v,r,i;
long long u,x,y;

f>>c;
f>>n>>h>>m>>s>>t>>v>>r;

for (i=0;i<n;i++)
{
f>>x;
y=verif(x);
if (x!=y)
{
s=s+r;
if (s>60)
{
CAPITOLUL 21. ONI 2017 21.2. ROBOT 257

s-=60; m++;
if (m>60)
{
m-=60; h++;
}
}
}
if (c==2)
g<<y<<’\n’;
}

if (c==1)
{
s=s+t*(n-1)+v*n;
m=m+s/60;
s=s%60;
h=h+m/60;
m=m%60;
g<<h<<" "<<m<<" "<<s<<"\n";
}

return 0;
}

Listing 21.2.3: robot ema.cpp


//Emanuela Cerchez
#include <fstream>

using namespace std;

ifstream fin("robot.in");
ofstream fout("robot.out");

int cerinta, n, h,m,s, v, r,t, nr;

int main()
{int i, rez, cx, x, cate, maxpar, minimpar, p10, corect, c, uc, j, timp, hf, mf, sf;
fin>>cerinta;
fin>>n>>h>>m>>s>>t>>v>>r;

if (cerinta ==1)
{
for (i=1; i<=n; i++)
{
fin>>x;
corect=1;
cx=x;
if (x%2==1) corect=0;
else
{ c=x%10; x/=10;
while (x>0 && x%2==0)
{
uc=x%10;
if (uc<c) corect=0;
c=uc;
x=x/10;
}
if (x==0) corect=0;
else
{c=x%10; x/=10;
while (x>0)
{
uc=x%10;
if (uc%2==0) corect=0;
if (uc>c) corect=0;
c=uc;
x/=10;
}
}
}
if (corect) nr++;
}
timp=h*3600+m*60+s+(n-nr)*r+t*(n-1)+v*n;
hf=timp/3600; timp=timp%3600; mf=timp/60; sf=timp%60;
CAPITOLUL 21. ONI 2017 21.2. ROBOT 258

fout<<hf<<’ ’<<mf<<’ ’<<sf<<’\n’;


}
else
{
for (i=1; i<=n; i++)
{
fin>>x;
corect=1; cx=x;
if (x%2==1) corect=0;
else
{ c=x%10; x/=10;
while (x>0 && x%2==0)
{uc=x%10;
if (uc<c) corect=0;
c=uc; x=x/10;
}
if (x==0) corect=0;
else
{c=x%10; x/=10;
while (x>0)
{ uc=x%10;
if (uc%2==0) corect=0;
if (uc>c) corect=0;
c=uc; x/=10;
}
}
}

if (corect) {nr++; rez=cx;}


else
{
rez=0; minimpar=10; maxpar=-1; p10=1;

for (c=1; c<10; c+=2)


{
x=cx; cate=0;
while (x)
{if (x%10==c) cate++; x/=10; }
for (j=0; j<cate; j++)
{rez=rez*10+c; p10*=10;}
if (cate && minimpar==10) minimpar=c;
}

for (c=8; c>=0; c-=2)


{
x=cx; cate=0;
while (x)
{if (x%10==c) cate++; x/=10;}
for (j=0; j<cate; j++)
{rez=rez*10+c; p10*=10;}
if (cate && maxpar==-1) maxpar=c;
}

p10/=10;
if (maxpar==-1) rez=(rez%p10)*10;
if (minimpar==10) rez=9*p10+rez%p10;
}

fout<<rez<<’\n’;
}
}
fout.close();
return 0;
}

Listing 21.2.4: robot-JT.cpp


//Jakab Tunde
#include <iostream>
#include <fstream>

using namespace std;

ifstream f("robot.in");
ofstream g("robot.out");
CAPITOLUL 21. ONI 2017 21.2. ROBOT 259

int main()
{int n,p,h,m,s,t,v,r,ok,a,b,c,i,d;
unsigned long long T=0;

f>>p;

if(p==1)
{
f>>n>>h>>m>>s;
f>>t>>v>>r;
b=0;
for(i=1;i<=n;i++)
{
f>>a;
T=T+t+v;
d=a;
ok=1;
if(a%2!=0)ok=0;
else
{
c=a%10;
a=a/10;
while(c<=a%10 and a%2!=1)
{
c=a%10;
a=a/10;
}
c=a%10;
a=a/10;
if(c%2==0)ok=0;
else
{
while(c>=a%10 and a%2==1)
{
c=a%10;
a=a/10;
}

if(a!=0) ok=0;
}
}

if(!ok)
{
T=T+r;
int x=0,y=0,z1=1,z2=1,j,v;

for(j=1;j<=9;j=j+2)
{
a=d;
while(a!=0)
{
if(a%10==j){x=x*10+j;z1=z1*10;}
a=a/10;
}
}

for(j=8;j>=0;j=j-2)
{
a=d;
while(a!=0)
{
if(a%10==j){y=y*10+j;z2=z2*10;}
a=a/10;
}
}

if(x==0)
{
z2=z2/10;
v=9*z2+y%z2;
}
else
if(y==0)
if(z2>1)v=x*z2;
CAPITOLUL 21. ONI 2017 21.2. ROBOT 260

else
{
z1=z1/10;
v=(x%z1)*10;
}
else v=x*z2+y;
}
}

T=T-t;
h=h+T/3600;
T=T%3600;
m=m+T/60;
T=T%60;
s=s+T;

if(s>=60)
{
m=m+s/60;
s=s%60;
}

if(m>=60)
{
h=h+m/60;
m=m%60;
}

g<<h<<’ ’<<m<<’ ’<<s;


}

if(p==2)
{
f>>n>>h>>m>>s;
f>>t>>v>>r;
b=0;

for(i=1;i<=n;i++)
{
f>>a;
T=T+t+v;
d=a;
ok=1;

if(a%2!=0)ok=0;
else
{
c=a%10;
a=a/10;
while(c<=a%10 and a%2!=1)
{
c=a%10;
a=a/10;
}

c=a%10;
a=a/10;
if(c%2==0)ok=0;
else
{
while(c>=a%10 and a%2==1)
{
c=a%10;
a=a/10;
}

if(a!=0)ok=0;
}
}

if(!ok)
{
T=T+r;
int x=0,y=0,z1=1,z2=1,j,v;

for(j=1;j<=9;j=j+2)
CAPITOLUL 21. ONI 2017 21.3. ROUA 261

{
a=d;
while(a!=0)
{
if(a%10==j){x=x*10+j;z1=z1*10;}
a=a/10;
}
}

for(j=8;j>=0;j=j-2)
{
a=d;
while(a!=0)
{
if(a%10==j){y=y*10+j;z2=z2*10;}
a=a/10;
}
}

if(x==0)
{
z2=z2/10;
v=9*z2+y%z2;
}
else
if(y==0)
if(z2>1)v=x*z2;
else
{
z1=z1/10;
v=(x%z1)*10;
}
else v=x*z2+y;

g<<v<<endl;
}
else g<<d<<endl;
}
}
}

21.2.3 *Rezolvare detaliată

21.3 roua
Problema 3 - roua 100 de puncte
Un copil doreşte să vopsească ouăle de Paşte, având la dispoziţie vopsele de culoare roşie,
galbenă, verde şi albastră. Fiecare culoare va fi reprezentată printr-un singur caracter astfel: ’r’
pentru culoarea roşie, ’g’ pentru galben, ’v’ pentru verde, ’a’ pentru albastru.
Pentru a vopsi ouăle, le aşază ı̂n rând, unul după altul. Astfel, o colorare va fi o succesiune de
N caractere din mulţimea {’r’,’g’,’v’,’a’}, reprezentând, ı̂n ordinea aşezării, culorile celor N ouă.
Numim ”roua” o secvenţă de R caractere cu proprietatea că dintre acestea exact R  1 caractere
reprezintă culoarea roşie, iar un caracter reprezintă una dintre celelalte 3 culori. De exemplu
secvenţele roua de lungime 3 sunt ”grr”, ”rgr”, ”rrg”, ”vrr”, ”rvr”, ”rrv”,”arr”, ”rar”, ”rra”.
Copilul consideră că o colorare este R-frumoasă, dacă oricare R caractere consecutive din
colorare formează o secvenţă roua. De exemplu, pentru N 11 ouă, şirul ”arrrvrrrarr” reprezintă
o colorare 4-frumoasă.

Cerinţe

Cunoscând N , numărul de ouă vopsite, şi numărul natural R, scrieţi un program care determină
şi afişează:
1. numărul de secvenţe ”roua” de lungime R existente ı̂n colorarea celor N ouă;
2. numărul total al colorărilor R-frumoase pentru cele N ouă.

Date de intrare
CAPITOLUL 21. ONI 2017 21.3. ROUA 262

Fişierul de intrare roua.in conţine pe prima linie un număr natural C reprezentând cerinţa
din problemă care trebuie rezolvată (1 sau 2). A doua linie din fişier conţine numerele naturale N
şi R, separate prin spaţiu, reprezentând numărul de ouă şi lungimea unei secvenţe ”roua”. Dacă
C 1, fişierul va conţine şi o a treia linie pe care se află colorarea celor N ouă.

Date de ieşire

Fişierul de ieşire roua.out va conţine o singură linie pe care va fi scris un număr natural,
reprezentând răspunsul la cerinţa specificată ı̂n fişierul de intrare.

Restricţii şi precizări

a3 & N & 10000


a2&R$N
a Pentru rezolvarea corectă a cerinţei 1 se acordă 40 puncte, pentru rezolvarea corectă a cerinţei
2 se acordă 60 de puncte.
a Pentru 60% dintre testele pentru cerinţa 2, 3 & N & 70
a Pentru 40% dintre testele pentru cerinţa 2, N % 70
a Rezultatul la cerinţa 2 poate avea cel mult 2400 de cifre.

Exemple
roua.in roua.out Explicaţii
1 4 Cerinţa este 1. Există N=7 ouă.
7 3 vrrrgrr Secvenţele roua de lungime 3 existente ı̂n colorare sunt ”vrr”,
”rrg”, ”rgr”, ”grr”.
2 15 Cerinţa este 2. Există 4 ouă.
43 Colorările 3-frumoase ale celor 4 ouă sunt ”grrg”, ”grrv”, ”grra”,
”vrrg”, ”vrrv”, ”vrra”, ”arrg”, ”arrv”, ”arra”, ”rgrr”, ”rvrr”,
”rarr”, ”rrgr”, ”rrvr”, ”rrar”.

Timp maxim de executare/test: 0.25 secunde


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

21.3.1 Indicaţii de rezolvare


Autor prof. Cardaş Cerasela-Daniela, Colegiul National A.T.Laurian Botoşani

Variabilele N şi R memorează numărul de caractere, respectiv lungimea unei secvenţe roua.
1. În variabilele p1 şi p2 memorăm penultima, respectiv ultima poziţie a unui caracter diferit
de ’r’.
Pentru fiecare caracter c citit din fişier avem cazurile:
a) c=’r’, incrementăm nr de secvenţe roua dacă p1 ¡ poziţia curentă - R şi p2 ¿ poziţia curentă
-R
b) c j ’r’, incrementăm nr de secvenţe roua dacă poziţia curentă - p2 ' R, actualizăm valorile
lui p1 şi p2.
2. O secvenţă roua este formată din R caractere şi este de forma ”rrr..rXr...r”, unde X este
oricare dintre caracterele ’a’,’g’ sau ’v’ şi ocupă orice poziţie de la 1 la R, ı̂n cadrul unei secvenţe.
Calculăm a N %R, b N ©R.
Pentru deducerea formulei, analizăm mai ı̂ntai cazul a 0.
a) Dacă a 0, există ı̂n şir b grupe de căte R valori consecutive.
Pentru o colorare R-frumoasă, caracterul X poate avea o valoare din 3 valori posibile şi ocupă
aceeaşi poziţie ı̂n cadrul fiecărei grupe.
Poziţia caracterului X este o valoare de la 1 la R =¿ putem forma
b
3 colorări R-frumoase ı̂n care X ocupă poziţia 1,
b
3 colorări R-frumoase ı̂n care X ocupă poziţia 2,
...,
b
3 colorări R-frumoase ı̂n care X ocupă poziţia R .
CAPITOLUL 21. ONI 2017 21.3. ROUA 263

b
In total avem R ˜ 3  colorări posibile.
b) Dacă a j 0, există ı̂n şir b grupe de căte R valori şi o grupă cu ultimele a valori din şir .
Pentru o colorare R-frumoasă, caracterul X va ocupa
b1
- fie o poziţie ı̂ntre 1 şi a ı̂n b  1 grupe, caz ı̂n care se formează a ˜ 3 colorări
b
- fie o poziţie ı̂ntre a  1 şi R ı̂n primele b grupe =¿ se formează R  a ˜ 3 colorări.
In total, numărul de colorări va fi
b1 b b b b b
a˜3  R  a ˜ 3 = a ˜ 3 ˜ 3  R  a ˜ 3 = 3 ˜ a ˜ 3  R  a = 3 ˜ 2 ˜ a  R.

Pentru N & 70 numărul de colorări se poate calcula direct ı̂n long long, iar pentru N % 70 se
va realiza ı̂nmulţirea dintre un număr mare şi un număr de o cifră.

21.3.2 Cod sursă

Listing 21.3.1: roua cardas.cpp


//Cardas Daniela
#include <fstream>

using namespace std;


ifstream in("roua.in");
ofstream out("roua.out");
int N,P,R,i,nroua,p1,p2,a,b,v[2500],x,p,j,ct;
char c;

int main()
{
in>>P;
if(P==1)
{
in>>N>>R>>c;i=1;
while(c==’r’&&i<N)in>>c,i++;
if(c!=’r’){p2=i;if(p2>=R)nroua=1;}
if(c==’r’&&i==N){out<<0<<’\n’;return 0;}

for(i=p2+1; i<=N; i++)


{
in>>c;
if(c!=’r’)
{
if(i-p2+1>R){nroua++;}
p1=p2;p2=i;
}
else
if(p1<=i-R&&i>=R&&p2>i-R){nroua++;}

out<<nroua<<’\n’;
}
else
{
///P=2
in>>N>>R;
a=N%R;b=N/R;

if(N<=70)
{
long long p=1;
for(i=1;i<=b;i++,p*=3);
p=p*(2*a+R);
out<<p<<’\n’;
return 0;
}

///initializam vectorul de cifre cu numarul 2a+R


x=2*a+R;i=0;
while(x)v[++i]=x%10,x/=10;
v[0]=i;
CAPITOLUL 21. ONI 2017 21.3. ROUA 264

///inmultim vectorul de cifre v cu 3 de b ori


for(i=1;i<=b;i++)
{
for(ct=0,j=1;j<=v[0];j++)
{
v[j]*=3;
x=v[j]+ct;v[j]=x%10;ct=x/10;
}
if(ct)
{
v[0]++;v[v[0]]=ct;
}
}

for(i=v[0];i>=1;i--)
out<<v[i];
out<<’\n’;
}
}

Listing 21.3.2: roua cp.cpp


//Carmen Popescu
#include <fstream>
#include <iostream>

using namespace std;

ifstream f("roua.in");
ofstream g("roua.out");

int main()
{
int c,n,r,x,ct,i,j;
char ch[10001];
long long v,p;

f>>c;
f>>n>>r;

if (c==1)
{
x=0;
ct=0;
for (i=0;i<r;i++)
{
f>>ch[i];
if (ch[i]==’r’) x++;
}
if (x==r-1) ct++;
for (i=r;i<n;i++)
{
f>>ch[i];
if (ch[i-r]==’r’) x--;
if (ch[i]==’r’) x++;
if (x==r-1) ct++;
}
g<<ct<<"\n";
}
else
{
// 3ˆ(n/r)*(2*(n%r)+r)
int c[10001],nc=0;
x=n/r;

// 3ˆ(n/r)
nc=1; c[0]=1;
for (i=1;i<=n/r;i++)
{
c[0]=3*c[0];
p=c[0]/10;
c[0]=c[0]%10;
for (j=1;j<nc;j++)
{
c[j]=3*c[j]+p;
CAPITOLUL 21. ONI 2017 21.3. ROUA 265

p=c[j]/10;
c[j]=c[j]%10;
}
while (p>0)
{
c[nc++]=p%10;
p=p/10;
}
}

v=2*(n%r)+r;
if (v>1)
{
p=0;
for (i=0;i<nc;i++)
{
c[i]=v*c[i]+p;
p=c[i]/10;
c[i]=c[i]%10;
}
while (p>0)
{
c[nc]=p%10; nc++;
p=p/10;
}
}

for (i=nc-1;i>=0;i--)
g<<c[i];
g<<"\n";
}
return 0;
}

Listing 21.3.3: roua jt.cpp


//Jakab Tunde
#include <fstream>
using namespace std;

ifstream f("roua.in");
ofstream g("roua.out");
int t[10001];

int main()
{int p,r,n;
f>>p>>n>>r;

if(p==1)
{
int a=1,b=0,h;
char c;
f>>c;
while(c==’r’ and a<=n)
{
f>>c;
a++;
}

if(c==’r’)g<<0;
else
{
if(a>=r)b++;
h=a-1;

for(int i=a+1;i<=n;i++)
{
f>>c;
if(c==’r’)
{
if(i-a<r and i-a+h+1>=r)b++;
}
else
{
h=i-a-1;
CAPITOLUL 21. ONI 2017 21.3. ROUA 266

a=i;
if (h>=r-1)b++;
}
}
}
g<<b;
}
else
{
int a,j,k,b=0,c;
a=2*(n%r)+r;
k=0;

while(a>0)
{
t[++k]=a%10;
a=a/10;
}

b=0;
for(int i=1;i<=n/r;i++)
{
for(j=1;j<=k;j++)
{
c=t[j]*3+b;
t[j]=c%10;
b=c/10;
}
if(c>9)t[++k]=c/10;
b=0;
}

for(int i=k;i>=1;i--)
g<<t[i];
}

f.close();
g.close();
return 0;
}

21.3.3 *Rezolvare detaliată


Capitolul 22

ONI 2016

22.1 Norocos
Problema 1 - Norocos 100 de puncte
Un număr natural nenul m se numeşte norocos dacă pătratul lui se poate scrie ca sumă de
m numere naturale consecutive. Un număr natural m se numeşte k-norocos, dacă este egal cu
produsul a exact k numere prime distincte. Observaţi că ı̂ntre cele două proprietăţi definite nu
există nicio legătură.

Cerinţe

Dându-se k şi N numere naturale, scrieţi un program care să determine:


a) Cel mai mic şi cel mai mare număr norocos dintre cele N numere citite
b) Câte numere k-norocoase sunt ı̂n şirul de N numere citite

Date de intrare

Fişierul de intrare norocos.in conţine pe prima linie un număr natural C. Pentru toate testele
de intrare, numărul C are una din valorile 1 sau 2. Pe linia a doua a fişierului se găsesc numerele
naturale N şi k, cu semnificaţia din enunţ, iar pe a treia linie se găsesc N numere naturale,
separate prin câte un spaţiu.

Date de ieşire

Fişierul de ieşire este norocos.out.


Dacă C 1, se va rezolva numai punctul a). În acest caz, ı̂n fişierul de ieşire se vor scrie,
separate printr-un spaţiu, ı̂n această ordine, cel mai mic şi cel mai mare număr norocos dintre
cele N numere citite. Dacă nu există niciun număr norocos se va afişa valoarea 0. Dacă există un
singur număr norocos, acesta se va afişa de două ori.
Dacă C 2, se va rezolva numai punctul b). În acest caz, ı̂n fişierul de ieşire se va scrie un
singur număr reprezentând numărul de numere k-norocoase citite.

Restricţii şi precizări

a 1 & N & 1000


a 2 & k & 30
a 1 & numerele citite de pe a treia linie a fişierului & 2000000000
a Pentru rezolvarea corectă a primei cerinţe se acordă 40 de puncte, pentru rezolvarea corectă
a celei de-a doua cerinţe se acordă 60 de puncte.

Exemple

267
CAPITOLUL 22. ONI 2016 22.1. NOROCOS 268

norocos.in norocos.out Explicaţii


1 5 165 Atenţie, C 1, deci se va rezolva doar prima
93 cerinţă.
165 12 33 30 5 18 105 15 4 Cel mai mic număr norocos este 5
2
5 =25=3+4+5+6+7
Cel mai mare număr norocos este 165
2
165 =27225=83+84+85+...+246+247 Observaţi
faptul că, deşi se citeşte valoarea lui k, aceasta
nu este folosită ı̂n rezolvarea cerinţei 1.
2 3 Atenţie, C 2, deci se va rezolva doar a doua
53 cerinţă.
165 31 165 105 44 Cele trei numere k-norocoase sunt 165, 165, 105

Timp maxim de executare/test: 0.5 secunde


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

22.1.1 Indicaţii de rezolvare

Ana-Maria Arişanu şi Cristian Frâncu

a)
m este norocos  m
2
a  a  1  a  2  ...  a  m  1 m2
ma  m  1m©2 
2m
2
2ma  m  1m  2m 2a  m  1 
m 2a  1 
m număr impar, a m  1©2
Prin urmare problema se reduce la a determina cel mai mare şi cel mai mic număr impar
dintr-un şir de n numere.
b)
Pentru rezolvarea acestei cerinţe trebuie să descompunem fiecare număr x ı̂n factori primi.
Trebuie să avem grijă de următoarele aspecte:
- Să ne oprim din algoritmul de descompunere imediat ce detectăm că numărul nu poate fi
k-norocos, de exemplu dacă am găsit un factor prim la putere mai mare decât unu, sau dacă am
descoperit mai mult de k factori primi.
- Optimizarea descompunerii ı̂n factori primi a numărului x prin ı̂mpărţire doar la divizorii d
cu proprietatea d ˜ d & x. Dacă am ajuns cu bine la finalul descompunerii şi dacă x este mai mare
decât 1 ı̂nseamnă că el este un număr prim la puterea 1, deci vom incrementa numărul de divizori
găsiţi.

22.1.2 Cod sursă

Listing 22.1.1: norocos.cpp


#include <fstream>
#include <cmath>

using namespace std;

int t, n, k, a, sol, d, e, nr, i, x, ok, r, amax = 0, amin = 2000000000;

int main ()
{
ifstream fin ("norocos.in");
ofstream fout("norocos.out");

fin>>t>>n>>k;
for (i=1;i<=n;i++)
{
fin>>x;

if (t == 1 && x%2 == 1)
{
a++;
if (x < amin) { amin = x; }
CAPITOLUL 22. ONI 2016 22.2. OGLINDA 269

if (x > amax) { amax = x; }


}

if (x == 1) continue;

if (t == 2)
{
ok = 1;
r = (int)sqrt(x);
d = 2;
nr = 0;

while (x != 1 && d <= r)


{
if (x%d == 0)
{
e = 0;
while (x%d == 0)
{
x /= d;
e++;
}

if (e != 1)
{
ok = 0;
break;
}

nr++;
if (nr > k)
{
ok = 0;
break;
}
}

d++;
}

if (x!=1) nr++;
if (nr != k) ok = 0;
if (ok) sol++;
}
}

if (t == 1)
{
if (a == 0) { fout<<a<<"\n"; }
else { fout<<amin<<" "<<amax<<"\n"; }
}
else fout<<sol<<"\n";

return 0;
}

22.1.3 *Rezolvare detaliată

22.2 Oglinda
Problema 2 - Oglinda 100 de puncte
Pentru un număr natural N se consideră şirul a 1, 2, 3..., N , deci ai i pentru orice i,
1 & i & N.
Asupra acestui şir se pot aplica operaţii de două tipuri:
a) la operaţia de tipul 1 se specifică două valori i şi j, cu 1 & i & j & N . Efectul acestei
operaţii asupra şirului este de oglindire a secvenţei din şir care ı̂ncepe cu elementul de pe poziţia
i şi se termină cu cel de pe poziţia j. De exemplu, dacă ı̂n şirul a 1, 2, 3, 4, 5, 6, 7 se aplică
CAPITOLUL 22. ONI 2016 22.2. OGLINDA 270

operaţia 3 6, atunci şirul devine a 1, 2, 6, 5, 4, 3, 7. Iar ı̂n şirul a 1, 4, 3, 2, 5, 6, 7, dacă se
aplică operaţia 4 6, atunci a 1, 4, 3, 6, 5, 2, 7.
b) Operaţia de tipul 2 conţine un indice i, 1 & i & N , şi cere să afişăm valoarea elementului
care se află ı̂n acel moment pe poziţia i ı̂n şir.
Se consideră M astfel de operaţii ı̂ntr-o ordine dată.
Cerinţe
Scrieţi un program care să determine şi să afişeze rezultatul pentru fiecare operaţie de tipul 2.
Date de intrare
Fişierul de intrare oglinda.in conţine pe prima linie două numere naturale N şi M , separate
printr-un spaţiu. Pe fiecare dintre următoarele M linii este specificată câte o operaţie de tipul 1
sau 2. O linie poate să conţină două sau trei numere, astfel: 1 i j (indicând o operaţie de tipul
1) respectiv 2 i (indicând o operaţie de tip 2). Valorile de pe aceeaşi linie sunt separate prin câte
un spaţiu.
Date de ieşire
Fişierul de ieşire oglinda.out conţine un număr de linii egal cu numărul de operaţii de tipul
2 care sunt definite ı̂n fişierul de intrare. Pe fiecare linie este afişat câte un număr natural
reprezintând rezultatul pentru o operaţie de tip 2 prezentă ı̂n fişierul de intrare, ı̂n ordinea ı̂n
care acestea sunt definite.
Restricţii şi precizări
a 1 & N & 1000000
a 1 & M & 2000
a Pentru teste ı̂n valoare de 40 de puncte, vom avea 1 & N & 2000.
a Se garantează că 1 & i & j & N la operaţiile de tipul 1 şi că 1 & i & N la operaţiile de tip 2.
a Se garantează că există cel puţin o operaţie de tipul 2.

Exemple
oglinda.in oglinda.out Explicaţii
10 4 3 Şirul iniţial este: 1 2 3 4 5 6 7 8 9 10
23 6 Rezultatul operaţiei 2 3 are ca efect afişarea elementului de pe
127 1 poziţia 3 (care este chiar 3).
23 Rezultatul operaţiei 1 2 7 are ca efect transformarea şirului ı̂n:
21 1 7 6 5 4 3 2 8 9 10.
Rezultatul operaţiei 2 3 are ca efect afişarea elementului de pe
poziţia 3 (care acum este 6).
Rezultatul operaţiei 2 1 are ca efect afişarea elementului de pe
poziţia 1 (care acum are valoarea 1).

Timp maxim de executare/test: 0.3 secunde


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

22.2.1 Indicaţii de rezolvare

prof. Marius Nicoli, C.N. ”Fraţii Buzeşti”, Craiova


O primă abordare a problemei se face prin simularea operaţiilor date pe un vector cu N
componente. Această soluţie nu se ı̂ncadrează ı̂n timp pe toate testele.
Pentru punctaj maxim se poate proceda astfel: se reţin operaţiile de tip 1 ı̂n doi vectori unul
pentru capetele stânga ale intervalelor de indici date şi altul pentru capetele din dreapta.
La ı̂ntâlnirea unei operaţii de tip 2 se determină valoarea iniţială de pe poziţia a, actualizând
pe a current prin aplicarea ı̂n ordine inversă a operaţiilor de tip 1 ı̂ntâlnite până atunci. Informaţii
despre aceste operaţii le găsim ı̂n cei doi vectori.
La o operaţie de tip 1 s, d (memorată ı̂n vector ı̂n momentul apariţiei sale), aceasta afectează
pe a doar dacă a este cuprins ı̂ntre s şi d (inclusiv). Timpul de executare este de ordinul m ˜ m
(m este numărul de operaţii).
CAPITOLUL 22. ONI 2016 22.3. PERECHI 271

22.2.2 Cod sursă

Listing 22.2.1: oglinda.cpp


#include <fstream>
#define DIMM 2010

using namespace std;

int S[DIMM], D[DIMM];


int n, m, i, j, a, b, t, k, x;

int main ()
{
ifstream fin ("oglinda.in");
ofstream fout("oglinda.out");

fin>>n>>m;
for (i=1;i<=m;i++)
{
fin>>t;
if (t == 1)
{
k++;
fin>>S[k]>>D[k];
}
else
{
fin>>a;
for (j=k; j>=1; j--)
{
if (S[j] <= a && a <= D[j])
{
x = a - S[j];
a = D[j] - x;
}
}

fout<<a<<"\n";
}
}
return 0;
}

22.2.3 *Rezolvare detaliată

22.3 Perechi
Problema 3 - Perechi 100 de puncte
Fie un şir a1 , a2 , ..., an de numere naturale, unde n este impar. Avem la dispoziţie o singură
operaţie admisă şi anume: putem aduna la două poziţii diferite din şir o aceeaşi valoare naturală
nenulă.

Cerinţe

1. Să se verifice dacă şirul poate să aibă toate elementele egale după aplicarea unei singure
operaţii.
2. Folosind de mai multe ori operaţia admisă, să se obţină şirul cu toate elementele egale, dar
valoarea egală obţinută să nu depăşească dublul valorii maxime din şirul iniţial.

Date de intrare

Fişierul perechi.in conţine pe prima linie un număr natural C, pe a doua linie numărul n, iar
pe linia a treia, separate prin câte un spaţiu, valorile a1 , a2 , ..., an .
CAPITOLUL 22. ONI 2016 22.3. PERECHI 272

Date de ieşire

Fişierul perechi.out va conţine


1. Dacă C 1, atunci se va rezolva doar prima cerinţă, deci se va afişa pe prima linie valoarea
0 dacă nu se pot obţine ı̂n şir toate elementele egale, sau se vor afişa trei numere naturale i j v
cu semnificaţia: la poziţiile i şi j din şir se adaugă valoarea v şi astfel toate elementele vectorului
vor deveni egale.
2. Dacă C 2, atunci se va rezolva doar a doua cerinţă. Pe fiecare linie a fişierului de ieşire
se vor afişa exact trei valori i j v cu semnificaţia: se adună valoarea v la ai şi la aj (unde i şi j
sunt distincte şi sunt cuprinse ı̂ntre 1 şi n).

Restricţii şi precizări

a 5 & n $ 2000, n este impar


a 0 & ai & 100000000 pentru orice i 1, ..., n
a Elementele şirului iniţial nu sunt neapărat distincte, dar nu sunt nici toate egale
a Dacă există mai multe soluţii, puteţi afişa oricare dintre ele
a Dacă numărul operaţiilor aplicate este mai mic sau egal decât n iar valoarea finală este de
cel mult două ori cât maximul iniţial şi rezultatul aplicării operaţiilor furnizează ı̂n şir aceeaşi
valoare, atunci veţi primi 100% din punctaj
a Dacă numărul ope raţiilor este cuprins ı̂ntre n  1 şi 2n iar valoarea finală este de cel mult
două ori cât maximul iniţial şi rezultatul aplicării operaţiilor furnizează ı̂n şir aceeaşi valoare,
atunci veţi primi 70% din punctaj
a Dacă numărul operaţiilor este mai mare de 2n sau dacă valoarea finală depăşeşte dublul valorii
maxime iniţiale, atunci veţi primi 0 puncte . De asemenea, dacă ı̂n urma operaţiilor aplicate nu
se obţine un şir cu aceeaşi valoare peste tot, sau dacă aplicaţi o operaţie ı̂n care poziţiile i şi j nu
sunt din intervalul 1...n, atunci deasemenea veţi primi 0 puncte
a Pentru teste valorând 20 de puncte vom avea C 1. Pentru restul testelor vom avea C 2,
din care pentru 30 de puncte şirul va fi format din numere distincte cuprinse ı̂ntre 1 şi n

Exemple
perechi.in perechi.out Explicaţii
1582882 256 C 1, deci se va rezolva doar prima cerinţă! Adunând valoarea
6 la poziţiile 2 şi 5 se va obţine şirul constant 8 8 8 8 8
2 122 C 2, deci se va rezolva doar a doua cerinţă! Valoarea maximă
5 344 din şir este 10, deci valoarea finală trebuie să fie maximum 20.
8 5 6 3 10 243 Trebuie efectuate cel mult 5 operaţii pentru 100 puncte.
Aplicând operaţia 1 2 2, obţinem şirul 10 7 6 3 10
Aplicând operaţia 3 4 4, obţinem şirul 10 7 10 7 10
Aplicând operaţia 2 4 3, obţinem şirul 10 10 10 10 10
1 0 C 1, deci se va rezolva doar prima cerinţă! Nu se poate efectua
5 o singură operaţie astfel ı̂ncât toate elementele şirului să devină
82782 egale.
2 131 C 2, deci se va rezolva doar a doua cerinţă! Valoarea maximă
3 122 din şir este 3, deci valoarea finală trebuie să fie maximum 6.
123 Trebuie efectuate cel mult 3 operaţii pentru 100 puncte.
Aplicând operaţia 1 3 1, obţinem şirul 2 2 4
Aplicând operaţia 1 2 2, obţinem şirul 4 4 4

Timp maxim de executare/test: 0.5 secunde


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

22.3.1 Indicaţii de rezolvare

prof. Dan Pracsiu, Liceul Teoretic Emil Racoviţă Vaslui

Cerinţa 1
CAPITOLUL 22. ONI 2016 22.3. PERECHI 273

Se verifică dacă ı̂n şir sunt doar două valori distincte, una care apare de 2 ori, cealaltă care
apare de n  2 ori. În caz afirmativ, se verifică dacă valoarea care apare de două ori este mai mică
decât cealaltă valoare.
Cerinţa 2
Ordonăm crescător şirul. Deoarece trebuie să rămână ordinea iniţială, păstrăm indicii ele-
mentelor ordonate.
După sortare pornim de la stânga la dreapta şi luăm iniţial primele două elemente ale şirului
sortat (cele mai mici).
Fie acestea a şi b cu a & b. Adunăm la cele două componente valoarea dată de diferenţa dintre
cel mai mare din elementele şirului (acesta se găseşte pe ultima poziţie ı̂n şirul sortat şi ı̂l notăm
cu max) şi a.
După această operaţie, pe primele două poziţii vom avea valorile max şi b  max  a (& max).
Deci acum valoarea maximă ı̂n şir, max, se află sigur pe a doua poziţie.
Procedăm analog cu componentele de pe poziţiile 3 şi 4 (notate la fel cu a şi b), adunând la
acestea valoarea max  a, obţinând valorile max şi b  max  a.
Similar se procedează cu toate perechile de pe poziţiile 2p  1, 2p.
Ultima de acest fel este n  2, n  1 (nu uităm că n este impar).
În acest moment am efectuat (n-1) div 2 operaţii de adunare, iar valoarea de pe prima
poziţie este egală cu cea de pe ultima poziţie, iar ı̂n rest, valorile de pe poziţiile 2p sunt egale cu
valorile de pe poziţiile 2p  1.
Maximul ı̂n şir este pe penultima poziţie n  1.
Vom aduna la toate cuplurile egale atât cât este necesar să ajungem la valoarea maximă (deci
ı̂ncă (n-1) div 2 operaţii).
În total am efectuat n  1 operaţii, deci ne ı̂ncadrăm ı̂n limita de n operaţii efectuate.

22.3.2 Cod sursă

Listing 22.3.1: perechi.cpp


#include <fstream>

#define inFile "perechi.in"


#define outFile "perechi.out"
#define Dim 10005

using namespace std;

int a[Dim];
int P[Dim];
int n;

void Cerinta1()
{
int i, cnt;
ofstream fout(outFile);

/// verifica nr de numere diferite


cnt = 1;
for (i = 2; i <= n; ++i)
if (a[i] != a[i - 1]) cnt++;

if (cnt != 2 || a[2] == a[3])


{
fout << "0\n";
fout.close();
return ;
}

cnt = a[3] - a[2];


fout<<P[1]<<" "<<P[2]<<" "<<cnt<<"\n";
fout.close();
}

void Cerinta2()
{
int i, ultim, v;
CAPITOLUL 22. ONI 2016 22.3. PERECHI 274

ofstream fout(outFile);

ultim = n;
for (i = 1; i < n; i += 2)
{
v = a[ultim] - a[i];
if (v > 0)
{
a[i] += v;
a[i + 1] += v;
fout << P[i] << " " << P[i + 1] << " " << v << "\n";
a[++ultim] = a[i];
P[ultim] = P[i];
a[++ultim] = a[i + 1];
P[ultim] = P[i + 1];
}
}

for ( ; i < ultim; i += 2)


{
v = a[ultim] - a[i];
if (v > 0)
{
a[i] += v;
a[i + 1] += v;
fout << P[i] << " " << P[i + 1] << " " << v << "\n";
}
}
fout.close();
}

int main()
{
int i, j, C;
int aux;

//citire
ifstream fin(inFile);
fin >> C;
fin >> n;
for (i = 1; i <= n; ++i)
{
fin >> a[i];
P[i] = i;
}
fin.close();

//sortare
for (i = 1; i < n; ++i)
for (j = i + 1; j <= n; ++j)
if (a[i] > a[j])
{
aux = a[i];
a[i] = a[j];
a[j] = aux;
aux = P[i];
P[i] = P[j];
P[j] = aux;
}

if (C == 1) Cerinta1();
else Cerinta2();
return 0;
}

22.3.3 *Rezolvare detaliată


Capitolul 23

ONI 2015

23.1 iepuras
Problema 1 - iepuras 100 de puncte
Iepuraşul Coconaş vrea să ajungă la grădina cu morcovi. Pentru aceasta el trebuie să traverseze
prin salturi o zonă cu proprietăţi speciale. Zona este formată din N căsuţe numerotate de la 1 la
N , dispuse una după cealaltă, iar fiecare căsuţă conţine un număr natural ce reprezintă cantitatea
de energie necesară iepuraşului pentru a sări ı̂ntr-o altă căsuţă. Iepuraşul pleacă dintr-o anumită
căsuţă şi se deplasează, de la stânga la dreapta, spre grădina cu morcovi după următoarele reguli:
a numărul ı̂nscris ı̂n căsuţa ı̂n care se află iepuraşul reprezintă numărul de căsuţe peste care
el va sări;
a dacă numărul ı̂nscris ı̂n căsuţa ı̂n care se află iepuraşul este număr prim, atunci energia lui
se dublează şi va sări peste un număr dublu de căsuţe;
a numărarea căsuţelor peste care va sări se face de la stânga la dreapta şi ı̂ncepe cu căsuţa
imediat următoare.
Astfel, dacă iepuraşul se află ı̂n căsuţa a treia şi numărul ı̂nscris ı̂n această căsuţă este 5,
iepuraşul va ajunge ı̂n căsuţa cu numărul de ordine 13 (13 3  2 ˜ 5).
a dacă iepuraşul ajunge ı̂ntr-o căsuţă care conţine numărul 0, el rămâne acolo pentru că nu
mai are energie să sară mai departe, altfel el continuă să sară după regulile descrise mai sus;
a iepuraşul ajunge la grădina cu morcovi dacă ultimul salt pe care ı̂l face depăşeşte căsuţa N .

Cerinţe

Scrieţi un program care citeşte trei numere naturale P , N şi K iar apoi N numere naturale şi
determină:
1) dacă iepuraşul poate ajunge sau nu, la grădina cu morcovi pornind din căsuţa K şi numărul
de salturi pe care le face iepuraşul pornind din căsuţa K;
2) căsuţa de pornire a iepuraşului, astfel ı̂ncât drumul parcurs de el să traverseze un număr
maxim de căsuţe. Pentru a determina numărul de căsuţe se vor lua ı̂n calcul: căsuţa de pornire,
toate căsuţele peste care iepuraşul a sărit şi toate căsuţele ı̂n care a ajuns ı̂n urma salturilor.
Iepuraşul poate porni din oricare căsuţă. În cazul ı̂n care există două sau mai multe căsuţe de
pornire care conduc la acelaşi număr maxim de căsuţe traversate se va lua ı̂n considerare căsuţa
cu numărul de ordine cel mai mic.

Date de intrare

Fişierul de intrare iepuras.in conţine pe prima linie un număr natural P . Pentru toate testele
de intrare, numărul P poate avea doar valoarea 1 sau valoarea 2.
Pe a doua linie a fişierului iepuras.in se găsesc, ı̂n această ordine, numerele naturale N şi K,
separate prin câte un spaţiu.
Pe a treia linie se găsesc N numere naturale separate prin câte un spaţiu, reprezentând valorile
din fiecare căsuţă ı̂n ordine de la 1 la N .

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 iepuras.out va conţine pe prima linie cuvântul DA ı̂n cazul ı̂n care iepuraşul a ajuns ı̂n

275
CAPITOLUL 23. ONI 2015 23.1. IEPURAS 276

grădina cu morcovi, respectiv cuvântul NU ı̂n caz contrar, iar pe a doua linie va conţine un număr
natural reprezentând numărul de salturi pe care le face iepuraşul pornind din căsuţa K.
Dacă valoarea lui P este 2, se va rezolva numai punctul 2) din cerinţe. În acest caz, fişierul
de ieşire iepuras.out va conţine pe prima linie două numere naturale separate printr-un spaţiu
reprezentând, ı̂n ordine, căsuţa de pornire şi numărul maxim de căsuţe determinat, iar pe a doua
linie, un şir de numere naturale separate prin câte un spaţiu reprezentând numerele din căsuţele ı̂n
care iepuraşul nu s-a aflat sau nu a sărit pe parcursul drumului, de la stânga la dreapta, ı̂ncepând
cu căsuţa 1. Dacă numărul maxim de căsuţe traversate este chiar N linia a doua nu va conţine
niciun număr.

Restricţii şi precizări

a1 & N & 7000


a1&K&N
a 0 & numerele conţinute ı̂n căsuţe & 100
a Pentru rezolvarea corectă a primei cerinţe se acordă 30 de puncte, pentru rezolvarea corectă
a celei de a doua cerinţe se acordă 70 de puncte.

Exemple
iepuras.in iepuras.out Explicaţii
NU P 1, pentru acest test, se rezolva cerinţa 1).
2 Iepuraşul pleacă din căsuţa 3, sare ı̂n căsuţa cu
numărul de ordine 7 şi mai departe, ı̂n căsuţa
cu numărul de ordine 11, unde găsind numărul
0 se opreşte.
2 2 13 P 2, pentru acest test, se rezolvă cerinţa
14 3 2601120021 2). Pentru a traversa un număr maxim de
23601121400231 căsuţe, iepuraşul pleacă din căsuţa cu numărul
de ordine 2 şi sare, pe rând, ı̂n căsuţele cu
numerele de ordine 8, 9, 13, şi apoi ı̂n grădină,
traversând astfel 13 căsuţe (de la căsuţa 2 la
căsuţa 14). Iepuraşul nu s-a aflat sau nu a
sărit ı̂n căsuţele de pe poziţiile 1, 3, 4, 5, 6, 7,
10, 11, 12 şi 14.

Timp maxim de executare/test: 1.0 secunde


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

23.1.1 Indicaţii de rezolvare


Soluţia 1
Cerinţa 1
Memorăm traseul cu căsuţe ı̂ntr-un vector pe poziţiile de la 1 pâna la N .
Pornim parcurgerea vectorului de la poziţia k şi parcurgem vectorul cât timp valoarea gasită
ı̂n căsuţă este diferită de 0 şi indicele căsuţei este mai mic sau egal cu N .
Creştem indicele vectorului cu valoarea care se găseşte memorată ı̂n căsuţă dacă numărul nu
este prim sau cu dublul valorii care se găseşte ı̂n căsuţă dacă numărul este prim. Incrementăm
numărul de salturi pe care le face iepuraşul.
Algoritmul se repetă până când ajungem ı̂ntr-o căsuţă care conţine numărul 0 sau până când
indicele calculat depăşeşte valoarea N .
Dacă indicele la care ajungem este mai mic sau egal cu N , iepuraşul nu ajunge la grădina cu
morcovi şi scriem N U , altfel iepuraşul ajunge la grădina cu morcovi şi scriem DA.
La final afişăm numărul de salturi.

Cerinţa 2
Calculăm numărul de căsuţe peste care poate sări iepuraşul (ca la cerinţa 1) pornind din căsuţa
1.
CAPITOLUL 23. ONI 2015 23.1. IEPURAS 277

Dacă indicele căsuţei la care ajunge iepuraşul este mai mare strict decat N atunci
numărul de căsuţe = N - poziţia de pornire + 1
altfel
numărul de căsuţe = indicele căsuţe - poziţia de pornire + 1.
Actualizăm maximum şi poziţia de pornire.
Repetăm algoritmul pentru restul căsuţelor până la N .
Scriem poziţia de pornire şi valoarea numărului maxim de căsuţe ı̂n fişier.
Scriem toate căsuţele de la 1 până la căsuţa de pornire determinată mai sus apoi scriem toate
căsuţele de pe traseul iepuraşului, cu excepţia căsuţei de pornire şi a celor ı̂n care a sărit.
Dacă ultima căsuţă ı̂n care ajunge iepuraşul are indicele strict mai mic decât N , scriem restul
căsuţelor până la N .
2
Soluţia are complexitatea O n .
Soluţia 2
Cerinţa 1
Se memorează numerele din casuţe ı̂ntr-un vector v.
Se simulează săriturile iepuraşului ce porneşte din căsuţa k şi se opreste fie când ajunge la o
căsuţă ce conţine numărul 0 fie când ajunge ı̂n grădina cu morcovi.
Cerinţa 2
Pentru a determina numărul maxim de căsuţe traversate se construieşte ı̂ncepând cu poziţia
n, un vector suplimentar a cu semnificaţia:
ai = poziţia ı̂n care se opreşte iepuraşul ce porneşte din căsuţa cu numărul i.

~
„n; dacă pornim din poziţia i iepuraşul ajunge ı̂n grădină
„
„
„i;
„ dacă ai 0
ai „
‚
„
„
„ai  2 ˜ ai; dacă ai este număr prim
„
„
„ai  ai; dacă ai nu este număr prim
€
Pentru fiecare poziţie i, ı̂ncepând cu poziţia n se determină numărul căsuţelor traversate ca
fiind l ai  i  1 şi se actualizează valoarea maximă, reţinându-se poziţia.

23.1.2 Cod sursă

Listing 23.1.1: iepuras 1.cpp


#include <iostream>
#include <fstream>
#include <cmath>

using namespace std;


const int DIM=100000;
int v[DIM],x[101];

/*void afisare(int N, unsigned int v[DIM])


{
int i;
for(i=1;i<=N;i++)
cout<<v[i]<<’ ’;
cout<<endl;
}*/

void prim(int n)
{
int i,j;
for (i=2;i<=n;i++)
x[i]=1;
for (i=2;i<=sqrt(n);i++)
if (x[i])
for (j=i;j<=n/i;j++)
x[i*j]=0;
}

int main()
CAPITOLUL 23. ONI 2015 23.1. IEPURAS 278

{
int N, K, P, i, j, l, nr=0, Max=0, poz; //nr-numar salturi din pozitia i
ifstream in("iepuras.in");
ofstream out("iepuras.out");

in>>P>>N>>K;
for(i=1;i<=N;i++) in>>v[i];
prim(100);

if(P==1)
{ //cerinta 1
j=K; nr=0;
while(v[j] && j<=N)
{
nr++;
if(x[v[j]])
j+=2*v[j];
else
j+=v[j];
}

if(j<=N)
{
out<<"NU"<<endl;
out<<nr;
}
else
{
out<<"DA"<<endl;
out<<nr;
}
}
else
{
//cerinta 2
i=1,j=1;
while(i<=N && j<=N)
{
j=i;nr=1;
while(v[j] && j<=N)
{
if(x[v[j]])
j+=2*v[j];
else
j+=v[j];
}

if(j>N)
nr=N-i+1;
else
nr=j-i+1;
if(nr>Max)
poz=i, Max=nr;
i++;
}

out<<poz<<’ ’<<Max<<’\n’;

for(i=1;i<=poz-1;i++)
out<<v[i]<<’ ’;

j=poz;
for(i=1;i<=Max && i<=N;i++)
{
if(x[v[j]])
j+=2*v[j];
else
j+=v[j];

for(l=poz+1;l<j && l<=N;l++)


out<<v[l]<<’ ’;

poz=j;
}
CAPITOLUL 23. ONI 2015 23.1. IEPURAS 279

for(i=j+1;i<=N;i++)
out<<v[i]<<’ ’;
}
return 0;
}

Listing 23.1.2: iepuras 2.cpp


#include <cstdio>
#include <cassert>

using namespace std;

int i, N, A[100005], Countstep, step, P, K, Pos, Count, CountMax;


bool Prim[100];

bool prim(int x)
{
for(int d=2; d*d<=x; d++)
if(x%d==0) return false;
return (x>=2);
}

int main()
{
freopen("iepuras.in", "r",stdin);
freopen("iepuras.out","w",stdout);

scanf("%d\n%d%d\n",&P, &N, &K);


assert(P>0&& P<3 && N>=1 && N<=7000);

for(int i=1; i<=N; i++)


{
scanf("%d", &A[i]);
assert( A[i]>=0 && A[i]<=100);
}

for(int i=2; i<=100; i++) Prim[i]=prim(i);

if(P==1)
{ Countstep=0;
for(i=K; i<=N && A[i]; i+=step, Countstep++)
{
if (Prim[A[i]]) step=A[i]*2;
else step=A[i];
}

if (i>N) printf("DA\n%d", Countstep);


else printf("NU\n%d", Countstep);
}
else
{
CountMax=0;
for(int I=1; I<=N ; I++)
{
for(i=I; i<=N && A[i]; i+=step)
{
if (Prim[A[i]]) step=A[i]*2;
else step=A[i];
}

if (i>N) i = N;

if(i- I + 1>CountMax)
{
CountMax=i- I + 1;
Pos = I;
}
}

printf("%d %d\n", Pos, CountMax);

for(i=1; i<=N; i++)


if(i!=Pos) printf("%d ", A[i]);
else
CAPITOLUL 23. ONI 2015 23.1. IEPURAS 280

if (Prim[A[i]]) Pos+=A[i]*2;
else Pos+=A[i];
}

return 0;
}

Listing 23.1.3: iepuras 3.cpp


#include <cstdio>
#include <cassert>

using namespace std;

int i, N, A[100005],Countstep, step, P, K, Pos, Count, CountMax;


bool Prim[100];

bool prim(int x)
{
for(int d=2; d*d<=x; d++)
if(x%d==0) return false;
return (x>=2);
}

int main()
{
freopen("iepuras.in", "r",stdin);
freopen("iepuras.out","w",stdout);

scanf("%d\n%d%d\n",&P, &N, &K);

for(int i=1; i<=N; i++)


{
scanf("%d", &A[i]);
}

for(int i=2; i<=100; i++) Prim[i]=prim(i);

if(P==1)
{ Countstep=0;
for(i=K; i<=N && A[i]; i+=step, Countstep++)
{
if (Prim[A[i]]) step=A[i]*2;
else step=A[i];
}

if (i>N) printf("DA\n%d", Countstep);


else printf("NU\n%d", Countstep);
}
else
{
CountMax=0;
for(int I=1; I<=N ; I++)
{
for(i=I; i<=N && A[i]; i+=step)
{
if (Prim[A[i]]) step=A[i]*2;
else step=A[i];
}

if (i>N) i = N;

if(i- I + 1>CountMax)
{
CountMax=i- I + 1;
Pos = I;
}
}

printf("%d %d\n", Pos, CountMax);

for(i=1; i<=N; i++)


if(i!=Pos) printf("%d ", A[i]);
else
if (Prim[A[i]]) Pos+=A[i]*2;
CAPITOLUL 23. ONI 2015 23.1. IEPURAS 281

else Pos+=A[i];
}

return 0;
}

Listing 23.1.4: iepuras 4.cpp


#include <fstream>
#include <iostream>

using namespace std;

int prim (int x)


{
if (x<2) return 0;
if (x==2) return 1;
if (x%2==0) return 0;
for (int i=3; i*i<=x; i++)
if (x%i==0) return 0;
return 1;
}

int v[100001];
int a[100001];

int main()
{
ifstream f("iepuras.in");
ofstream g("iepuras.out");

int n,p,k,i,j,nr=0,l;

f>>p>>n>>k;
for (i=1; i<=n; i++) f>>v[i];

if (p==1)
{
while (k<=n && v[k]!=0)
{
nr++;
if (prim (v[k])) k=k+2*v[k];
else k=k+v[k];
}

if (k>n) g<<"DA"<<’\n’<<nr<<’\n’;
else g<<"NU"<<’\n’<<nr<<’\n’;
}
else
{
int vm=-1;
for (i=n; i>=1; i--)
{
if (v[i]==0)
a[i]=i;
else
if (prim(v[i]))
{
j=i+2*v[i];
if (j<n) a[i]=a[j];
else a[i]=n;
}
else
{
j=i+v[i];
if (j<n) a[i]=a[j];
else a[i]=n;
}

l=a[i]-i+1;
if (vm<=l){vm=l; k=i;}
}

g<<k<<’ ’<<vm<<’\n’;
CAPITOLUL 23. ONI 2015 23.1. IEPURAS 282

int u=1;

for (i=1; i<k; i++) g<<v[i]<<’ ’;

while (k<=n && v[k]!=0)


{
u=k+1;
if (prim (v[k])) k=k+2*v[k];
else k=k+v[k];

if (k<=n) for (i=u; i<k; i++) g<<v[i]<<’ ’;


else for (i=u; i<=n; i++) g<<v[i]<<’ ’;
}

if (k<n && v[k]==0)


for (i=k+1; i<=n; i++) g<<v[i]<<’ ’;

g<<’\n’;
}

return 0;
}

Listing 23.1.5: iepuras 5.cpp


#include <fstream>
#include <cassert>

using namespace std;

int prim (int x)


{
if (x<2) return 0;
if (x==2) return 1;
if (x%2==0) return 0;
for (int i=3; i*i<=x; i++)
if (x%i==0) return 0;
return 1;
}

int v[100001];
int a[100001];

int main()
{
ifstream f("iepuras.in");
ofstream g("iepuras.out");

int n,p,k,i,j,nr=0,l,x;

f>>p>>n>>k;

i=0;
while (f>>x)
{
i++; v[i]=x;
assert (v[i]>=0&&v[i]<=100);
}

assert(p==1 || p==2);
assert(n>=1&& n<=7000);
assert(k<=n && k>=1);
assert(i==n);

if (p==1)
{
while (k<=n && v[k]!=0)
{
nr++;
if (prim (v[k])) k=k+2*v[k];
else k=k+v[k];
}

if (k>n) g<<"DA"<<’\n’<<nr<<’\n’;
else g<<"NU"<<’\n’<<nr<<’\n’;
CAPITOLUL 23. ONI 2015 23.1. IEPURAS 283

}
else
{
int vm=-1;
for (i=n; i>=1; i--)
{
if (v[i]==0)
a[i]=i;
else
if (prim(v[i]))
{
j=i+2*v[i];
if (j<n) a[i]=a[j];
else a[i]=n;
}
else
{
j=i+v[i];
if (j<n) a[i]=a[j];
else a[i]=n;
}

l=a[i]-i+1;
if (vm<=l){vm=l; k=i;}
}

g<<k<<’ ’<<vm<<’\n’;

int u=1;

for (i=1; i<k; i++) g<<v[i]<<’ ’;


while (k<=n && v[k]!=0)
{
u=k+1;
if (prim (v[k])) k=k+2*v[k];
else k=k+v[k];

if (k<=n) for (i=u; i<k; i++) g<<v[i]<<’ ’;


else for (i=u; i<=n; i++) g<<v[i]<<’ ’;
}

if (k<n && v[k]==0)


for (i=k+1; i<=n; i++) g<<v[i]<<’ ’;

g<<’\n’;
}

return 0;
}

Listing 23.1.6: iepuras 6.cpp


#include <fstream>
#include <math.h>

#define MAX 100

using namespace std;

ifstream f("iepuras.in");
ofstream g("iepuras.out");

bool c[MAX],e1[100001];
int e[100001],salturi,N,P,M,K,pozMin,nrMax;

int main()
{
int i,j,aux;
c[1]=1;

//generare ciur
M=sqrt(MAX);
for(i=2;i<=M;i++)
if(c[i]==0)
for(j=i*i;j<=MAX;j+=i)c[j]=1;
CAPITOLUL 23. ONI 2015 23.1. IEPURAS 284

//citire
f>>P>>N>>K;
for(i=1;i<=N;i++)f>>e[i];

if(P==1)//1)
{
//sarituri iepure
for(i=K;i<=N;)
if(e[i]==0)break;
else
{
salturi++;aux=e[i];if(c[aux]==0)aux*=2; i=i+aux;
}

//verficare
if(i<=N)g<<"NU"<<’\n’;else g<<"DA"<<’\n’;
g<<salturi<<’\n’;
}
else//2)
{
for(i=1;N-i>nrMax;i++)
{
//caut nrMax si pozMin
j=i;
while(j<=N && e[j]!=0)
{
if(c[e[j]]==0)j+=2*e[j];
else j+=e[j];
}

if(j>N)salturi=N-i+1;
else salturi=j-i+1;

if(salturi>nrMax) {nrMax=salturi;pozMin=i;}
}

//afisez pozMin si nrMax


g<<pozMin<<’ ’<<nrMax<<’\n’;

//afisez casutele pana la pozMin


for(i=1;i<pozMin;i++) g<<e[i]<<’ ’;

//fac traseul maxim


for(i=pozMin;i<=N;)
{
e1[i]=1;
if(e[i]==0)break;
else
{
aux=e[i];if(c[aux]==0)aux*=2;i+=aux;e1[i]=1;
}
}

//afisez casutele de la pozMin pana unde a mers


for(i=pozMin;i<=pozMin+nrMax-1;i++)
if(e1[i]==0)g<<e[i]<<’ ’;

//afisez casutele pana la N


for(;i<=N;i++)if(e1[i]!=-1)g<<e[i]<<’ ’;

g<<’\n’;
}

f.close();
g.close();
return 0;
}

23.1.3 *Rezolvare detaliată


CAPITOLUL 23. ONI 2015 23.2. INVENTIE 285

23.2 inventie
Problema 2 - inventie 100 de puncte
Lui Mihai ı̂i place matematica distractivă, sau poate mai mult distracţia decât matematica.
Pentru a scăpa de teme, el a inventat operaţia ”smile” notată cu semnul , operaţie care se aplică
numerelor naturale nenule conform exemplelor de mai jos:
6 4=210 8 5=313 6 6=12 43 1500=1457 1543
9 2=711 7 6=113 6 10=416 23 23=46
Profesorul de matematică i-a promis nota 10 pentru invenţie, numai dacă ştie să determine
corect numărul divizorilor pari pentru rezultatul obţinut prin operaţia ”smile”. Astfel, Mihai
a primit N perechi de numere a, b pentru care trebuie să calculeze a b şi să determine dacă
rezultatul obţinut are divizori pari.

Cerinţe

Scrieţi un program care citeşte un număr natural N şi N perechi de numere naturale a, b şi
afişează:
a) pentru fiecare pereche de numere a, b, rezultatul a b;
b) cel mai mic şi cel mai mare rezultat a b care nu are divizori pari.

Date de intrare

Fişierul de intrare inventie.in conţine pe prima linie un număr natural N . Fiecare din
următoarele N linii conţine câte două numere naturale a, b despărţite printr-un spaţiu.

Date de ieşire

În fişierul de ieşire inventie.out:


a pentru fiecare din cele N perechi a, b, se va afişa rezultatul a b, fiecare rezultat pe câte o
linie, ı̂n ordinea ı̂n care perechile apar ı̂n fişierul de intrare;
a dacă toate cele N rezultate obţinute au divizori pari, pe linia N  1 se va afişa valoarea 0
(zero);
a dacă s-a obţinut măcar un rezultat fără divizori pari, atunci, pe linia N  1 se va afişa cel
mai mic rezultat a b care nu are divizori pari, şi pe linia N  2 se va afişa cel mai mare rezultat
a b care nu are divizori pari. Dacă un singur rezultat nu are divizori pari, atunci acesta va fi scris
şi pe linia N  1 şi pe linia N  2.

Restricţii şi precizări

a 1 & N & 20
a a şi b sunt numere naturale nenule de maxim 18 cifre fiecare

Exemple
inventie.in inventie.out Explicaţii
8 210 Prin operaţia ”smile” se obţin, ı̂n ordine, valorile 210, 711,
64 711 313, 113, 12, 416, 14571543, 46.
92 313 Dintre acestea nu au divizori pari numerele 711, 313, 113,
85 113 14571543, cel mai mic fiind 113 şi cel mai mare 14571543.
76 12
66 416
6 10 14571543
43 1500 46
23 23 113
14571543
2 26 Prin operaţia ”smile” se obţin, ı̂n ordine, valorile 26,
13 13 9761512 9761512, ambele numere având divizori pari.
268 1244 0

Timp maxim de executare/test: 0.5 secunde


Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 10 KB
CAPITOLUL 23. ONI 2015 23.2. INVENTIE 286

23.2.1 Indicaţii de rezolvare


Rezultatul ”invenţiei” se obţine prin concatenarea valorilor ¶a  b¶ si a  b.
Un caz special este cazul a b, cand rezultatul este a  b.
Numerele care au 0 divizori pari sunt numerele impare, prin urmare pentru a doua cerinţă ne
interesează doar perechile a, b ı̂n care a  b este număr par, adică perechile a, b ı̂n care a şi b
au parităţi diferite.
Se determină minimul şi maximul dintre rezultatele obţinute din perechile a, b cu a şi b având
parităţi diferite.
Numerele a şi b având maxim 18 cifre, rezultatul invenţiei poate fi un număr mare, deci trebuie
efectuate comparaţii ı̂ntre numere mari.

23.2.2 Cod sursă

Listing 23.2.1: inventie 1.cpp


#include<fstream>
#include<algorithm>

using namespace std;

int main()
{
int gasit=0,n,v[60],vmin[60],vmax[60],maimic,maimare,i,k;

unsigned long long s,dif,a,b;

ifstream f("inventie.in");
ofstream g("inventie.out");

f>>n;

for (i=1; i<=n; i++)


{
f>>a>>b;
if (a==b) g<<a+b<<’\n’;
else
{
if (a>b) dif=a-b;
else dif=b-a;
g<<dif<<a+b<<’\n’;
}

if (a%2!=b%2)
{
k=0; // numarul cifrelor
gasit=1;
s=a+b;
while (s)
{
k++;
vmin[k]=vmax[k]=s%10;
s=s/10;
}
while (dif)
{
k++;
vmin[k]=vmax[k]=dif%10;
dif=dif/10;
}
vmin[0]=vmax[0]=k;
break;
}
}

i++;
while (i<=n)
{
f>>a>>b; //g<<" am citit "<<a<<’ ’<<b<<"la pasul "<<i<<’\n’;
if (a==b) g<<a+b<<’\n’;
else
CAPITOLUL 23. ONI 2015 23.2. INVENTIE 287

{
if (a>b) dif=a-b;
else dif=b-a;
g<<dif<<a+b<<’\n’;
}

if (a%2!=b%2)
{
k=0; // numarul cifrelor
s=a+b;
while (s)
{
k++;
v[k]=s%10;
s=s/10;
}
while (dif)
{
k++;
v[k]=dif%10;
dif=dif/10;
}

v[0]=k;
// verific daca noul rezultat este mai mic decat vmin,
// sau mai mare decat vmax
if (v[0]<vmin[0])
for (int j=0; j<=v[0]; j++) vmin[j]=v[j];
else if (v[0]>vmax[0])
for (int j=0; j<=v[0]; j++) vmax[j]=v[j];
else
{
if (v[0]==vmin[0])
{
maimic=1;// pres ca v<vmin
for (int j=v[0]; j>=1; j--)
if (v[j]>vmin[j])
{
maimic=0;
break;
}
else if (v[j]<vmin[j]) break;
if (maimic){
for (int j=0; j<=v[0]; j++) vmin[j]=v[j];
}
}

if (v[0]==vmax[0])
{
maimare=1; // pres ca v>vmax
for (int j=v[0]; j>=1; j--)
if (v[j]<vmax[j])
{
maimare=0;
break;
}
else if (v[j]>vmax[j]) break;
if (maimare)
for (int j=0; j<=v[0]; j++) vmax[j]=v[j];
}
}
}
i++;
}

if (gasit==0) g<<0<<’\n’;
else
{
for (int j=vmin[0]; j>=1; j--) g<<vmin[j];
g<<’\n’;
for (int j=vmax[0]; j>=1; j--) g<<vmax[j];
g<<’\n’;
}
return 0;
}
CAPITOLUL 23. ONI 2015 23.2. INVENTIE 288

Listing 23.2.2: inventie 2cpp


#include <fstream>
#include <cstring>

using namespace std;

ifstream fin("inventie.in");
ofstream fout("inventie.out");

unsigned ct,ad[40],i,k,maxx[40],minn[40];
int j;

void aduna(unsigned long long a, unsigned long long b)


{
i=0;
ct=0;
while(a||b)
{
ad[++i]=(a%10+b%10+ct)%10;
ct=(a%10+b%10+ct)/10;
a/=10;
b/=10;
}
if(ct) ad[++i]=ct;
ad[0]=i;
}

int comp(unsigned x[],unsigned y[])


{
if(x[0]<y[0]) return -1;
else
if(x[0]>y[0]) return 1;
else
{
for(j=x[0];j>=1;j--)
if(x[j]<y[j]) return -1;
else if (x[j]>y[j])return 1;
return 0;
}
}

int main()
{
unsigned n,ok=0;
unsigned long long a,b,z;

maxx[0]=0;
minn[0]=39;
for(j=1;j<=39;j++) minn[j]=9;
fin>>n;
for(k=1;k<=n;k++)
{
memset(ad,0,sizeof(ad));
fin>>a>>b;
aduna(a,b);

if(a==b);
else
if(a>b) fout<<a-b;
else fout<<b-a;

for(j=ad[0];j>=1;j--) fout<<ad[j];
fout<<’\n’;

if(a%2!=b%2)
{
ok=1;
z = a>b ? a-b : b-a;
j=ad[0];

while(z)
{
ad[++j]=z%10;
z/=10;
}
CAPITOLUL 23. ONI 2015 23.2. INVENTIE 289

ad[0]=j;
if(comp(ad,minn)<0)
{
for(j=ad[0];j>=0;j--) minn[j]=ad[j];
}
if(comp(ad,maxx)>0)
for(j=ad[0];j>=0;j--){ maxx[j]=ad[j]; }
}
}

if(ok)
{
for(k=minn[0];k>=1;k--) fout<<minn[k];
fout<<’\n’;

for(k=maxx[0];k>=1;k--)fout<<maxx[k];
fout<<’\n’;
}
else fout<<0<<’\n’;

return 0;
}

Listing 23.2.3: inventie 3.cpp


#include <cstdio>
#include <cassert>

using namespace std;

unsigned long long x, y, Y, X;

int Min[55], Max[55], m, b[55], i, N;

int main()
{
freopen("inventie.in", "r",stdin);
freopen("inventie.out","w",stdout);

scanf("%d\n",&N);

for(int i= 1; i<=50; i++) Min[i]=9;

Min[0]=50;
for(int i= 1; i<=N; i++)
{
scanf("%lld %lld\n",&x, &y);

X=(x<y ? y-x: x-y);

Y= x + y;
if(x!=y) printf("%llu",X);
printf("%llu\n",Y);

if(x%2!=y%2)
{
m=0;
while(Y)
{
b[++m]=Y%10;
Y/=10;
}

while(X)
{
b[++m]=X%10;
X/=10;
}

b[0]=m;
if(b[0] > Max[0])
for(int i=0; i<=b[0]; i++) Max[i]=b[i];

if(b[0] < Min[0])


CAPITOLUL 23. ONI 2015 23.2. INVENTIE 290

for(int i=0; i<=b[0]; i++) Min[i]=b[i];

if(b[0]==Max[0])
{
for(int i=b[0]; i>=1 && b[i]==Max[i]; i--);

if(i>0 && b[i]>Max[i])


for(int i=0; i<=b[0]; i++) Max[i]=b[i];
}

if(b[0]==Min[0])
{
for(int i=b[0]; i>=1 && b[i]==Min[i]; i--);
if(i>0 && b[i]<Min[i])
for(int i=0; i<=b[0]; i++) Min[i]=b[i];
}
}
}

if(Min[0]==50 && Max[0]==0) printf("0\n");


else
{
for(int i=Min[0]; i>=1 ; i--) printf("%d", Min[i]);
printf("\n");
for(int i=Max[0]; i>=1 ; i--) printf("%d", Max[i]);
}

return 0;

Listing 23.2.4: inventie 4 20p.cpp


#include<fstream>

using namespace std;

int main()
{
int n,i,gasit=0;
unsigned int s,dif,a,b,vmin,vmax,p,nr;

ifstream f("inventie.in");
ofstream g("inventie.out");

f>>n;
for (i=1; i<=n; i++)
{
f>>a>>b;
if (a==b) nr=a+b;
else
{
if (a>b) dif=a-b;
else dif=b-a;
s=a+b;
p=1;
while (s)
{
s=s/10;
p=p*10;
}
nr=dif*p+a+b;
}
g<<nr<<’\n’;
if (a%2!=b%2)
{
gasit=1;
vmin=vmax=nr;
break;
}
}
i++;
while (i<=n)
{
f>>a>>b; //g<<" am citit "<<a<<’ ’<<b<<"la pasul "<<i<<’\n’;
CAPITOLUL 23. ONI 2015 23.2. INVENTIE 291

if (a==b) nr=a+b;
else
{
if (a>b) dif=a-b;
else dif=b-a;
s=a+b;
p=1;
while (s)
{
s=s/10;
p=p*10;
}
nr=dif*p+a+b;
}
g<<nr<<’\n’;
if (a%2!=b%2)
{
if (vmin>nr) vmin=nr;
if (vmax<nr) vmax=nr;
}
i++;
}
if (gasit==0) g<<0<<’\n’;
else
g<<vmin<<’\n’<<vmax<<’\n’;
return 0;
}

Listing 23.2.5: inventie 5 45p.cpp


#include<fstream>

using namespace std;

int main()
{
int n,i,gasit=0;
unsigned long long s,dif,a,b,vmin,vmax,p,nr;

ifstream f("inventie.in");
ofstream g("inventie.out");

f>>n;
for (i=1; i<=n; i++)
{
f>>a>>b;
if (a==b) nr=a+b;
else
{
if (a>b) dif=a-b;
else dif=b-a;
s=a+b;
p=1;
while (s)
{
s=s/10;
p=p*10;
}
nr=dif*p+a+b;
}
g<<nr<<’\n’;
if (a%2!=b%2)
{
gasit=1;
vmin=vmax=nr;
break;
}
}
i++;
while (i<=n)
{
f>>a>>b; //g<<" am citit "<<a<<’ ’<<b<<"la pasul "<<i<<’\n’;
if (a==b) nr=a+b;
else
{
CAPITOLUL 23. ONI 2015 23.2. INVENTIE 292

if (a>b) dif=a-b;
else dif=b-a;
s=a+b;
p=1;
while (s)
{
s=s/10;
p=p*10;
}
nr=dif*p+a+b;
}
g<<nr<<’\n’;
if (a%2!=b%2)
{
if (vmin>nr) vmin=nr;
if (vmax<nr) vmax=nr;
}

i++;
}
if (gasit==0) g<<0<<’\n’;
else
g<<vmin<<’\n’<<vmax<<’\n’;
return 0;
}

Listing 23.2.6: inventie 6.cpp


#include <fstream>
#include <math.h>

using namespace std;

ifstream f("inventie.in");
ofstream g("inventie.out");

unsigned long long a,b,c,d;


int N,nrmin[40],nrmax[40];

int compar(int v1[],int v2[])


{
int i;
if(v1[0]>v2[0]) return 1;
if(v1[0]<v2[0]) return 2;
for(i=1;i<=v1[0];i++)
if(v1[i]!=v2[i])break;
if(i>v1[0])return 0;
if(v1[i]>v2[i])return 1;
else return 2;
}

void copie(int v1[], int v2[])


{
for(int i=0;i<=v2[0];i++) v1[i]=v2[i];
}

int main()
{
f>>N;
nrmin[0]=40;
int i;
for(i=1;i<=N;i++)
{
f>>a>>b;
if(a>=b)c=a-b;
else c=b-a;
d=a+b;
if(c!=0)g<<c;
g<<d;
g<<’\n’;
if(a%2!=b%2)
{
int v[40]={0};

//adaug c in vector
CAPITOLUL 23. ONI 2015 23.2. INVENTIE 293

if(c!=0)
{
int nrc=0;
unsigned long long c1=c;
while(c1>0){nrc++;c1/=10;}
v[0]=nrc;
for(int ii=nrc;ii>=1;ii--)
{
v[ii]=c%10;
c/=10;
}
}

//completez cu d=a+b
int nrc=0;
unsigned long long d1=d;
while(d1>0){nrc++;d1/=10;}
v[0]+=nrc;
for(int ii=v[0];d>0;ii--){v[ii]=d%10;d/=10;}
if(compar(v,nrmin)==2)copie(nrmin,v);
if(compar(v,nrmax)==1)copie(nrmax,v);
}
}

if(nrmax[0]!=0)
{
int i;
for(i=1;i<=nrmin[0];i++)g<<nrmin[i];
g<<’\n’;
for(i=1;i<=nrmax[0];i++)g<<nrmax[i];
g<<’\n’;
}
else g<<0<<’\n’;

f.close();
g.close();
return 0;
}

Listing 23.2.7: inventie 7.cpp


#include <fstream>
#include <string.h>

using namespace std;

ifstream f("inventie.in");
ofstream g("inventie.out");

unsigned long long a,b,c,d;


int N;

char nrmin[40]="999999999999999999999999999999999999999",nrmax[40],v[40];

int main()
{
f>>N;
int i;
for(i=1;i<=N;i++)
{
f>>a>>b;

if(a>=b)c=a-b;
else c=b-a;

d=a+b;
if(c!=0)g<<c;
g<<d;
g<<’\n’;

if(a%2!=b%2)
{
//pun d in v oglindit
int nrc=0;
while(d>0){v[nrc++]=’0’+d%10;d/=10;}
CAPITOLUL 23. ONI 2015 23.2. INVENTIE 294

//pun c in v oglindit
if(c!=0)
{
while(c>0){v[nrc++]=’0’+c%10;c/=10;}
}

v[nrc]=0;
for(int j=0;j<strlen(v)/2;j++)
{
char aux=v[j];
v[j]=v[strlen(v)-j-1];
v[strlen(v)-j-1]=aux;
}

if(strlen(v)<strlen(nrmin)) strcpy(nrmin,v);
else
if(strlen(v)==strlen(nrmin) && strcmp(v,nrmin)<0)strcpy(nrmin,v);

if(strlen(v)>strlen(nrmax))strcpy(nrmax,v);
else
if(strlen(v)==strlen(nrmax) && strcmp(v,nrmax)>0)strcpy(nrmax,v);
}
}

if(nrmax[0]!=0) g<<nrmin<<’\n’<<nrmax<<’\n’;
else g<<0<<’\n’;

f.close();
g.close();
return 0;
}

Listing 23.2.8: inventie 8 35p.cpp


#include<fstream>

using namespace std;

int main()
{
int n,i,gasit=0;
long long s,dif,a,b,vmin,vmax,p,nr;

ifstream f("inventie.in");
ofstream g("inventie.out");

f>>n;
for (i=1; i<=n; i++)
{
f>>a>>b;
if (a==b) nr=a+b;
else
{
if (a>b) dif=a-b;
else dif=b-a;
s=a+b;
p=1;
while (s)
{
s=s/10;
p=p*10;
}
nr=dif*p+a+b;
}
g<<nr<<’\n’;
if (a%2!=b%2)
{
gasit=1;
vmin=vmax=nr;
break;
}
}
i++;
while (i<=n)
CAPITOLUL 23. ONI 2015 23.3. MESAJ 295

{
f>>a>>b; //g<<" am citit "<<a<<’ ’<<b<<"la pasul "<<i<<’\n’;
if (a==b) nr=a+b;
else
{
if (a>b) dif=a-b;
else dif=b-a;
s=a+b;
p=1;
while (s)
{
s=s/10;
p=p*10;
}
nr=dif*p+a+b;
}
g<<nr<<’\n’;
if (a%2!=b%2)
{
if (vmin>nr) vmin=nr;
if (vmax<nr) vmax=nr;
}

i++;
}
if (gasit==0) g<<0<<’\n’;
else
g<<vmin<<’\n’<<vmax<<’\n’;
return 0;
}

23.2.3 *Rezolvare detaliată

23.3 mesaj
Problema 3 - mesaj 100 de puncte
În ţara lui Piticot cuvintele au doar două litere, prima fiind o majusculă (literă mare) iar a
doua o minusculă (literă mică). Piticii Mi şi Gi se distrează şi ı̂şi trimit mesaje ascunzând cuvintele
ı̂n cadrul unor secvenţe transmise sub forma unor şiruri de litere.
Piticul Mi scrie şi trimite un mesaj piticului Gi respectând
următoarele reguli:
a un mesaj conţine una sau mai multe secvenţe;
a orice literă care apare ı̂n mesaj, de cel puţin două ori, pe poziţii
alăturate, este numită terminator;
a o secvenţă se ı̂ncheie când s-a ı̂ntâlnit o succesiune de litere ter-
minator;
a cuvântul este format din prima majusculă şi ultima minusculă din
secvenţă, fără a lua ı̂n seamă litera terminator a secvenţei; Figura 23.1: mesaj
a o secvenţă ascunde un cuvânt dacă terminatorul său se repetă de exact două ori şi dacă
conţine cel puţin o literă mare şi o literă mică, ignorând terminatorul de secvenţă;
a costul unui cuvânt este egal cu numărul total de apariţii al celor două litere din care este
format, ı̂n cadrul secvenţei ı̂n care a fost ascuns, luând ı̂n considerare inclusiv literele terminator.
De exemplu secvenţa s f u E e t R u E E ascunde un cuvânt deoarece conţine şi majuscule
şi minuscule, iar litera terminator de secvenţă, E, se repetă de exact două ori. Secvenţa ascunde
cuvântul Eu, iar costul cuvântului este 5 (3 litere E + 2 două litere u).
La primirea mesajului, piticul Gi determină, pentru fiecare majusculă, costul maxim al cuvin-
telor care ı̂ncep cu aceasta.

Cerinţe

Scrieţi un program care determină:


1) numărul de secvenţe trimise care nu ascund cuvinte;
2) cuvintele din mesaj, ı̂n ordinea ı̂n care au fost trimise de piticul Mi;
3) pentru fiecare majusculă, câte cuvinte care ı̂ncep cu ea au costul maxim determinat de Gi.
CAPITOLUL 23. ONI 2015 23.3. MESAJ 296

Date de intrare

Fişierul de intrare mesaj.in conţine pe prima linie un număr natural P . Pentru toate testele
de intrare, numărul P poate avea numai una dintre valorile 1, 2 sau 3.
Pe a doua linie a fişierului de intrare se găseşte numărul natural N reprezentând numărul de
litere folosite de Mi pentru scrierea mesajului.
Pe a treia linie se găsesc N litere mari şi mici ale alfabetului englez, separate prin câte un
spaţiu, reprezentând literele mesajului, ı̂n ordinea ı̂n care au fost trimise.

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 mesaj.out va conţine pe prima linie un număr natural reprezentând răspunsul la cerinţa
1).
Dacă valoarea lui P este 2, se va rezolva numai punctul 2) din cerinţe. În acest caz, fişierul de
ieşire mesaj.out va conţine cuvintele din mesaj, fiecare cuvânt scris pe câte o linie, ı̂n ordinea ı̂n
care au fost trimise.
Dacă valoarea lui P este 3, se va rezolva numai punctul 3) din cerinţe. În acest caz, fişierul de
ieşire mesaj.out va conţine pe fiecare linie câte o majusculă urmată de un număr natural nenul,
separate printr-un spaţiu. Majusculele vor fi afişate ı̂n ordine de la A la Z, ı̂nsă doar cele pentru
care au existat ı̂n mesaj cuvinte care au ı̂nceput cu ele.

Restricţii şi precizări

a 1 & N & 2000000


a litera terminator a unei secvenţe poate fi ori minusculă ori majusculă;
a ultimele litere din fişier sunt literele terminator ale ultimei secvenţe din mesajul trimis;
a se garantează că ı̂n şirul de litere din fişierul de intrare se află ascuns cel puţin un cuvânt;
a majusculele alfabetului englez sunt A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
T, U, V, W, X, Y, Z;
a pentru 50% din teste N & 1000000
a Pentru rezolvarea cerinţei 1) se acordă 20 de puncte, pentru rezolvarea cerinţei 2) se acordă
40 de puncte, iar pentru rezolvarea cerinţei 3) se acordă 40 de puncte.

Exemple:
mesaj.in mesaj.out
1 4
34
wwwweDorFDorrtRneReyyjjiMoeitttjww
Explicaţie:
Textul conţine şase secvenţe: Sunt 4 secvenţe care nu ascund cuvinte:
1) w w w w a prima secvenţă şi a patra deoarece conţin numai
2) e D o r F D o r r terminatorul;
3) t R n e R e y y a secvenţa a cincea nu se decodifică deoarece termi-
4) j j natorul se repetă de mai mult de două ori;
5) i M o e i t t t a secvenţa a şasea nu conţine majuscule.
6) j w w

mesaj.in mesaj.out
2 Nu
34 Do
uNaaeDorFDorrtRneReyyjjiMoeitttjww Re
Explicaţie:
Textul conţine şase secvenţe: Prima secvenţă are terminatorul a care se repetă de
1) u N a a două ori şi ascunde cuvântul Nu
2) e D o r F D o r r A doua secvenţă are terminatorul r şi ascunde
3) t R n e R e y y cuvântul Do.
4) j j A treia are terminatorul y şi ascunde cuvântul Re.
5) i M o e i t t t Ultimele trei secvenţe nu ascund cuvinte.
6) j w w
CAPITOLUL 23. ONI 2015 23.3. MESAJ 297

mesaj.in mesaj.out
3 A2
24 B1
AattBbBtteAeannBwIIFieFF F1
Explicaţie:
Textul conţine cinci secvenţe: Cuvintele transmise ı̂n mesaj sunt
1) A a t t Aa (cost 2)
2) B b B t t Bb (cost 3)
3) e A e a n n Aa (cost 2)
4) B w I I Bw (cost 2)
5) F i e F F Fe (cost 4)
Costul maxim al cuvintelor care ı̂ncep cu A este 2 şi
au fost 2 cuvinte transmise.
Pentru litera B s-a transmis un singur cuvânt de cost
maxim 3.
Pentru litera F s-a transmis un singur cuvânt de cost
maxim 4.

Timp maxim de executare/test: 1.5 secunde


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

23.3.1 Indicaţii de rezolvare


Problema poate fi rezolvată citind caracter cu caracter şi memorând doar ultimele două litere
citite.
Pe parcursul citiri se reţine numărul apariţiilor consecutive al unui caracter. ı̂n funcţie de
acesta se identifică fiecare secvenţă. ı̂n cadrul secvenţei curente se actualizează:
a cele două litere ale posibilului cuvânt ascuns ı̂n secvenţă curentă,
a numărul de apariţii al fiecărei minuscule ale alfabetului englez (se foloseşte un vector de
frecvenţă)
a numărul de apariţii al primei majuscule ı̂ntâlnite ı̂n cadrul secvenţei curente

La finalul unei secvenţe se actualizează dacă este cazul, costul maxim al unui cuvânt care
ı̂ncepe cu majuscula din cuvântului determinat la pasul curent.
Dacă se optează pentru preluarea literelor ı̂ntr-un vector de 1 milion de caractere, se vor obţine
50 de puncte.

23.3.2 Cod sursă

Listing 23.3.1: mesaj 1.c


1 #include <stdio.h>
2 #include <ctype.h>
3
4 int l=1, nr=0, nLw=0, N,fL[27],fC[27], nM, Cost, CostMax[27],P, Nrsecv, i;
5 char c, x , y, z, first, last, s;
6
7 int main()
8 {
9 freopen("mesaj.in", "r",stdin);
10 freopen("mesaj.out","w",stdout);
11
12 scanf("%d\n",&P);
13 scanf("%d\n%c%c",&N, &x, &s);
14
15 if(islower(x)) fL[x-’a’]++;
16
17 l=1;
18 first=last=’#’;
19 while(s!=’\n’)
20 {
21 scanf("%c%c", &y, &s);
CAPITOLUL 23. ONI 2015 23.3. MESAJ 298

22 if(islower(y)) fL[y-’a’]++;
23
24 while (x!=y && s!=’\n’)
25 {
26 if(islower(x)) last=x;
27 else
28 if(first==’#’) {first=x; nM=1;}
29 else
30 if(first==x) nM++;
31
32 x=y;
33 scanf("%c%c", &y, &s);
34 if(islower(y)) fL[y-’a’]++;
35 if(s==’\n’) break;
36 }
37
38 if (x==y) l=2;
39 while (x==y && s!=’\n’)
40 {
41 scanf("%c%c", &y, &s);
42 if(islower(y)) fL[y-’a’]++;
43 if(x==y) l++;
44 if(s==’\n’) break;
45 }
46
47 if(first==x) nM+=l;
48 if(l==2 && first!=’#’ && last!=’#’)
49 {
50 if(P==2) printf("%c%c\n",first,last);
51 Cost=nM + fL[last-’a’];
52 if(last==y)Cost--;
53 if(Cost==CostMax[first-’A’]) fC[first-’A’]++;
54 if(Cost>CostMax[first-’A’])
55 {
56 fC[first-’A’]=1;
57 CostMax[first-’A’]=Cost;
58 }
59 }
60 else Nrsecv++;
61
62 x=y;
63 l=1;
64 first=last=’#’;
65 nM=0;
66 for(i=0;i<27;i++) fL[i]=0;
67 Cost=0;
68 if(islower(x)) fL[x-’a’]++;
69 }
70
71 if(P==1)printf("%d\n", Nrsecv);
72 if(P==3)
73 for(i=0;i<26;i++)
74 if(fC[i]) printf("%c %d\n", (char)(’A’+i), fC[i]);
75
76 return 0;
77 }

Listing 23.3.2: mesaj 2.cpp


#include <cstdio>
#include <cctype>
#include <cassert>

using namespace std;

int l=1, nr=0, nLw=0, N,fL[27],fC[27], nM, Cost, CostMax[27],P, Nrsecv, i;


char c, x , y, z, first, last, s;

int main()
{
freopen("mesaj.in", "r",stdin);
freopen("mesaj.out","w",stdout);

scanf("%d\n",&P);
scanf("%d\n%c%c",&N, &x, &s);
CAPITOLUL 23. ONI 2015 23.3. MESAJ 299

if(islower(x)) fL[x-’a’]++;
l=1;
first=last=’#’;
while(s!=’\n’)
{
scanf("%c%c", &y, &s);
if(islower(y)) fL[y-’a’]++;
while (x!=y && s!=’\n’)
{
if(islower(x)) last=x;
else
if(first==’#’) {first=x; nM=1;}
else if(first==x) nM++;
x=y;
scanf("%c%c", &y, &s);
if(islower(y)) fL[y-’a’]++;
if(s==’\n’) break;
}

if (x==y) l=2;
while (x==y && s!=’\n’)
{
scanf("%c%c", &y, &s);
if(islower(y)) fL[y-’a’]++;
if(x==y) l++;
if(s==’\n’) break;
}

if(first==x) nM+=l;
if(l==2 && first!=’#’ && last!=’#’)
{
if(P==2) printf("%c%c\n",first,last);
Cost=nM + fL[last-’a’];
if(last==y)Cost--;
if(Cost==CostMax[first-’A’]) fC[first-’A’]++;
if(Cost>CostMax[first-’A’])
{
fC[first-’A’]=1;
CostMax[first-’A’]=Cost;
}
}
else Nrsecv++;

x=y;
l=1;
first=last=’#’;
nM=0;
for(int i=0;i<27;i++)fL[i]=0;
Cost=0;
if(islower(x)) fL[x-’a’]++;
}

if(P==1)printf("%d\n", Nrsecv);
if(P==3)
for(i=0;i<26;i++)
if(fC[i]) printf("%c %d\n", (char)(’A’+i), fC[i]);

return 0;
}

Listing 23.3.3: mesaj 3.cpp


#include <fstream>
#include <cctype>

using namespace std;

ifstream in("mesaj.in");
ofstream out("mesaj.out");

int majCounts[256];
int minCounts[256];
int maxCost[256];
int maxCostCounts[256];
CAPITOLUL 23. ONI 2015 23.3. MESAJ 300

int main()
{
int P;
in >> P;

int N;
in >> N;

int numSecvente = 0;
int numSecventeCuCuvinte = 0;

char ch = ’#’;
int countCh = 1;

char majCh = ’#’;


char minCh = ’#’;

for (int i = 0; i <= N; ++ i)


{
char peekCh;
if (i < N)
{
in >> peekCh;
}
else
{
peekCh = ’#’;
}

if (ch == peekCh)
{
countCh ++;
}
else
{
switch (countCh)
{
case 1:
switch (P)
{
case 1:
if (isupper(ch) && majCh == ’#’) majCh = ch;
if (islower(ch)) minCh = ch;
break;
case 2:
if (isupper(ch) && majCh == ’#’) majCh = ch;
if (islower(ch)) minCh = ch;
break;
case 3:
if (isupper(ch) && majCh == ’#’) majCh = ch;
if (islower(ch)) minCh = ch;

if (isupper(ch)) majCounts[ch] ++;


if (islower(ch)) minCounts[ch] ++;
break;
}
break;

case 2:
switch(P)
{
case 1:
numSecvente ++;
if (majCh != ’#’ && minCh != ’#’)
numSecventeCuCuvinte ++;

majCh = minCh = ’#’;


break;
case 2:
if (majCh != ’#’ && minCh != ’#’)
{
out << majCh << minCh << ’\n’;
}

majCh = minCh = ’#’;


CAPITOLUL 23. ONI 2015 23.3. MESAJ 301

break;
case 3:
if (isupper(ch)) majCounts[ch] += 2;
if (islower(ch)) minCounts[ch] += 2;

if (majCh != ’#’ && minCh != ’#’)


{
int cost = majCounts[majCh]+minCounts[minCh];
if (cost > maxCost[majCh])
{
maxCost[majCh] = cost;
maxCostCounts[majCh] = 1;
}
else
if (cost == maxCost[majCh])
{
maxCostCounts[majCh] ++;
}
}

majCh = minCh = ’#’;


for(int ii=0; ii<256;ii++) majCounts[ii]=0;
for(int ii=0; ii<256;ii++) minCounts[ii]=0;
break;
}
break;

default:
switch (P)
{
case 1:
numSecvente ++;

majCh = minCh = ’#’;


break;
case 2:
majCh = minCh = ’#’;
break;
case 3:
majCh = minCh = ’#’;
for(int ii=0; ii<256;ii++) majCounts[ii]=0;
for(int ii=0; ii<256;ii++) minCounts[ii]=0;
break;
}
}

countCh = 1;
ch = peekCh;
}
}

switch(P)
{
case 1:
out << numSecvente - numSecventeCuCuvinte << ’\n’;
break;
case 3:
for (char ch = ’A’; ch != ’Z’; ++ ch)
{
if (maxCost[ch])
{
out << ch << ’ ’ << maxCostCounts[ch] << ’\n’;
}
}
break;
}

return 0;
}

Listing 23.3.4: mesaj 4.cpp


#include<fstream>
#include<iostream>
CAPITOLUL 23. ONI 2015 23.3. MESAJ 302

using namespace std;

char pr[500000];
char ul[500000];

int main()
{
ifstream f("mesaj.in");
ofstream g("mesaj.out");

int n,t=0,nrlitmici=0, nrlitmari=0,i=1,nr=0,kp=0,ns=0,j,p;


char c,u,prima, ultima;

int nrmari[28]= {0};


int nrmici[28]= {0};
int costmax [28]= {0};
int cate[28]= {0};

f>>p>>n;
f>>c;
while (i<=n-1)
{
for (j=0; j<=27; j++) nrmici[j]=nrmari[j]=0;
u=c;
if (u>=’a’ && u<=’z’) nrmici[u-’a’]++;
else nrmari[u-’A’]++;
f>>c;
i++;
while (c!=u&&i<=n)
{
if (c>=’a’ && c<=’z’) nrmici[c-’a’]++;
else nrmari[c-’A’]++;

if (u>=’a’&&u<=’z’)
{
nrlitmici++;
ultima=u;
}
else
{
nrlitmari++;
if (nrlitmari==1) prima=u;
}

if (i==n)
{
i++;
break;
}
u=c;
f>>c;
i++;
}

while (c==u&&i<=n)
{
if (c>=’a’ && c<=’z’) nrmici[c-’a’]++;
else nrmari[c-’A’]++;

nr++;
if (i==n)
{
i++;
break;
}
f>>c;
i++;
}

if (nr==1 && nrlitmici>0 && nrlitmari>0)


{
pr[kp]=prima;
ul[kp]=ultima;
kp++;
if (costmax[prima-’A’]<nrmari[prima-’A’]+nrmici[ultima-’a’])
{
CAPITOLUL 23. ONI 2015 23.3. MESAJ 303

costmax[prima-’A’]=nrmari[prima-’A’]+nrmici[ultima-’a’];
cate[prima-’A’]=1;
}
else
if (costmax[prima-’A’]==nrmari[prima-’A’]+nrmici[ultima-’a’])
cate[prima-’A’]++;
}
else { ns++;}

nr=0;
nrlitmici=0;
nrlitmari=0;
}

if (p==2)
for(i=0; i<kp; i++) g<<pr[i]<<ul[i]<<’\n’;
else
if (p==1)
g<<ns<<’\n’;
else
for (c=’A’; c<=’Z’; c++)
if (costmax[c-’A’]>0) g<<c<<’ ’<<cate[c-’A’]<<’\n’;

return 0;
}

Listing 23.3.5: mesaj 5.cpp


#include <iostream>
#include <fstream>

using namespace std;

ifstream in("mesaj.in");
ofstream out("mesaj.out");

char prim[100000],ultim[100000];
int lmici[28],lmari[28],cost[28]={0};

int main()
{
char x,y;
int i,j,P,N,nrsv=0,sw=1,nrt=0,nrs=0,cost=0,cost_max[28]={0},nrc[28]={0};
char prima_M=’*’,ultima_m=’*’;

in>>P;
in>>N;
in>>x;
i=1;

while(i<=N)
{
for(j=0;j<=28;j++)
lmari[j]=lmici[j]=0;

if(’a’<=x && x<=’z’)


lmici[x-’a’]++;
else
lmari[x-’A’]++;

in>>y;
i++;
while(x!=y && i<=N)
{
if(’a’<=x && x<=’z’)
ultima_m=x;
else
if(sw)
prima_M=x,sw=0;

if(’a’<=y && y<=’z’)


lmici[y-’a’]++;
else
lmari[y-’A’]++;
CAPITOLUL 23. ONI 2015 23.3. MESAJ 304

x=y;
in>>y; i++;
}

nrt=1;
while(x==y && i<=N)
{
nrt++;
if(’a’<=y && y<=’z’)
lmici[y-’a’]++;
else
lmari[x-’A’]++;
x=y;
in>>y;
i++;
}

if(P==2 && nrt==2 && prima_M!=’*’ && ultima_m!=’*’)


out<<prima_M<<ultima_m<<’\n’;
if(nrt>=2)
{
if(nrt==2 && (prima_M==’*’ || ultima_m==’*’))
nrsv++;
if(nrt==2 && (prima_M!=’*’ || ultima_m!=’*’))
{
cost=lmari[prima_M-’A’]+lmici[ultima_m-’a’];
if(cost>cost_max[prima_M-’A’])
cost_max[prima_M-’A’]=cost, nrc[prima_M-’A’]=1;
else
if(cost==cost_max[prima_M-’A’])
nrc[prima_M-’A’]++;
}
if(nrt>2)
nrsv++;
nrt=0;
sw=1;
prima_M=ultima_m=’*’;
}
x=y;
}

if(P==1 && i>N)


out<<nrsv;
else
if(P==3)
for(j=0;j<=27;j++)
if(cost_max[j]!=0)
out<<(char)(’A’+j)<<’ ’<<nrc[j]<<’\n’;

in.close();
out.close();
return 0;
}

Listing 23.3.6: mesaj 6.cpp


#include <fstream>
#include <cstring>
#include <cctype>

using namespace std;

ifstream in("mesaj.in");
ofstream out("mesaj.out");

int majCounts[256];
int minCounts[256];
int maxCost[256];
int maxCostCounts[256];

int main()
{
int P;
in >> P;
CAPITOLUL 23. ONI 2015 23.3. MESAJ 305

int N;
in >> N;

int numSecvente = 0;
int numSecventeCuCuvinte = 0;

char ch = ’#’;
int countCh = 1;

char majCh = ’#’;


char minCh = ’#’;

for (int i = 0; i <= N; ++ i)


{
char peekCh;
if (i < N)
{
in >> peekCh;
}
else
{
peekCh = ’#’;
}

if (ch == peekCh)
{
countCh ++;
}
else
{
switch (countCh)
{
case 1:
switch (P)
{
case 1:
if (isupper(ch) && majCh == ’#’) majCh = ch;
if (islower(ch)) minCh = ch;
break;
case 2:
if (isupper(ch) && majCh == ’#’) majCh = ch;
if (islower(ch)) minCh = ch;
break;
case 3:
if (isupper(ch) && majCh == ’#’) majCh = ch;
if (islower(ch)) minCh = ch;

if (isupper(ch)) majCounts[ch] ++;


if (islower(ch)) minCounts[ch] ++;
break;
}
break;

case 2:
switch(P)
{
case 1:
numSecvente ++;
if (majCh != ’#’ && minCh != ’#’)
numSecventeCuCuvinte ++;

majCh = minCh = ’#’;


break;
case 2:
if (majCh != ’#’ && minCh != ’#’)
{
out << majCh << minCh << ’\n’;
}

majCh = minCh = ’#’;


break;
case 3:
if (isupper(ch)) majCounts[ch] += 2;
if (islower(ch)) minCounts[ch] += 2;

if (majCh != ’#’ && minCh != ’#’)


CAPITOLUL 23. ONI 2015 23.3. MESAJ 306

{
int cost = majCounts[majCh]+minCounts[minCh];
if (cost > maxCost[majCh])
{
maxCost[majCh] = cost;
maxCostCounts[majCh] = 1;
}
else
if (cost == maxCost[majCh])
{
maxCostCounts[majCh] ++;
}
}

majCh = minCh = ’#’;


memset(majCounts, 0, sizeof(majCounts));
memset(minCounts, 0, sizeof(minCounts));
break;
}
break;

default:
switch (P)
{
case 1:
numSecvente ++;

majCh = minCh = ’#’;


break;
case 2:
majCh = minCh = ’#’;
break;
case 3:
majCh = minCh = ’#’;
memset(majCounts, 0, sizeof(majCounts));
memset(minCounts, 0, sizeof(minCounts));
break;
}
}

countCh = 1;
ch = peekCh;
}
}

switch(P)
{
case 1:
out << numSecvente - numSecventeCuCuvinte << ’\n’;
break;
case 3:
for (char ch = ’A’; ch != ’Z’; ++ ch)
{
if (maxCost[ch])
{
out << ch << ’ ’ << maxCostCounts[ch] << ’\n’;
}
}
break;
}

return 0;
}

Listing 23.3.7: mesaj 7.cpp


#include <fstream>

using namespace std;

ifstream f("mesaj.in");
ofstream g("mesaj.out");

char s[1000001],minu,maju;
int N,P,nr;//nr=nr de repetari ale unei litere
CAPITOLUL 23. ONI 2015 23.3. MESAJ 307

int nrs,nrsl;//nrs=nr secvente; nrsl=nr secvente ce contin cuvinte


int cost, cmax[26],nrap[26];

int main()
{
//citire
int i;
f>>P>>N;
for(i=1;i<=N;i++)f>>s[i];

//1)numarare secvente si secvente ce contin cuvinte


if(P==1)
{
maju=minu=’ ’;
if(s[1]>=’A’ && s[1]<=’Z’ && s[1]!=s[2] && maju==’ ’)maju=s[1];
else
if(s[1]>=’a’ && s[1]<=’z’ && s[1]!=s[2])minu=s[1];

for(i=2;i<=N;)
{
if(s[i]!=s[i-1])
{
if(s[i]>=’A’ && s[i]<=’Z’ && s[i]!=s[i+1] && maju==’ ’)
maju=s[i];
else
if(s[i]>=’a’ && s[i]<=’z’ && s[i]!=s[i+1])
minu=s[i];
i++;
}
else
{
//se termina o secventa
nrs++;
nr=0;
while(s[i]==s[i-1] && i<=N)
{
i++;
nr++;
}
if(maju!=’ ’ && minu!=’ ’ && nr==1)
nrsl++;
maju=minu=’ ’;
}
}
g<<nrs-nrsl<<’\n’;
}

//2)afisare cuvinte
if(P==2)
{
maju=minu=’ ’;
if(s[1]>=’A’ && s[1]<=’Z’ && s[1]!=s[2] && maju==’ ’)
maju=s[1];
else
if(s[1]>=’a’ && s[1]<=’z’ && s[1]!=s[2])
minu=s[1];

for(i=2;i<=N;)
{
if(s[i]!=s[i-1])
{
if(s[i]>=’A’ && s[i]<=’Z’ && s[i]!=s[i+1] && maju==’ ’)
maju=s[i];
else
if(s[i]>=’a’ && s[i]<=’z’ && s[i]!=s[i+1])
minu=s[i];
i++;
}
else
{
//se termina o secventa
nrs++;nr=0;while(s[i]==s[i-1] && i<=N){i++;nr++;}
if(maju!=’ ’ && minu!=’ ’ && nr==1)g<<maju<<minu<<’\n’;
maju=minu=’ ’;
}
}
CAPITOLUL 23. ONI 2015 23.3. MESAJ 308

//3)afisare cuvinte
if(P==3)
{
int j=1,k;
maju=minu=’ ’;
if(s[1]>=’A’ && s[1]<=’Z’ && s[1]!=s[2] && maju==’ ’)
maju=s[1];
else
if(s[1]>=’a’ && s[1]<=’z’ && s[1]!=s[2])
minu=s[1];

for(i=2;i<=N;)
{
if(s[i]!=s[i-1])
{
if(s[i]>=’A’ && s[i]<=’Z’ && s[i]!=s[i+1] && maju==’ ’)
maju=s[i];
else
if(s[i]>=’a’ && s[i]<=’z’ && s[i]!=s[i+1])
minu=s[i];
i++;
}
else
{
//se termina o secventa
nrs++;
cost=0;
nr=0;
while(s[i]==s[i-1] && i<=N){i++; nr++;}
if(maju!=’ ’ && minu!=’ ’ && nr==1)
{
for(k=j;k<=i-1;k++)
if(s[k]==maju)cost++;
else
if(s[k]==minu)cost++;

if(cost>cmax[maju-’A’])
{
cmax[maju-’A’]=cost;
nrap[maju-’A’]=1;
}
else
if(cost==cmax[maju-’A’])
{
nrap[maju-’A’]++;
}
}
maju=minu=’ ’;j=i;
}
}

for(i=0;i<26;i++)
if(cmax[i]>0) g<<(char)(i+’A’)<<’ ’<<nrap[i]<<’\n’;
}
f.close();g.close();return 0;
}

23.3.3 *Rezolvare detaliată


Capitolul 24

ONI 2014

24.1 2048
Problema 1 - 2048 100 de puncte
Ada şi Ben sunt pasionaţi de jocurile pe calculator şi tocmai au descoperit cea mai recentă
versiune a jocului 2048.
Regulile jocului sunt foarte simple:
a se porneşte de la un şir de N piese pe care sunt
ı̂nscrise numere din mulţimea { 2, 4, 8, 16, 32, 64, 128,
256, 512, 1024, 2048 };
a piesele sunt aşezate ı̂n locaţii numerotate consecu-
tiv cu numerele 1, 2, ..., N ;
a la fiecare pas, poate avea loc o MUTARE la
STÂNGA sau o MUTARE la DREAPTA;
a pentru fiecare joc este stabilit un număr maxim de
mutări M ;
a dacă are loc o MUTARE la DREAPTA, atunci:
- piesele pot fuziona la dreapta, ı̂ncepând cu penul-
tima piesă din şir: dacă o piesă se află pe o poziţie i şi
are ı̂nscrisă valoarea k, iar pe poziţia i  1 se află o piesă
cu aceeaşi valoare k, atunci aceste piese vor ”fuziona”, Figura 24.1: 2048
pe poziţia i  1 se va obţine o piesă cu valoarea 2k, iar pe poziţia i rămâne o locaţie liberă;
- după efectuarea fuzionărilor, piesele se aliniază la dreapta, astfel ı̂ncât ultima piesă să se afle
pe poziţia n;
a dacă are loc o MUTARE la STâNGA, atunci:
- piesele pot fuziona la stânga, ı̂ncepând cu a doua piesă din şir: dacă o piesă se află pe o
poziţie i şi are ı̂nscrisă valoarea k, iar pe poziţia i  1 se află o piesă cu aceeaşi valoare k, atunci
aceste piese vor ”fuziona”, pe poziţia i  1 se va obţine o piesă cu valoarea 2k, iar pe poziţia i
rămâne o locaţie liberă;
- după efectuarea fuzionărilor, piesele se aliniază la stânga, astfel ı̂ncât prima piesă să se afle
pe poziţia 1;
a jocul se ı̂ncheie atunci când se ajunge ı̂n una dintre următoarele situaţii:
- pe cel puţin una dintre piese se află ı̂nscrisă valoarea 2048;
- valorile ı̂nscrise nu se mai pot modifica prin mutarea pieselor;
- s-au efectuat toate cele M mutări.

Cerinţe

Scrieţi un program care să citească numerele naturale N (numărul iniţial de piese) şi M
(numărul maxim de mutări), un şir de N numere reprezentând, ı̂n ordine, numerele ı̂nscrise pe
cele N piese şi cel mult M caractere din mulţimea rS, Dx ce reprezintă mutările fixate de către
Ada şi Ben, şi care determină:

309
CAPITOLUL 24. ONI 2014 24.1. 2048 310

a) numărul X de mutări efectuate până la ı̂ncheierea jocului;


b) numărul maxim Y inscris pe una dintre piese la ı̂ncheierea jocului;
c) numărul maxim Z de fuzionări efectuate la o mutare.

Date de intrare

Fişierul de intrare 2048.in conţine pe prima linie, separate prin câte un spaţiu, numerele N
şi M . A doua linie a fişierului conţine cele N numere inscrise, ı̂n ordine, pe piese, separate prin
câte un spaţiu. A treia linie a fişierului conţine cele M caractere, separate prin câte un spaţiu, ce
reprezintă cele M direcţii de mutare.

Date de ieşire

Fişierul de ieşire 2048.out va conţine pe prima linie numărul X, pe a doua linie numărul Y
şi pe a treia linie numărul Z.

Restricţii şi precizări

- 2 & N, M & 10000;


- caracterul D indică o mutare la dreapta, iar caracterul S indică o mutare la stânga;
- pentru rezolvarea cerinţei a) se acordă 40% din punctaj, pentru cerinţa b) 40% din punctaj
şi pentru cerinţa c) 20% din punctaj.

Exemple
2048.in 2048.out Explicaţii
7 10 4 Succesiunea de mutări este reprezentată ı̂n figura 1.
16 4 4 2 2 4 8 32 Au fost efectuate 4 mutări până la ı̂ncheierea jocului, cea
DDSDSDSSDD 2 mai mare valoare inscrisă pe una dintre piese fiind 32.
Numărul maxim de fuzionări, două, a fost obţinut la prima
mutare.

Timp maxim de executare/test: 0.5 secunde


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

24.1.1 Indicaţii de rezolvare


Se memorează şirul de numere ı̂n tabloul unidimensional a de lungime n.
Se memorează ı̂n două variabile st şi dr poziţiile de ı̂nceput şi de sfârşit ale secvenţei de piese
rămase ı̂n tablou.
Se citeşte, pe rând, câte o mutare, se parcurge tabloul a ı̂n sensul mutării (de la st la dr sau
invers) şi se efectuează toate fuzionările posibile, contorizându-se numărul acestora.
La ı̂ncheierea jocului se determină valoarea maximă care se află ı̂n tablou ı̂n intervalul
ast, adr .

24.1.2 Cod sursă

Listing 24.1.1: 2048.cpp


//Cristina Sichim, C.N. Ferdinand I Bacau
#include <fstream>

using namespace std;

ifstream f("2048.in");
ofstream g("2048.out");

int v[10001],n,m,i,j,k,st,dr,p,X,Y,Z,z,s;
char d;

int main()
{
f>>n>>m;
for(i=1;i<=n;++i){f>>v[i]; if(v[i]==2048) s=1;}
CAPITOLUL 24. ONI 2014 24.1. 2048 311

st=1;dr=n;
for(i=1;i<=m && !s;i++)
{ f>>d;
z=0;
if(d==’D’)
{for(j=dr;j>st;j--)
if(v[j]==v[j-1]) {v[j]*=2;
if(v[j]==2048) s=1;
for(k=j-1;k>st;k--)v[k]=v[k-1];
st++;
z++;
}
}
else
{ for(j=st;j<dr;j++)
if(v[j]==v[j+1]){ v[j]*=2;
if(v[j]==2048) s=1;
for(k=j+1;k<dr;k++)v[k]=v[k+1];
dr--;
z++;
}
}
X=i;
if(z==0) X=i-1,i=m;
Z=max(Z,z);
if(s)i=m;
}

Y=v[st];
for(i=st+1;i<=dr;i++) Y=max(Y,v[i]);
g<<X<<’\n’<<Y<<’\n’<<Z<<’\n’;
f.close();g.close();

return 0;
}

Listing 24.1.2: 2048A.cpp


#include <fstream>

using namespace std;

ifstream f("2048.in");
ofstream g("2048.out");

int p[10001],n,m,k,i,ii,nrfuz,x,y,z,j,in,sf,mutat,gata,P;
char d,ud;

int main()
{
//citire
f>>n>>m;

for(i=1;i<=n;i++){f>>p[i];if(p[i]==2048){gata=1;y=2048;}}

in=1;sf=n;
for(i=1;i<=m && !gata;i++)
{
f>>d;nrfuz=0;mutat=0;
if(d==’D’)
{for(j=sf;j>in;j--)
if(p[j]==p[j-1])
{
nrfuz++;mutat=1;if(P>=in && P<=j-1)P++;
p[j]*=2;
for(k=j-1;k>in;k--)p[k]=p[k-1];
in++;
}
}
else
{for(j=in;j<sf;j++)
if(p[j]==p[j+1])
{
nrfuz++;mutat=1;if(P<=sf && P>=j+1)P--;
CAPITOLUL 24. ONI 2014 24.1. 2048 312

p[j]*=2;
for(k=j+1;k<sf;k++)p[k]=p[k+1];
sf--;
}
}

if(nrfuz>z)z=nrfuz;
if(!mutat)gata=1;else ud=d,x++;

for(ii=in;ii<=sf;ii++)
if(p[ii]>y)y=p[ii];

if(y==2048)gata=1;
}

if(ud==’D’)P=P+n-sf;
else P=P-(in-1);

g<<x<<endl<<y<<endl<<z<<endl;

f.close();g.close();return 0;
return 0;
}

Listing 24.1.3: 2048F.cpp


#include <fstream>

using namespace std;

int n,i,j,v[10010],p[12],x,y,z,m,k,f=1;
char c;

int main()
{
x=y=z=0;
ifstream fin("2048.in");
ofstream fout("2048.out");

fin>>n>>m;
for(i=1;i<=n;i++)
{fin>>v[i];
k=0;x=v[i];
while(x>1) x>>=1,k++;
p[k]++;
}

x=0;
while(x<m&&!p[11]&&f)
{ x++;
fin>>c;

if(c==’S’)
{
f=0;
for(i=2;i<=n;)
if(v[i]==v[i-1])
{v[i-1]*=2;
k=0;f++;
while(v[i]>1) v[i]>>=1,k++;
p[k]-=2;p[k+1]++;
for(j=i;j<n;j++)
v[j]=v[j+1];
n--;i++;
}
else i++;
if(f>z)z=f;
}
else
{
f=0;
for(i=n-1;i>=1;i--)
if(v[i]==v[i+1])
{v[i]*=2;
k=0;f++;
CAPITOLUL 24. ONI 2014 24.1. 2048 313

while(v[i+1]>1) v[i+1]>>=1,k++;
p[k]-=2;p[k+1]++;
for(j=i+1;j<n;j++)
v[j]=v[j+1];
n--;i--;
}
if(f>z)z=f;
}

//for(i=1;i<=11;i++) fout<<p[i]<<’ ’; fout<<’\n’;


//for(i=1;i<=n;i++) fout<<v[i]<<’ ’; fout<<’\n’;
}

if(p[11]) y=2048;
else
{
for(i=11;!p[i];i--);
y=1<<i;
}

if(!f)x--;

fout<<x<<’\n’<<y<<’\n’<<z<<’\n’;

fin.close();
fout.close();
return 0;
}

Listing 24.1.4: 2048G.cpp


#include <fstream>

using namespace std;

long long a[10001], Y;


int z,i,x,Z,j,k,N,M,gata=1;
char c;

int main()
{
ifstream f("2048.in");
ofstream g("2048.out");

f>>N>>M;f>>a[1];

for(i=2;i<=N;i++) {f>>a[i];if(a[i]==a[i-1] )gata=0;}


for(i=1;i<=N;i++) if(a[i]==2048) gata=1;

for(i=1;i<=M && (gata==0);i++)


{

f>>c;

x++;Z=0;
if(c==’D’)
{ int q=N;
for(j=N;j>1;j--)
if(a[j]==a[j-1])
{ a[j]=2*a[j];if(a[j]==2048) gata=1;
for(k=j-1;k<N;k++) a[k]=a[k+1];
q--;Z++;j--; }
if(q==N) {gata=1;x--;} else N=q;

}
else
{ int q=N;
for(j=1;j<N;j++)
if(a[j]==a[j+1])
{ a[j]=2*a[j];if(a[j]==2048)gata=1;
for(k=j+1;k<N;k++) a[k]=a[k+1];
N--;Z++;
}
if(q==N) {x--;gata=1;}
CAPITOLUL 24. ONI 2014 24.1. 2048 314

if(z<Z) z=Z;
}

Y=a[1];N++;

for(i=1;i<=N;i++)
{
if(a[i]>Y) Y=a[i];
}

g<<x<<endl<<Y<<endl<<z<<endl;

f.close();
g.close();
return 0;
}

Listing 24.1.5: 2048L.cpp


#include <fstream>

using namespace std;

ifstream fin("2048.in");
ofstream fout("2048.out");

int n,m,a[10001],i,x,y,z,st,dr,nr,k,j,p,sch;
char c,uc,uuc;

int main()
{
fin>>n>>m;
for(i=1;i<=n;i++)
fin>>a[i];

x=y=z=0;
for(j=1;j<=n;j++)
y=max(y,a[j]);

if(y!=2048)
{x=y=z=0;
st=1;dr=n;
for(i=1;i<=m;i++)
{
fin>>c;
nr=0;
x++;

if(c==’S’)
{
for(j=st;j<dr;j++)
if(a[j]==a[j+1])
{
a[j]=2*a[j];nr++;
if(j+1==p)p--,sch=1;
else sch=0;
for(k=j+1;k<dr;k++)
{
a[k]=a[k+1];
if(k+1==p&&!sch){p--;sch=1;}
}
dr--;
}

z=max(z,nr);
}
else
{
for(j=dr;j>st;j--)
if(a[j]==a[j-1])
{
a[j]=2*a[j];nr++;
if(j-1==p)p++,sch=1;
CAPITOLUL 24. ONI 2014 24.1. 2048 315

else sch=0;
for(k=j-1;k>=st;k--)
{
a[k]=a[k-1];
if(k-1==p&&sch==0){p++;sch=1;}
}
st++;
}

z=max(z,nr);
}

if(nr==0)x--;

for(j=1;j<=n;j++)
y=max(y,a[j]);

if(nr==0)uuc=uc;
else uuc=c;

if(y==2048||nr==0)break;

uc=c;
}
}

fout<<x<<’\n’<<y<<’\n’<<z<<’\n’;
fout.close();
return 0;
}

Listing 24.1.6: 2048R.cpp


//Raluca Costineanu
#include <fstream>

using namespace std;

int a[10001], n, m;
char d;

ifstream f("2048.in");
ofstream g("2048.out");

int main()
{
int i, nr=0, p, u, k, max=0, nrf, nrm=0;
bool ok=1, e2048=0;

f>>n>>m;
for(i=1;i<=n;i++){f>>a[i];if(a[i]>nrm)nrm=a[i];}

if(nrm==2048)e2048=1,ok=0;

p=1; u=n;
while(ok)
{
f>>d; nr++;
nrf=0;
if(d==’S’)
{
k=p;
for(i=p;i<u;i++)
if(a[i]==a[i+1]) {a[k++]=2*a[i]; i++; nrf++; if(a[k-1]>nrm)nrm=a[k-1];}
else a[k++]=a[i];

if(i==u)a[k++]=a[i];
u=k-1;
}
else
{
k=u;
for(i=u;i>p;i--)
if(a[i]==a[i-1]) {a[k--]=2*a[i]; i--; nrf++;if(a[k+1]>nrm)nrm=a[k+1];}
else a[k--]=a[i];
CAPITOLUL 24. ONI 2014 24.2. BABILON 316

if(i==p) a[k--]=a[i];
p=k+1;
}

if(nrm==2048)e2048=1;

if(nrf==0)ok=0;
else if(nrf>max)max=nrf;

if(nr==m)ok=0;

if(e2048==1)ok=0;
//for(i=p;i<=u;i++)g<<a[i]<<’ ’;g<<’\n’;
}

if(nr==m or e2048==1)
g<<nr<<’\n’;
else
g<<nr-1<<’\n’;

g<<nrm<<’\n’<<max<<’\n’;

f.close();
g.close();
return 0;
}

24.1.3 *Rezolvare detaliată

24.2 babilon
Problema 2 - babilon 100 de puncte
Babilonienii au dezvoltat un sistem poziţional de scriere a numerelor, ı̂n care orice număr
natural se poate reprezenta utilizând semnele (unu), (zece) şi spaţii.
Valorile k " r2, 3, ..., 9x se obţin scriind semnul de k ori (scrierea babiloniană a lui 3 este
).
Numerele 11, 12, ..., 59 se obţin ca succesiuni de semne urmate de semne (43 se reprezintă
ca ).
Sistemul foloseşte gruparea unităţilor câte şaizeci. Astfel, pentru a scrie umărul şaizeci se
foloseşte acelaşi semn ca pentru unu, dar valoarea sa este dată de poziţia ı̂n care se găseşte semnul
.
Babilonienii nu foloseau cifra 0. Pentru poziţionarea corectă a semnelor se utiliza spaţiu
(60 se reprezintă ca , 3600 se reprezintă ca etc.).
Se codifică scrierea babiloniană a unui număr utilizând cifra 1 ı̂n locul semnului , cifra 2 ı̂n
locul semnului şi cifra 3 ı̂n loc de spaţiu, ca ı̂n exemplele de mai jos:

Scrierea
babiloniană
Codificarea 1311 12 1221111 123111
scrierii
babiloniene
Valoarea 1*60+2=62 1*60+10=70 1*60+20+4=84 1*60*60+10*60+3=4203
zecimală
a numărului

Cerinţe

Dându-se un număr natural n şi un şir de n cifre din mulţimea r1, 2, 3x, reprezentând codificarea
scrierii babiloniene a unui număr natural, să se determine:
CAPITOLUL 24. ONI 2014 24.2. BABILON 317

a) numărul maxim de cifre 1 aflate pe poziţii consecutive ı̂n codificarea scrierii babiloniene
date;
b) numărul natural din sistemul zecimal corespunzător scrierii babiloniene date.

Date de intrare

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


a pe prima linie un număr natural p ( 1 & p & 2 );
a pe a doua linie un număr natural n;
a pe a treia linie n cifre separate prin câte un spaţiu, reprezentând codificarea scrierii ba-
biloniene a unui număr natural.

Date de ieşire

Dacă valoarea lui p este 1, atunci se va rezolva numai punctul a) din cerinţă. În acest caz,
fişierul de ieşire babilon.out va conţine pe prima linie un număr natural reprezentând numărul
maxim de cifre 1 aflate pe poziţii consecutive ı̂n codificarea scrierii babiloniene date.
Dacă valoarea lui p este 2, atunci se va rezolva numai punctul b) din cerinţă. În acest caz,
fişierul de ieşire babilon.out va conţine pe prima linie numărul natural corespunzător scrierii
babiloniene date.

Restricţii şi precizări

2 & n & 10 ;
9
a
a se garantează faptul că numărul de cifre al rezultatului de la punctul b) (numărul zecimal)
este mai mic decât 20;
a 30% din teste vor avea pe prima linie valoarea 1, iar restul de 70% din teste vor avea pe
prima linie valoarea 2.

Exemple

babilon.in babilon.out Explicaţii


1 3 1 1 3 2 1 1 1 2.
8 Cea mai lungă secvenţă de cifre 1 are lungimea 3.
11321112
2 7213
7
1132111

2 se ı̂nmulţeşte de două ori cu 60 (o dată pentru


că este urmat de spaţiu şi ı̂ncă o dată pentru că
precede o grupă care ı̂ncepe cu semnul $ ), apoi
se adună valoarea 13.
2*60*60+10+3=7213
2 11541
9
111211221

3 se ı̂nmulţeşte cu 60 de două ori pentru că este


precedat de două grupe care ı̂ncep cu semnul $ ,
apoi se adună 12 ı̂nmulţit cu 60 şi la final se adună
21.
3*60*60+12*60+21=11541

Timp maxim de executare/test: 0.1 secunde


Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 5 KB
CAPITOLUL 24. ONI 2014 24.2. BABILON 318

24.2.1 Indicaţii de rezolvare


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

Punctul a):
Se citesc pe rând valorile din fişier, se determină lungimea fiecărei secvenţe de cifre 1 şi se
reţine lungimea maximă.
Punctul b):
Se citeşte prima cifră şi se iniţializează o variabilă z cu 1 dacă cifra este 1 (corespunzător
semnului ), respectiv cu 10 dacă este egală cu 2 (corespunzător semnului ). Se continuă
citirea câte unei cifre şi la ı̂ntâlnirea cifrei 3 (corespunzătoare unui spaţiu ı̂n scrierea babiloniană)
sau a cifrei 2 precedată de o cifră 1 (ignorând eventualele cifre 3 corespunzătoare spaţiilor) valoarea
z se ı̂nmulţeşte cu 60. Pentru fiecare cifră 1 ı̂ntâlnită, z se incrementează cu 1, iar pentru fiecare
cifră 2, se incrementează cu 10.

24.2.2 Cod sursă

Listing 24.2.1: babilon.cpp


//Florentina Ungureanu - Colegiul National de Informatica Piatra-Neamt
#include <fstream>
#include <iostream>
#include <string.h>

using namespace std;


unsigned n, v, a, b, c;

ifstream f("babilon.in");
ofstream g("babilon.out");

int main()
{
long long z=0;
unsigned i, fr, fmax;
f>>v>>n;
if(v==1)
{
f>>a;
fmax=fr=a==1;
for(i=2;i<=n;i++)
{
f>>b;
if(a*b==1) fr++;
else
{
if (fr>fmax) fmax=fr;
fr=b==1;
}
a=b;
}

if (fr>fmax) fmax=fr;
g<<fmax<<’\n’;
}
else
{
f>>a;
if(a==1)z=1;
else
if(a==2)z=10;
else z=0;

for(i=2;i<=n;i++)
{
f>>b;
if (b>a) z=z*60;
if(b==1)z++;
else if(b==2)z+=10;
if (b!=3) a=b;
}
CAPITOLUL 24. ONI 2014 24.2. BABILON 319

g<<z<<’\n’;
}

f.close();
g.close();
return 0;
}

Listing 24.2.2: babilonA.cpp


#include <fstream>

using namespace std;

ifstream f("babilon.in");
ofstream g("babilon.out");

int var,n,i,c[121],l,lmax,prec;
long long nrb;

int main()
{
//citire-prelucare
f>>var>>n;
for(i=1;i<=n;i++) f>>c[i];
if(var==1)
{
for(i=1;i<=n;i++)
{
if(c[i]==1) l++;
else {if(l>lmax) lmax=l;
l=0;
}
}
{if(l>lmax) lmax=l;l=0;} g<<lmax<<endl;
}
else
{
for(i=1;i<=n;i++)
if(c[i]==1) nrb++,prec=c[i];
else if(c[i]==3) nrb*=60;
else {
if(prec==1)nrb*=60;
nrb+=10;prec=c[i];
}
g<<nrb<<endl;
}
return 0;
}

Listing 24.2.3: babilonC.cpp


#include <fstream>
//Cristina Sichim

using namespace std;

ifstream f("babilon.in");
ofstream g("babilon.out");

long long r;
int v,n,i,c,a,k1,k;

int main()
{ f>>v>>n;
for(i=1;i<=n;++i)
{ f>>c;
switch(c)
{case 1: r++,a=c,k++,k1=max(k,k1);break;
case 2: if(a==1) r*=60;r+=10,a=c,k=0;break;
default:r*=60,k=0;
}
}
CAPITOLUL 24. ONI 2014 24.2. BABILON 320

if(v==1)g<<k1<<’\n’;
else g<<r<<’\n’;

f.close();
g.close();
return 0;
}

Listing 24.2.4: babilonL.cpp


#include <fstream>

using namespace std;

ifstream fin("babilon.in");
ofstream fout("babilon.out");

int n, c1,c2,i,x,caz,nr1,nrmax;
long long nr;
char c;

int main()
{
fin>>caz;
if(caz==1)
{
fin>>n;nr1=0;
for(i=1;i<=n;i++)
{
fin>>c;c1=c-’0’;
if(c1==1)nr1++;
else
{
if(nr1>nrmax)nrmax=nr1;
nr1=0;
}
}
if(nr1>nrmax)nrmax=nr1;
fout<<nrmax<<’\n’;
}
else
{
fin>>n>>c;
nr=nr1=0;
c1=c-’0’;
if(c1==1){nr1++;x=1;}
else x=10;
for(i=2;i<=n;i++)
{
fin>>c;
c2=c-’0’;
if(c2==1)
{x++;nr1++;}
else
if(c2==2)
{
if(c1==2)x=x+10;
else
if(nr1)
{
nr=nr*60+x;//fout<<x<<’ ’<<nr<<’\n’;
x=10;
nr1=0;
}
else x=10;
}
else
{
nr=nr*60+x;//fout<<x<<’ ’;
x=0;
}
c1=c2;
}
nr=nr*60+x;
fout<<nr<<’\n’;
CAPITOLUL 24. ONI 2014 24.3. IEPURASI 321

}
fout.close();
return 0;
}

24.2.3 *Rezolvare detaliată

24.3 iepurasi
Problema 3 - iepurasi 100 de puncte
Se construieşte un şir de numere naturale care
respectă restricţiile:
- primul număr din şir este 9;
- numerele se generează ı̂n ordine strict
crescătoare;
- şirul conţine toate numerele formate doar cu
cifrele 7, 8 şi 9 cu proprietatea că numărul cifrelor
9 este mai mare sau egal decât numărul cifrelor 8
şi numărul cifrelor 8 este mai mare sau egal decât
numărul cifrelor 7.
Primii 14 termeni ai şirului, ı̂n ordine, sunt: 9,
89, 98, 99, 789, 798, 879, 897, 899, 978, 987, 989, Figura 24.2: iepurasi
998, 999.
Pornind de la aceste numere, Liv a inventat un joc interactiv: N iepuraşi sunt aşezaţi ı̂n şir,
fiecare având câte un cartonaş. Fiecare cartonaş are două feţe, o faţă albă pe care este inscripţionat
un număr din acest şir şi o faţă gri, pe care este inscripţionată poziţia acelui număr ı̂n şir, poziţii
numerotate ı̂n ordine, ı̂ncepând cu valoarea 14.
Exemple. Cartonaşul care are pe faţa gri inscripţionat numărul 1 va avea pe faţa albă
inscripţionat numărul 9, iar cartonaşul care are pe faţa gri inscripţionat numărul 5 va avea pe faţa
albă inscripţionat numărul 789.
Iepuraşii sunt aşezaţi ı̂ntr-o ordine oarecare şi ţin cartonaşele astfel ı̂ncât să se vadă faţa
gri. Jocul constă ı̂n a rearanja iepuraşii de la stânga la dreapta, descrescător după numerele
inscripţionate pe feţele gri, având la dispoziţie doar operaţia T AP pe un iepuraş. Când se aplică
operaţia T AP unui iepuraş atunci secvenţa de iepuraşi, ı̂ncepând de la cel pe care s-a făcut T AP şi
până la sfârşitul şirului (spre dreapta), este oglindită (ca ı̂n imaginea de mai sus). După oglindire,
toţi iepuraşii din acea secvenţă ţin cartonaşele astfel ı̂ncât să se vadă faţa albă. Se doreşte aplicarea
unui număr cât mai mic de operaţii T AP pentru rearanjarea iepuraşilor.
Cerinţe
Scrieţi un program care să citească numerele naturale N (reprezentând numărul de iepuraşi) şi
a1 , a2 , ..., aN (reprezentând, ı̂n ordine, numerele inscripţionate pe feţele gri) şi care să determine:
a) Numărul minim de operaţii T AP necesare rearanjării iepuraşilor;
b) Cel mai mic număr aflat pe o faţă albă care nu se vede, ı̂n cazul ı̂n care au rămas cartonaşe
neı̂ntoarse. Dacă toate cartonaşele au fost ı̂ntoarse (la toate fiind vizibilă faţa albă) se va afişa cel
mai mare număr aflat pe o faţă albă a unui cartonaş.
Date de intrare
Fişierul de intrare iepurasi.in conţine pe prima linie numărul natural N reprezentând numărul
de iepuraşi. A doua linie a fişierului conţine, ı̂n ordine, cele N numere: a1 , a2 , ...,aN , separate
prin câte un spaţiu, reprezentând ı̂n ordine, numerele inscripţionate pe feţele gri ale cartonaşelor.
Date de ieşire
Fişierul de ieşire iepurasi.out va conţine pe prima linie un număr reprezentând numărul
minim de operaţii T AP necesare rearanjării iepuraşilor.
A doua linie va conţine un număr reprezentând cel mai mic număr aflat pe o faţă albă care nu
se vede (ı̂n cazul ı̂n care au rămas cartonaşe neı̂ntoarse), respectiv cel mai mare număr aflat pe o
faţă albă a unui cartonaş, ı̂n cazul ı̂n care toate cartonaşele au fost ı̂ntoarse (la toate fiind vizibilă
faţa albă).
CAPITOLUL 24. ONI 2014 24.3. IEPURASI 322

Restricţii şi precizări

a 2 & N & 10000;


a 1 & ai & 10000 (1 & i & N );
a N , a1 , a2 , ..., aN sunt numere naturale;
a pentru rezolvarea cerinţei a) se acordă 50% din punctaj, iar pentru cerinţa b) se acordă 50%
din punctaj.

Exemple
iepurasi.in iepurasi.out Explicaţii
5 1 Se aplică o singură operaţie TAP pe iepuraşul cu numărul
14 5 8 9 10 999 de ordine 5.
Cartonaşul neı̂ntors are numărul de ordine 14 (999).

Timp maxim de executare/test: 1.0 secunde


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

24.3.1 Indicaţii de rezolvare


Cerinţa a)
Întrucât problema cere ca rearanjarea iepuraşilor să se facă de la stânga la dreapta, primul
iepuraş care trebuie repoziţionat este iepuraşul cu cel mai mare număr pe faţa gri. Urmând aceeaşi
idee, la fiecare pas i, trebuie repoziţionat iepuraşul cu cel mai mare număr pe faţa gri, care se află
pe o poziţie j (i & j & n). Costul unei astfel de repoziţionări poate fi 0, 1 sau 2.
Soluţia1. Se parcurge tabloul cu numerele de ordine ale iepuraşilor, de la stânga la dreapta,
şi pentru fiecare ai se verifică dacă este maxim pe secvenţa ai ... an. Dacă nu este maxim,
se caută poziţia elementului maxim aflat la dreapta lui i, fie aceasta imax şi se execută un T AP
pe iepuraşul cu numărul de ordine aimax, dacă imax j N şi apoi un T AP pe iepuraşul cu
numărul de ordine ai.
Soluţia2. Se face o copie a tabloului unidimensional cu numerele de ordine ale iepuraşilor citite
(a1). Se ordonează descrescător a1 şi se compară cu şirul iniţial. În cazul ı̂n care ai j a1i se
execută T AP pe ai, dacă a1N  ai sau se face T AP pe aj , dacă a1j  ai şi T AP pe
ai.
Soluţia3. Se realizează un precalcul care numără pentru fiecare cartonaş gri, câte elemente
sunt mai mici ca valoare şi se reţine ı̂ntr-un tablou poziţia pe care ar ocupa-o ı̂n şirul sortat şi ı̂n
alt tablou poziţia pe care o ocupă ı̂n şirul actual. Pentru un cartonaş care nu se află pe poziţia
sa finală se realizează T AP din poziţia elementului care ar fi trebuit să se afle ı̂n această poziţie.
Dacă acest element se află ı̂n şirul actual pe poziţia n se face un T AP , iar dacă nu, se fac două
T AP -uri (primul ca să ajungă pe poziţia n şi al doilea ca să ajungă la locul său).
Cerinţa b)
Soluţia1. Se utilizează 4 tablouri unidimensionale, unul pentru memorarea tuturor numerelor
ce se pot forma, ı̂n ordine crescătoare, cu cifrele 7, 8 şi 9 şi trei tablouri unidimensionale ı̂n care
se memorează frecvenţa de apariţie a cifrelor 7, 8 şi 9 ı̂n numerele generate.
Soluţia2. Se simulează o generare ı̂n baza 4 ı̂n care resturilor 1, 2, 3 li se asociază cifrele 7, 8
şi 9.

24.3.2 Cod sursă

Listing 24.3.1: iepurasi AI.cpp


//Ana Intuneric
#include <fstream>

using namespace std;

ifstream f("iepurasi.in");
CAPITOLUL 24. ONI 2014 24.3. IEPURASI 323

ofstream g("iepurasi.out");

long long toate[200001],ncurent;


int N,a[10001],dim_sir,TAP,nr1,nr2;
bool viz[10001];
char fr7[200001],fr8[200001],fr9[200001];

int main()
{
int i,j,k,maxi,imax,aux,c7,c8,c9;;
//citire
f>>N;
for(i=1;i<=N;i++)f>>a[i];

//sortare descrescatoare
for(i=1;i<=N;i++)
{
imax=i;maxi=a[i];
for(j=i+1;j<=N;j++)
if(a[j]>maxi)maxi=a[j],imax=j;
if(imax!=i)
{
if(a[N]!=maxi)
{
TAP++;
//TAP pe iepurasul imax
for(j=imax,k=N;j<k;j++,k--)
aux=a[j],a[j]=a[k],a[k]=aux,viz[j]=true,viz[k]=true;
}
//TAP pe iepurasul i
if(a[i]!=maxi)
{
TAP++;
for(j=i,k=N;j<k;j++,k--)
aux=a[j],a[j]=a[k],a[k]=aux,viz[j]=true,viz[k]=true;
}
}
}

//det cartonas minim/maxim


if(viz[1])k=a[1];
else
{
i=1;while(!viz[i] && i<=N)i++;
k=a[i-1];
}

//constructie sir de numere cu cifrele 7,8,9 pana la numarul de pe pozitia k


fr7[1]=1;fr8[2]=1;fr9[3]=1;
toate[1]=7;toate[2]=8;toate[3]=9;
dim_sir=0;nr1=1;nr2=3;
while(dim_sir<k)
{
c7=fr7[nr1];c8=fr8[nr1];c9=fr9[nr1];
ncurent=toate[nr1];nr1++;nr2--;
if(c7<=c8 && c8<=c9) dim_sir++;

fr7[nr1+nr2]=c7+1;fr8[nr1+nr2]=c8;fr9[nr1+nr2]=c9;
toate[nr1+nr2]=10*ncurent+7;nr2++;

fr7[nr1+nr2]=c7;fr8[nr1+nr2]=c8+1;fr9[nr1+nr2]=c9;
toate[nr1+nr2]=10*ncurent+8;nr2++;

fr7[nr1+nr2]=c7;fr8[nr1+nr2]=c8;fr9[nr1+nr2]=c9+1;
toate[nr1+nr2]=10*ncurent+9;nr2++;
}

//afisare
g<<TAP<<endl<<ncurent<<endl;
f.close();g.close();return 0;
return 0;
}

Listing 24.3.2: iepurasi CS.cpp


CAPITOLUL 24. ONI 2014 24.3. IEPURASI 324

//Cristina Sichim
#include <fstream>
#include <algorithm>

using namespace std;

ifstream f("iepurasi.in");
ofstream g("iepurasi.out");

int v1[10001],v2[10001],c[4],n,i,j,k,t,tap;
long long z,x,y;

bool cand(int i,int j) {return (i>j);}

int main()
{ f>>n;
for(i=1;i<=n;i++){f>>v1[i];v2[i]=v1[i];}

sort(v2+1,v2+n+1,cand);

i=1;while(i<=n && v1[i]==v2[i])i++;


if(i==n+1)k=v2[n];
else if(i==1) k=v2[1];
else k=v2[i-1];

for(;i<n;i++)
if(v1[i]!=v2[i])
{ j=i;
while(v1[j]!=v2[i])j++;
if(j!=n) tap++,reverse(v1+j,v1+n+1);
tap++;reverse(v1+i,v1+n+1);
}

//c[1]->7,c[2]->8,c[3]->9
x=1;
while(k)
{ c[0]=c[1]=c[2]=c[3]=0;t=1;
y=x++;
z=0;
while(y)z+=(y%4+6)*t,c[y%4]++,y=y/4,t=t*10;
if(c[0]==0 && c[3]>=c[2] && c[2]>=c[1]) k--;
}

g<<tap<<’\n’<<z<<’\n’;
f.close();g.close();
return 0;
}

Listing 24.3.3: iepurasi gina.cpp


#include <fstream>

using namespace std;


long long a[10001],n,i,Imax,x,j,k,I[10001],tap,gata,J,aux;
int main()
{ ifstream f("iepurasi.in");ofstream g("iepurasi.out");
f>>n;
for(i=1;i<=n;i++) f>>a[i];
for(k=1;k<n;k++)
{ Imax=k;
for(j=k+1;j<=n;j++) if(a[j]>a[Imax]) Imax=j;
if(k!=Imax)
{ tap++;J=n;
if(Imax!=n)
{for(j=Imax;j<J;j++)
{aux=a[j];a[j]=a[J];a[J]=aux; J--;I[j]=1;I[J]=1;}
I[j]=1;tap++;}
J=n;
for(j=k;j<J;j++){aux=a[j];a[j]=a[J];a[J]=aux; J--;I[j]=1;I[J]=1;}
I[j]=1;
}
}
int i1=0,i2=0;
for(i=n;i>=1;i--)
if(!a[i])
CAPITOLUL 24. ONI 2014 24.3. IEPURASI 325

if(i1==0)i1=i;
else
if(i2==0)i2=i;
else
break;
//if(i1*i2)
// {g<<i1<<" "<<i2<<endl;}
//else
// {g<<a[2]<<" "<<a[1]<<endl;}
//g<<tap<<endl;
//for(i=1;i<=n;i++)
//g<<a[i]<<’ ’;
long long P,x,i=1,n4,n7=0;
i=1;
for(n7=0;n7<=a[1];i++)
if(i%4)
{ int c[4],ok=1;
for(int j=0;j<=3;j++)c[j]=0;
P=1;x=i;n4=0;
while(x)
{n4=n4+(x%4+6)*P;
c[x%4]++;x=x/4; P=P*10;
}
if(c[0]!=0 || c[1]>c[2] || c[1]>c[3] || c[2]>c[3])ok=0;
if(ok)
{
//g<<i<<’ ’<<n4<<endl;
I[++n7]=n4;
}
}

g<<tap<<endl;
if(i1*i2)
{//g<<I[i1]<<" "<<I[i2]<<endl;
g<<I[i2]<<endl;
}
else
{//g<<I[a[2]]<<" "<<I[a[1]]<<endl;
g<<I[a[1]]<<endl;
}

f.close();
g.close();
return 0;
}

Listing 24.3.4: iepurasi lucia.cpp


#include <fstream>
#include<algorithm>

using namespace std;

ifstream fin("iepurasi.in");
ofstream fout("iepurasi.out");

int n, a[10011], i, viz[10011], ao[10011],nro,caz,m1,m2,poz,nt,nr;


long long s[20100];

void adauga(int cm,int poz,int m)


{
long long nrnou,x,nv,pp,sf,inc;
nv=0;
pp=1;
x=s[poz];
while(pp<x)
{
sf=x%pp;
inc=x/pp;
nrnou=(inc*10+cm)*pp+sf;
nt++;
s[nt]=nrnou;
for(i=nt-1; i>=nr+1; i--)
if(s[nt]==s[i])
{
CAPITOLUL 24. ONI 2014 24.3. IEPURASI 326

nt--;
break;
}
pp=pp*10;
nv++;
// if(nt>=m)return;
}
nrnou=cm*pp+x;;
nt++;
s[nt]=nrnou;
for(i=nt-1; i>=nr+1; i--)
if(s[nt]==s[i])
{
nt--;
break;
}
// if(nt>=m)return;
}

void construieste(int m)
{
long long i,k,c7,c8,c9,nv;
long long x;
s[1]=9;
k=1;
nr=1;
nt=nr;
//m=7000;
while(nt<m)
{
for(poz=k; poz<=nr; poz++)
{
x=s[poz];
c7=c8=c9=0;
nv=0;
while(x)
{
if(x%10==7)c7++;
if(x%10==8)c8++;
if(x%10==9)c9++;
x=x/10;
nv++;
}
if(c8<c9)adauga(8,poz,m);
if(c7<c8&&c8<=c9)adauga(7,poz,m);
adauga(9,poz,m);

}
//if(nt>=m)break;
x=0;
for(i=1; i<=nv+1; i++)
x=x*10+9;
s[++nt]=x;
for(i=nt-1; i>=nr+1; i--)
if(s[nt]==s[i])
{
nt--;
break;
}
k=nr+1;
nr=nt;
}
sort(s+1,s+nt+1);
}

void schimba(int st)


{
int i,j;
i=st;
j=n;
while(i<=j)
{
swap(a[i],a[j]);
viz[i]=1;
viz[j]=1;
i++;
CAPITOLUL 24. ONI 2014 24.3. IEPURASI 327

j--;
}
}

int main()
{
fin>>n;
for(i=1; i<=n; i++)
{
fin>>a[i];
ao[i]=a[i];
}

sort(ao+1,ao+n+1);

for(i=1; i<=n/2; i++)


swap(ao[i],ao[n+1-i]);

for(i=1; i<=n; i++)


if(ao[i]!=a[i])
{
nro++;
for(poz=i+1; poz<=n; poz++)
if(a[poz]==ao[i])break;
if(poz!=n)
{
schimba(poz);
nro++;
schimba(i);
}
else schimba(i);
}
caz=2;
for(i=1; i<=n; i++)
if(viz[i]==0)
{
caz=1;
break;
}
if(caz==1)
{
m1=10001;
for(i=1; i<=n; i++)
if(viz[i]==0 && m1>a[i])
m1=a[i];
else break;
}
else
{
m1=0;
for(i=1; i<=n; i++)
if(m1<a[i]) m1=a[i];

construieste(m1);
fout<<nro<<’\n’<<s[m1]<<’\n’;
fout.close();
return 0;
}

Listing 24.3.5: iepurasiM.cpp


#include <fstream>
#include <iostream>
#include <algorithm>

using namespace std;


unsigned long long a[10001],sir[10001],vmax,vmin,i,x,nr,j,t,m;
int n,b[10001],y[10001],d[10001],p1,p2,p,k,ok,rez,ii,cif[10];

ifstream f("iepurasi.in");
ofstream g("iepurasi.out");

int main()
CAPITOLUL 24. ONI 2014 24.3. IEPURASI 328

{f>>n;
for(i=1;i<=n;i++)
{
f>>a[i];
if(a[i]>vmax) vmax=a[i];
}

f.close();

//varianta generare sir care intra in timp


for(i=1;nr<=vmax;i++)
{t=1;
for(j=0;j<=3;j++)cif[j]=0;
x=i;m=0;
while(x)
{m=m+(x%4+6)*t;cif[x%4]++;x=x/4; t=t*10;}
ok=1;if(cif[0]!=0)ok=0;
if(ok)for(j=1;j<3;j++)if(cif[j]>cif[j+1])ok=0;
if(ok) sir[++nr]=m;
}

//varianta de generare sir care nu intra in timp


/*nr=0;s
for(i=1;nr<=vmax; i++)
{
if(i%10>6)
for(j=0;j<=9;j++) cif[j]=0;
x=i;
ok=1;
while(x)

{ if(x%10<7){ok=0;x=0;}
cif[x%10]++;x=x/10;
}
if (cif[7]>cif[8]|| cif[8]>cif[9])ok=0;

if(ok){nr++;sir[nr]=i;}

}
*/

for(i=1;i<=n;i++)
{k=0;
for(j=1;j<=n;j++)if(a[j]<a[i])k++;
b[i]=k+1;y[k+1]=i;
}

vmin=a[1];p=0;
ok=1;
for(j=1;j<=n;j++)
{
if(b[j]!=n-j+1) {;p=j;break;}
if(vmin>a[j])vmin=a[j];

for(i=1;i<=n; i++)
if(b[i]!=n-i+1)
{
p1=i;p2=y[n-i+1];
if(p2==n)
{rez++;k=0; for(j=p2;j>=p1; j--) {k++;d[k]=b[j];} }
else
{ rez=rez+2;k=0;
for(j=p2;j<=n; j++){k++;d[k]=b[j];}
for(j=p2-1;j>=p1; j--){k++;d[k]=b[j];}
}
for(ii=1;ii<=k; ii++) {b[p1+ii-1]=d[ii];y[d[ii]]=p1+ii-1;}
}

g<<rez<<endl;
if(p==1)g<<sir[vmax]<<endl;
else
g<<sir[vmin]<<endl;
CAPITOLUL 24. ONI 2014 24.3. IEPURASI 329

g.close();
}

24.3.3 *Rezolvare detaliată


Capitolul 25

ONI 2013

25.1 greieri
Problema 1 - greieri 100 de puncte
Pe o linie orizontală se găsesc n
greieri. Ei ı̂ncep să stea ”capră” ı̂ntr-
o ordine prestabilită ı̂ncepând cu ul-
timul, pe rând, până la primul. Toţi
greierii care ı̂l precedă pe cel care stă
”capră” sar peste acesta, ı̂n ordine.
De exemplu pentru n=4, mai ı̂ntâi
stă ”capră” greierele 4 şi peste el sar,
ı̂n ordine, 3, 2 şi 1. Apoi stă ”capră”
greierele 3 şi sar peste el, ı̂n ordine, 2,
1 şi 4. Apoi stă ”capră” greierele 2 şi
peste el sar, ı̂n ordine, 1, 3 şi 4. Apoi
stă ”capră” greierele 1 şi sar peste el, Figura 25.1: greieri
ı̂n ordine, 4 , 3 şi 2, şi se revine la ordinea iniţială.

Cerinţe

Scrieţi un program care citeşte numerele naturale n şi m şi determină:


a) De câte sărituri este nevoie pentru a se ajunge la ordinea iniţială?
b) Cum vor fi aşezaţi greierii după m sărituri?

Date de intrare

Fişierul de intrare greieri.in conţine pe prima linie numerele naturale n şi m, separate printr-
un spaţiu, cu semnificaţia din enunţ.

Date de ieşire

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


a) pe prima linie o valoare ce reprezintă numărul de sărituri după care se revine la ordinea
iniţială;
b) pe a doua linie numerele ce reprezintă ordinea greierilor după m paşi, separate prin spaţii.

Restricţii şi precizări

a2 & n & 100000


a1 & m & 2000000000
a se acordă 20% din punctaj pentru rezolvarea corectă cerinţei a)
a se acordă 80% din punctaj pentru rezolvarea corectă cerinţei b)
a răspunsurile la cele două cerinţe vor fi scrise exact pe linia indicată; ı̂n cazul ı̂n care nu
cunoaşteţi rezolvarea la una dintre cerinţe, pe linia respectivă se va scrie valoarea 1;
a fiecare linie din fişierul de intrare se termină cu caracterul sfârşit de linie

330
CAPITOLUL 25. ONI 2013 25.2. ONIGIM 331

Exemple
greieri.in greieri.out Explicaţii
45 12 După cum se vede şi ı̂n imagine pornind de la linia iniţială
4312 1 2 3 4 la primul pas sare greierele 3 peste 4, la pasul 2
sare greierele 2 peste 4, la pasul trei sare greierele 1 peste
4, la pasul patru sare greierele 2 peste 3, iar la pasul cinci
sare greierele 1 peste 3.

Timp maxim de executare/test: 0.4 secunde


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

25.1.1 *Indicaţii de rezolvare


matematică

25.1.2 *Cod sursă

25.1.3 *Rezolvare detaliată

25.2 Onigim
Problema 2 - Onigim 1000 de puncte
La ONIGIM 2013 participă N elevi de clasa a V-a având ca id-uri, ı̂n ordine, numerele naturale
de la 1 la N . Anul acesta organizatorii au afişat la clasa a V-a toate punctajele distincte obţinute
de elevi, ı̂n ordine strict crescătoare p1 , p2 , ..., pK , şi un şir de N valori a1 , a2 , ..., aN , unde ai
reprezintă numărul de elevi care au punctaje strict mai mici decât punctajul elevului având id-ul
i (1 & i & N ).

Cerinţe

Cunoscând numărul de elevi (N ), numărul de punctaje distincte (K) obţinute de elevii de


clasa a V-a, punctajele p1 , p2 , ..., pK , ı̂n ordine strict crescătoare, şi valorile a1 , a2 , ..., aN , cu
semnificaţia din enunţ, să se scrie un program care determină:
a) Punctajul obţinut de fiecare elev ı̂n ordinea crescătoare a id-urilor.
b) Numărul de distincţii acordate de organizatori. Numărul de distincţii este egal cu numărul
de elevi care au obţinut cele mai mari trei punctaje distincte.
c) Numărul maxim de elevi care au obţinut acelaşi punctaj.

Date de intrare

Fişierul de intrare onigim.in conţine pe prima linie numerele naturale N şi K reprezentând
numărul de elevi, respectiv numărul de punctaje distincte obţinute de elevi.
Pe a doua linie sunt K numere naturale ı̂n ordine strict crescătoare p1 , p2 , ..., pK reprezentând
punctajele distincte obţinute de elevi, şi pe a treia linie sunt N numere naturale a1 , a2 , ..., aN ,
unde ai reprezintă numărul de elevi care au punctaje strict mai mici decât punctajul elevului cu
ID-ul i.

Date de ieşire

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


Pe prima linie se află N numere naturale v1 , v2 , ..., vN reprezentând punctajele obţinute de cei
N concurenţi (vi - punctajul concurentului cu ID-ul i), pe a doua linie se află un număr natural
D reprezentând numărul de distincţii acordate de organizatori, pe a treia linie se află un număr
natural M reprezentând numărul maxim de elevi care au obţinut acelaşi punctaj.

Restricţii şi precizări


CAPITOLUL 25. ONI 2013 25.3. EXTRAPRIME 332

a 1 & N & 1000;


a 1 & pi & 300, (1 & i & N );
a 0 & ai $ 1000, (1 & i & N );
a 3 & K & 300;
a Pentru prima cerinţă rezolvată corect se acordă 40% din punctaj; pentru a doua cerinţă
rezolvată corect se acordă 30% din punctaj; pentru a treia cerinţă rezolvată corect se acordă 30%
din punctaj;
a Răspunsurile la cele trei cerinţe vor fi scrise exact pe linia indicată; ı̂n cazul ı̂n care nu
cunoaşteţi rezolvarea la una dintre cerinţe, pe linia respectivă se va scrie valoarea 1;
a Fiecare linie din fişierul de intrare se termină cu caracterul sfârşit de linie.

Exemple
onigim.in onigim.out Explicaţii
64 200 150 100 100 175 200 Sunt 4 elevi care au punctajul mai mic decât punc-
100 150 175 200 4 tajul elevului cu id-ul 1, 2 elevi cu punctajul mai
420034 2 mic decât punctajul elevului cu id-ul 2, etc.
Cele mai mari 3 punctaje sunt obţinute de 4 elevi.
Numărul maxim de elevi care au acelaşi punctaj
este 2.

Timp maxim de executare/test: 0.1 secunde


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

25.2.1 *Indicaţii de rezolvare


listă, tablou, tablou vector (unidimensional), tablou vector caracteristic (de frecvenţă)

25.2.2 *Cod sursă

25.2.3 *Rezolvare detaliată

25.3 Extraprime
Problema 3 - Extraprime 100 de puncte
Gigel, mare amator de probleme de matematică şi informatică, a observat că unele numere
prime au o proprietate interesantă: orice cifră ar elimina dintr-un astfel de număr, numărul obţinut
este tot număr prim. A numit astfel de numere numere extraprime. De exemplu, numărul 317
este un număr extraprim: el este număr prim şi, ı̂n plus, dacă eliminăm cifra 3, obţinem 17, care
este prim; dacă eliminăm 1, obţinem 37, care este prim; dacă eliminăm 7, obţinem 31, care este şi
el număr prim.

Cerinţe

Spunem că x este ı̂ntre a şi b dacă x ' a şi x & b. Fiind date două valori naturale a şi b, să
se determine câte numere extraprime există ı̂ntre a şi b, precum şi cel mai mic şi cel mai mare
număr extraprim dintre a şi b.

Date de intrare

Pe prima linie a fişierului de intrare extraprime.in se găsesc cele două valori naturale a şi b,
separate printr-un spaţiu.

Date de ieşire
CAPITOLUL 25. ONI 2013 25.3. EXTRAPRIME 333

Fişierul de ieşire extraprime.out va avea 3 linii.


Pe prima linie se va scrie un număr natural nr reprezentând numărul de numere extraprime
dintre a şi b.
Pe linia a doua a fişierului de ieşire se va scrie cel mai mic număr extraprim dintre a şi b, iar
pe linia a treia a fişierului de ieşire se va scrie cel mai mare număr extraprim dintre a şi b.

Restricţii şi precizări

a 10 $ a & b $ 10000000
a Numărul 1 nu este prim.
a Pentru datele de test există ı̂ntotdeauna soluţie.

Exemple
extraprime.in extraprime.out Explicaţii
10 100 4 Se află 4 numere extraprime mai mari decât 10 şi mai
23 mici decât 100: 23, 37, 53 şi 73.
73

Timp maxim de executare/test: 1.1 secunde


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

25.3.1 *Indicaţii de rezolvare


matematică

25.3.2 *Cod sursă

25.3.3 *Rezolvare detaliată


Capitolul 26

ONI 2012

26.1 culegere
Problema 1 - culegere 100 de puncte
O culegere de probleme are P pagini, numerotate de la 1 la P .
Problemele din culegere sunt numerotate cu 1, 2, 3, ..., etc, ı̂n or-
dinea apariţiei lor ı̂n culegere.
Pe prima pagină a culegerii este scrisă o singură problemă (cea cu
numărul 1).
Pe a doua pagină sunt scrise exact două probleme (cele cu numerele Figura 26.1: culegere
2 şi 3, ı̂n această ordine).
Pe cea de-a treia pagină sunt scrise exact trei probleme (cele cu numerele 4, 5 şi 6, ı̂n această
ordine), ..., pe cea de a P -a pagină sunt scrise exact P probleme.

Cerinţe

Scrieţi un program care citeşte numerele naturale P şi N şi determină valorile:
a) T , numărul total de cifre care au fost utilizate ı̂n numerotarea tuturor problemelor din
culegere;
b) M , numărul minim de pagini pe care ar trebui să le aibă culegerea, astfel ı̂ncât aceasta să
conţină şi problema numerotată cu N .

Date de intrare

Fişierul culegere.in conţine pe prima linie cele două numere naturale P şi N , separate printr-
un spaţiu, cu semnificaţia din enunţ.

Date de ieşire

Fişierul culegere.out conţine:


a pe prima linie numărul natural T , cu semnificaţia din enunţ;
a pe a doua linie numărul natural M , cu semnificaţia din enunţ.

Restricţii şi precizări

a 1 & P & 16000;


a 1 & N & 2112600000;
a pentru rezolvarea corectă a cerinţei a) se acordă 50% din punctaj;
a pentru rezolvarea corectă a cerinţei b) se acordă 50% din punctaj.

Exemple

334
CAPITOLUL 26. ONI 2012 26.1. CULEGERE 335

culegere.in culegere.out Explicaţii


59 21 Problemele sunt numerotate cu numerele:
4 a 1 (pagina 1)

a 2, 3 (pagina 2)

a 4, 5, 6 (pagina 3)
a 7, 8, 9, 10 (pagina 4)
a 11, 12, 13, 14, 15 (pagina 5).
În scrierea acestor numere s-au folosit 21 de cifre =¿ T 21.
Pentru a conţine şi problema cu numărul 9, culegerea trebuie să
aibă minimum 4 pagini =¿ M 4.

Timp maxim de executare/test: 0.1 secunde


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

26.1.1 Indicaţii de rezolvare


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

O soluţie care obţine 100p poate fi construită pe baza următorului algoritm:


Cerinţa a)
a Se determină numărul total nt de exerciţii pe care le poate conţine culegerea de P pagini:

nt  P ˜ P  1©2

Se observă că nt & 16000 ˜ 16001©2 128008000


a Se determină numărul k de cifre din scrierea zecimală a lui nt (k & 9)

Figura 26.2: culegereIR1

a Se determină numărul T total de cifre utilizate ı̂n scrierea tuturor numerelor naturale nenule
cel mult egale cu nt, observând că:

Figura 26.3: culegereIR2

Figura 26.4: culegereIR3


CAPITOLUL 26. ONI 2012 26.1. CULEGERE 336

Cerinţa b)
a Se determină cel mai mic număr natural M cu proprietatea că 1  2  3  ...  M ' N. Acesta
va reprezenta numărul minim de pagini cerut.

Figura 26.5: culegereIR4

26.1.2 Cod sursă

Listing 26.1.1: culegere 2.cpp


//prof.Carmen Minca

#include <fstream>

using namespace std;

int main()
{ long long nt,p10=1,k=0,M,i,T=0, P,N,x;

ifstream f("culegere.in");
ofstream g("culegere.out");

f>>P>>N;

nt=P*(P+1)/2;
x=nt;
while(x)
{
k++; x/=10;
}

for(i=1;i<k;i++)
{
T=T+i*p10;
p10*=10;
}

T=T*9+(nt-p10+1)*k;
g<<T<<endl;

long long probl=0;


for(M=1;probl+M<N;M++)
probl+=M;

g<<M<<endl;

return 0;
}

Listing 26.1.2: culegere 3.cpp


//prof.Carmen Minca
//solutie care depaseste continutul programei de gimnaziu

#include <fstream>
#include <cmath>

using namespace std;

int main()
{
long long n,p=1,k,i,nrc=0, P,N;

ifstream f("culegere.in");
CAPITOLUL 26. ONI 2012 26.2. CULORI 337

ofstream g("culegere.out");

f>>P>>N;

n=P*(P+1)/2;
k=log10(n*1.0);
k++;

for(i=1;i<k;i++)
{
nrc=nrc+i*p;
p*=10;
}

nrc=nrc*9+(n-p+1)*k;
g<<nrc<<endl;
long long pag=1;
if(N>1)
{
pag=(-1+sqrt(1.+8*N))/2;
if(pag*(pag+1)<2*N)pag++;
}
g<<pag<<endl;
return 0;
}

26.1.3 *Rezolvare detaliată

26.2 culori
Problema 2 - culori 100 de puncte
Fiecare dintre cei N copii, numerotaţi de la 1 la N , primeşte câte un cartonaş colorat. Doamna
dirigintă ı̂i aşează ı̂n cerc, ı̂n ordinea numerotării, ı̂n sens orar. Astfel, fiecare copil are doi vecini,
aşezaţi ı̂n stânga, respectiv ı̂n dreapta lui.
Andrei, pasionat de informatică, asociază fiecărei culori distincte un cod, reprezentat printr-un
număr natural nenul, şi inscripţionează fiecare cartonaş cu codul corespunzător culorii acestuia.
Cerinţe
Scrieţi un program care citeşte două numere naturale N şi K şi determină pentru Andrei:
a) numărul copiilor din cerc care au cartonaşe de aceeaşi culoare cu cartonaşele vecinilor;
b) numărul maxim de cartonaşe de aceeaşi culoare ce sunt deţinute de copiii aşezaţi pe K
poziţii consecutive ı̂n cercul format.
Date de intrare
Fişierul de intrare culori.in conţine pe prima linie numerele naturale N şi K, separate printr-
un spaţiu, şi pe fiecare dintre următoarele N linii, câte un număr natural. Cele N numere
reprezintă codurile culorilor cartonaşelor, ı̂n ordinea numerotării copiilor, ı̂ncepând cu copilul
1.
Date de ieşire
Fişierul de ieşire culori.out conţine:
a pe prima linie, numărul natural determinat la cerinţa a);
a pe a doua linie, numărul natural determinat la cerinţa b).

Restricţii şi precizări


a 2 $ N & 1000;
a 2 $ K & N;
a codurile culorilor sunt numere naturale nenule, consecutive, mai mici sau egale cu 100;
a dacă C este codul maxim asociat unei culori (1 & C & 100) atunci există cel puţin C cartonaşe
care au codurile distincte: 1, 2, 3, ..., C;
a se acordă 30% din punctaj pentru rezolvarea corectă a cerinţei a);
a se acordă 70% din punctaj pentru rezolvarea corectă a cerinţei b).
CAPITOLUL 26. ONI 2012 26.2. CULORI 338

Exemple
culori.in culori.out Explicaţii
85 2
3 4 Sunt doi copii care au, fiecare, car-
1 tonaşe identice cu cei doi vecini
2 (copilul 5 şi copilul 8).
1 Numărul maxim de cartonaşe de
1 aceeaşi culoare deţinute de copiii
1 aşezaţi pe K 5 poziţii consecutive
3 ı̂n cercul format este 4 (dintre copiii
3 2, 3, 4, 5, 6 doar copiii 2, 4, 5 şi 6 au
cartonaşe de culoarea 1). Figura 26.6: culori

Timp maxim de executare/test: 0.1 secunde


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

26.2.1 Indicaţii de rezolvare


prof. Adriana Simulescu, Liceul ”GRIGORE MOISIL” Timişoara

O soluţie se poate obţine astfel:


Codurile culorilor cartonaşelor se citesc ı̂n vectorul x. Pe măsură ce se citesc aceste coduri se
calculează numărul de copii nrc care au cartonaşe de aceeaşi culoare cu cea a cartonaşelor vecinilor
şi numărul de culori c determinând maximul din valorile vectorului x.
Pentru rezolvarea cerinţei b) vectorul x se dublează astfel: xN  1 x1, xN  2 x2,
..., x2 ˜ N  1 xN  1

Figura 26.7: culoriIR1

Calculăm numărul pentru cerinţa b) astfel:


Pentru copiii cu numerele de ordine de la 1 la K am construit vectorul de apariţii ale codurilor
culorilor cartonaşelor ap şi se determină numărul maxim de apariţii maxck.
CAPITOLUL 26. ONI 2012 26.2. CULORI 339

Figura 26.8: culoriIR2

Pentru următoarele secvenţe de k (i 2, 3, ..., N ) copii alăturaţi scad din vectorul de apariţii
prezenţa culorii cartonaşului copilului i  1 şi adun prezenţa culorii cartonaşului copilului i  K  1.
Pentru fiecare secvenţă se actualizează maximul cu elementele din vectorul de apariţii.

Figura 26.9: culoriIR3

26.2.2 Cod sursă

Listing 26.2.1: culori 1.cpp


//prof.Adriana Simulescu
#include<fstream>

using namespace std;

int x[2001],apc[101],N,k,c,nrc,apc1[101],maxck,nrck,nrmax,nrmaxk;

ifstream fin("culori.in");
ofstream fout("culori.out");

void citire()
{int i;
fin>>N>>k;
fin>>x[1];
x[N+1]=x[1];
c=x[1];
fin>>x[2];
x[N+2]=x[2];
if(x[2]>c)c=x[2];

for(i=3;i<=N;i++)
{fin>>x[i];
x[N+i]=x[i];
if(x[i]>c)c=x[i];
if(x[i-1]==x[i-2]&&x[i]==x[i-1])
nrc++;
}
if(x[1]==x[N]&&x[N]==x[N-1])
nrc++;
if(x[1]==x[2]&&x[1]==x[N])
nrc++;
}

int main()
{int i,j;
citire();
maxck=0;
for(i=1;i<=k;i++)
{apc1[x[i]]++;
if(apc1[x[i]]>maxck)
maxck=apc1[x[i]];
CAPITOLUL 26. ONI 2012 26.2. CULORI 340

for(i=2;i<=N;i++)
{apc1[x[i-1]]--;
apc1[x[i+k-1]]++;

for(j=1;j<=c;j++)
if(apc1[j]>maxck)
maxck=apc1[j];

fout<<nrc<<endl<<maxck<<endl;

fin.close();fout.close();
return 0;
}

Listing 26.2.2: culori 2.cpp


//prof.Sanda Junea
#include <fstream>
#include <iostream>

using namespace std;

ifstream f("culori.in");
ofstream g("culori.out");

int n,k,c[2001],a[2001],nrc,maxc,maxcc,c_max;

int main()
{int i,j;
f>>n>>k;
for(i=1;i<=n;i++)
{
f>>c[i];
if(c[i]>c_max)
c_max=c[i];
}
for(i=n+1;i<=n+n;i++)
{
c[i]=c[i-n];
}
for(i=2;i<n;i++)
if(c[i-1]==c[i] && c[i]==c[i+1])nrc++;
if(c[n]==c[n-1] && c[n]==c[1])nrc++;
if(c[1]==c[2] && c[1]==c[n])nrc++;
g<<nrc<<endl;

for(i=1;i<=k;i++)
a[c[i]]++;
maxc=0;
for(i=1;i<=c_max;i++)
if(a[i]>maxc)
maxc=a[i];
for(j=k+1;j<=n+n;j++)
{
a[c[j-k]]--; a[c[j]]++;
if(maxc>maxcc)
maxcc=maxc;
for(i=1;i<=c_max;i++)
if(a[i]>maxc)
maxc=a[i];
}
g<<maxcc;
f.close();g.close();
return 0;
}

26.2.3 *Rezolvare detaliată


CAPITOLUL 26. ONI 2012 26.3. STELE 341

26.3 stele
Problema 3 - stele 100 de puncte
Ţara Numerelor Fermecate era un ţinut minunat!
Până şi stelele de pe cer erau numerotate cu numere
naturale nenule distincte! Stelele făceau parte din
Constelaţia Numerelor şi erau aranjate ı̂ntr-un roi ı̂n
formă de triunghi, pe coloane şi pe rânduri ı̂n cadrul
fiecărei coloane, ca ı̂n desenul alăturat. Stelele cu nu-
merele 1, 3, 7, 13, 21, 31, ..., situate pe rândul marcat
cu ı̂n desen, formau centrul roiului de stele.
Coloanele din roi erau numerotate de la stânga la
dreapta, ı̂ncepând cu numărul 1, iar rândurile din cadrul
fiecărei coloane erau numerotate de jos ı̂n sus, ı̂ncepând
cu numărul 1 (ca ı̂n desen).
Legenda spune că, pe vremuri, trăia ı̂n ţara Nu-
merelor Fermecate o vrăjitoare deosebit de rea şi de put-
ernică. Tot ceea ce atingea această vrăjitoare cu bagheta
Figura 26.10: stele
magică se prefăcea ı̂n stană de piatră. Ea ı̂şi propusese
să-i preschimbe ı̂n statui pe toţi copiii din ţinut.
În acea vreme ı̂nvăţa la şcoală Numerel, un băieţel vrednic şi curajos. Îl iubea toată lumea!
Zâna Cea Bună s-a hotărât să ı̂l ajute pe Numerel. Aceasta i-a promis inimosului băiat o baghetă
magică, pe care Numerel să o folosească ı̂mpotriva vrăjitoarei. Pentru a primi bagheta, Numerel
a cules pulberea celei de a K-a stele situată ı̂n centrul roiului pentru a i-o da Zânei.
Dar aventura a continuat! Zâna locuia pe steaua cu numărul N , iar Numerel a trebuit să
găsească adresa acesteia, respectiv numărul coloanei, precum şi numărul rândului din coloană, pe
care se găsea această stea.
Aventura voastră abia acum ı̂ncepe!
Cerinţe
Scrieţi un program care citeşte două numere naturale K şi N şi determină pentru Numerel:
a) numărul celei de a K-a stele situată ı̂n centrul roiului;
b) coloana şi rândul (din această coloană) corespunzătoare adresei Zânei.
Date de intrare
Fişierul de intrare stele.in conţine pe prima linie cele două numere naturale, K şi N , separate
printr-un spaţiu.
Date de ieşire
Fişierul de ieşire stele.out conţine:
a pe prima linie, numărul natural determinat la punctul a);
a pe a doua linie, coloana şi rândul determinate la punctul b), ı̂n această ordine, separate
printr-un spaţiu.
Restricţii şi precizări
a 0 $ K & 60000;
a 0 $ N & 60000;
a se acordă 20% din punctaj pentru rezolvarea corectă a cerinţei a);
a se acordă 80% din punctaj pentru rezolvarea corectă a cerinţei b).

Exemple
stele.in stele.out Explicaţii
53 21 Primele K 5 stele din centrul roiului au numerele: 1, 3, 7, 13, 21 .
22 Steaua cu numărul N 3 se află pe coloana 2 , rândul 2 .
25 335 Primele K 2 stele din centru roiului au numerele: 1, 3 .
Steaua cu numărul N 5 se află pe coloana 3 , rândul 5 .
Timp maxim de executare/test: 0.5 secunde
Memorie: total 2 MB din care pentru stivă 2 MB
Dimensiune maximă a sursei: 10 KB
CAPITOLUL 26. ONI 2012 26.3. STELE 342

26.3.1 Indicaţii de rezolvare


prof. Gina Balacea, Colegiul Naţional ”Vasile Alecsandri” - Galaţi

O soluţie pentru 100p se poate obţine astfel:


a Se aranjează numerele 1, 2, 3, 4, ... ı̂n formă de triunghi, astfel:

Figura 26.11: steleIR

a Se observă că numărul de jos al fiecărei coloane i (nr. stelei de pe rândul 1, coloana i) este
2
pătratul perfect al numărului coloanei = i .
2
a Toate numerele de pe linia din mijloc se obţin cu formula i  i  1, unde i este numărul
2 2 2
coloanei: 3 2  2  1; 7 3  3  1; 13 4  4  1. Prin urmare, al K-lea element se determină
2
cu formula K  K  1.
a Dat fiind un număr N , se poate găsi numărul rândului şi al coloanei din triunghi, după cum
urmează:
Coloana = cel mai mic număr natural al cărui pătrat perfect este mai mare sau egal ca N .
2
Rândul = Coloana  N  1.
De exemplu, pentru N 6, avem : 2 $ 6 & 3 . Prin urmare coloana este 3 iar rândul este
2 2
2
3 31 7
a Nu este necesar ca datele să fie memorate ı̂ntr-un tabel.

26.3.2 Cod sursă

Listing 26.3.1: stele 1.cpp


//prof.Gina Balacea
#include<cstdio>

using namespace std;

unsigned long long i,j,n,K,N;

int main()
{FILE *f,*g;
f=fopen("stele.in","r");
g=fopen("stele.out","w");
fscanf(f,"%I64d %I64d",&K,&n);
fprintf(g,"%I64d\n",K*K-K+1);
N=1;
while(N*N<n) N++;
fprintf(g,"%I64d %I64d\n",N,N*N-n+1);
fclose(f);
fclose(g);
return 0;
}
CAPITOLUL 26. ONI 2012 26.3. STELE 343

Listing 26.3.2: stele 2.cpp


//prof.Liliana Chira
#include<cstdio>
#include<cmath>
int main()
{
unsigned long long c,l,N,K,p;

freopen("stele.in","r",stdin);
freopen("stele.out","w",stdout);

scanf("%I64d%I64d",&K,&N);
printf("%I64d\n",K*K-K+1);

p=(int)sqrt(N);
if(N==p*p)
c=p;
else c=p+1;
l=c*c-N+1;
printf("%I64d %I64d\n",c,l);

printf("\n");
return 0;
}

Listing 26.3.3: stele 3.cpp


//prof.Sanda Junea
#include<fstream>
#include<iostream>

using namespace std;

ifstream f("stele.in");
ofstream g("stele.out");

int k,n;
int main()
{
int i;
unsigned long long x;
f>>k>>n;
x=(unsigned long long)(k-1)*(k-1)+(k*k-(k-1)*(k-1)+1)/2;
g<<x<<endl;
i=1;
while(i*i<n)i++;
if(i*i==n)
g<<i<<" "<<1<<endl;
else
g<<i<<" "<<(i*i-n+1);
return 0;
}

26.3.3 *Rezolvare detaliată


Capitolul 27

ONI 2011

27.1 Fagure
Problema 1 - Fagure 100 de puncte
Bunicul lui Ionel este apicultor şi din acest motiv Ionel a vrut să combine pasiunea lui pentru
numere cu meseria bunicului. El a aşezat n numere sub forma unui şir de nr faguri, numerotaţi
de la 1 la nr. În cadrul unui fagure numerele au fost aşezate ı̂n sensul rotirii acelor de ceasornic.
Pe latura comună a doi faguri el aşează numai două numere.
Mihuţ, fratele lui Ionel, ca să facă o glumă a amestecat numerele din faguri astfel: a luat
cel mai mare număr prim din al doilea fagure şi l-a schimbat cu cel mai mare număr prim din
penultimul fagure (cu numărul de ordine nr  1), apoi a luat cel mai mare număr prim din al
treilea fagure şi l-a schimbat cu cel mai mare număr prim din antepenultimul fagure (cu numărul
de ordine nr  2), continuă aşa până la mijlocul şirului de faguri.
Mihuţ nu s-a atins de numerele care făceau parte din latura comună a doi faguri alăturaţi.
Dacă ı̂n cadrul unui fagure Mihuţ nu a găsit un număr prim ce poate fi mutat, atunci nu a realizat
interschimbarea ı̂n cadrul perechii de faguri corespunzătoare.
Exemplu:
Ionel a plecat de la 18 numere:
2 11 37 14 5 12 17 101 97 26 3 19 13 5 130 7 213 907
şi le-a aşezat conform modelului din figura 1. Modelul din figura 2 a rezultat după ce Mihuţ
a amestecat numerele. Mihuţ nu are voie să amestece numerele: 11, 37, 101, 97, 19, 13.

Figura 27.1: fagure

Cerinţe

Scrieţi un program care să citească informaţiile din fişierul de intrare fagure.in şi care să
determine:
a) numărul fagurilor pe care a reuşit Ionel să ı̂i construiască;
b) cel mai mic număr de ordine al fagurelui pe care Ionel a plasat valoarea x, ı̂nainte de
amestecarea realizată de Mihuţ;
c) pentru un număr natural k, citit din fişier, care este noul număr plasat de Mihuţ pe fagurele
cu numărul de ordine k. Dacă Mihuţ nu s-a atins de numerele de pe fagurele k se va scrie valoarea
0.

Date de intrare

Fişierul de intrare fagure.in conţine trei linii:


- pe prima linie se află perechea de numere naturale n şi k separate printr-un spaţiu cu
semnificaţiile din enunţ;

344
CAPITOLUL 27. ONI 2011 27.1. FAGURE 345

- a doua linie conţine cele n numere naturale nenule mai mici decât 32000, separate prin câte
un spaţiu, cu care Ionel a construit fagurii;
- pe ultima linie din fişier se află numărul natural x cu semnificaţia din enunţ. Valoarea x se
regăseşte ı̂n fişier şi pe linia a doua.

Date de ieşire

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


a) pe prima linie se va scrie numărul natural nr ce reprezintă numărul fagurilor construiţi de
Ionel;
b) pe a doua linie se va scrie numărul de ordine minim al fagurelui pe care a fost plasată
valoarea x. ı̂n cazul ı̂n care valoarea x se găseşte pe latura comună a doi faguri alăturaţi, se vor
afişa numerele de ordine ale celor doi faguri ı̂n ordinea crescătoare a valorilor, separate printr-un
spaţiu;
c) pe a treia linie se va scrie numărul pe care Mihuţ l-a plasat pe fagurele k după ce a amestecat
numerele sau valoarea 0 dacă nu s-a atins de fagurele k.

Restricţii şi precizări

a Pentru toate testele, ultimul fagure construit de Ionel, este format din 6 numere.
a 10 & n $ 10000
a 2 & k & cu numărul de ordine al fagurelui din mijloc
a 1 & x $ 30000
a Pentru rezolvarea cerinţei a) se acordă 30% din punctaj, pentru rezolvarea cerinţei b) 40%
din punctaj şi pentru rezolvarea cerinţei c) 30% din punctaj.

Exemple
fagure.in fagure.out Explicaţii
18 2 4 4 reprezintă numărul
2 11 37 14 5 12 17 101 97 26 3 19 13 5 130 7 213 907 23 fagurilor construiţi de
101 5 Ionel; 101 aparţine
fagurilor 2 şi 3; 5
reprezintă valoarea
plasată de Mihuţ pe
fagurele 2.

Timp maxim de executare/test: 1.0 secunde

27.1.1 Indicaţii de rezolvare


prof. Daniela Tarasă - Colegiul Naţional ”Gheorghe Vrănceanu” Bacău
prof. Gavril Petru Florin - Colegiul Naţional ”Roman Vodă” Roman

Punctul a): Fiecare fagure conţine două valori comune cu fagurele anterior la care se adaugă
alte patru valori. Numărul fagurilor se obţine cu următoarea formulă:
a nr n  2©4;
Punctul b): Pentru a determina numărul minim de ordine al fagurelui pe care se afla iniţial
valoarea x, se va realiza o căutare secvenţială, determinând poziţia primei apariţii a valorii x.
Dacă valoarea x este găsită pe latura comuna a doi faguri, atunci se afişează numerele de ordine
a celor doi faguri (ı̂n ordinea crescătoare a lor).
Se tratează separat cazul ı̂n care valoarea x apare ı̂n primul fagure sau ı̂n ultimul.
Punctul c): pentru a determina valoarea rezultată după amestecare, se determină:
a numărul de ordine al fagurelui simetric cu fagurele k;
a primalitatea valorilor ce pot fi amestecate;
a cea mai mare dintre valorile prime ce pot fi amestecate.

În cazul ı̂n care fagurele k sau nr  k  1 nu conţine valori prime ce pot fi amestecate, se va
scrie ı̂n fişierul de ieşire valoarea 0.
CAPITOLUL 27. ONI 2011 27.1. FAGURE 346

27.1.2 Cod sursă

Listing 27.1.1: fagure.cpp


#include<fstream>
#include<math.h>

using namespace std;

ifstream f("fagure.in");
ofstream g("fagure.out");

int v[10001];

int prim (int x)


{
long d;
if(x<2) return 0;
for(d=2;d<=sqrt(x);d++)
if(x%d==0) return 0;
return 1;
}

int main()
{ int n,i,nr_fag,k,gasit=0,grupa,nr,poz,fag,x1,x2,x;
f>>n>>k;
for(i=1;i<=n;i++)
f>>v[i];
f>>x;

// cerinta 1 calculam si afisam numarul fagurilor construiti


nr_fag=(n-6)/4+1;
g<<nr_fag<<’\n’;

// cerinta 2 cautam prima aparitie a lui x in v


for(i=1;i<=n &&!gasit;i++)
if(v[i]==x) {gasit=1;poz=i;}

// verificam si afisam numarul sau numerele fagurilor din care face parte x
if(poz<=6)
if(poz==2 ||poz==3) g<<1<<’ ’<<2<<’\n’;
else g<<1<<’\n’;

else
if(poz==n-1 || poz==n-2) g<<nr_fag<<’\n’;
else
if((poz%4==0 || poz%4==1) && poz/4<nr_fag)
g<<poz/4<<’ ’<<poz/4+1<<’\n’;
else
if(poz%4==3) g<<poz/4+1<<’\n’;
else g<<poz/4<<’\n’;

// cerinta 3
// fagurele pe care s-a gasit initial numarul prim este
fag=nr_fag+1-k;

// discutam despre pozitiile fag*4-1, fag*4+2 pentru ca de pozitiile


// fag*4 si fag*4+1 nu avem voie sa ne atingem
// notam cu x1 si x2 pozitiile pe care le verificam
x1=fag*4-1;
x2=fag*4+2;

if(prim(v[x1])&& prim(v[x2]))
if(v[x1]>v[x2]) g<<v[x1]<<’\n’;
else g<<v[x2]<<’\n’;
else
{
if(prim(v[x1])) g<<v[x1]<<’\n’;

if (prim(v[x2])) g<<v[x2]<<’\n’;
}

if(prim(v[x1])==0 && prim(v[x2])==0)


CAPITOLUL 27. ONI 2011 27.2. GOE 347

g<<0<<’\n’;

f.close();
g.close();
return 0;
}

27.1.3 *Rezolvare detaliată

27.2 Goe
Problema 2 - Goe 100 de puncte
Goe este un copil drăgălaş, dar tare leneş.
Nu ı̂i place nici să scrie, nici să numere. Cu
greu a fost convins de mama sa să ı̂nveţe cifrele,
dar de scris tot nu poate să le scrie pe toate. Nu
ı̂i plac cifrele 2, 4, 5 şi 7, iar cifra 6 o ı̂ncurcă cu
9 şi invers. Şi asta nu este tot. Când mama sa ı̂i
dă să copieze numere, pentru a exersa scrierea
cifrelor, el le scrie ı̂n oglindă, adică scrie cifrele
ı̂n ordinea inversă. De exemplu numărul 138
va fi scris de Goe 831.
Mama lui Goe scrie ı̂n fiecare zi, ı̂n ordine
crescătoare, câte 9 numere naturale, sărind Figura 27.2: Goe
ı̂nsă peste orice număr divizibil cu 10, ca ı̂n Figura 1. Goe copiază zilnic aceste numere. Din
păcate, el nu ı̂şi ı̂ndreaptă niciuna dintre greşeli: copiază numerele scriindu-le oglindite, nu scrie
numerele care conţin cifrele 2, 4, 5 şi 7 şi ı̂nlocuieşte, ı̂n continuare cifra 6 cu 9 şi invers (vezi
Figura 2).

Cerinţe

Scrieţi un program care să citească numerele naturale nenule k, p şi n şi care să determine:
a) Numărul de numere scrise de Goe ı̂n primele k zile;
b) Al p-lea palindrom scris corect de Goe; un număr este palindrom dacă este egal cu oglinditul
său;
c) Cel mai mare număr scris de Goe ı̂n primele n zile.

Date de intrare

Fişierul goe.in conţine o singură linie pe care sunt scrise trei numere naturale k, p şi n, separate
prin câte un spaţiu.

Date de ieşire

Fişierul de ieşire goe.out va conţine 3 linii:


a) pe prima linie, se va scrie numărul de numere scrise de Goe ı̂n primele k zile;
b) pe a doua linie, se va scrie un număr natural reprezentând al p-lea palindrom scris corect
de Goe;
c) pe a treia linie, se va scrie cel mai mare număr scris de Goe ı̂n primele n zile.

Restricţii şi precizări

a 1 & k & 100000


a 1 & p & 750
a 1 & n & 32000000
Pentru rezolvarea cerinţei a) se acordă 40% din punctaj, pentru cerinţa b) 30% din punctaj şi
pentru cerinţa c) 30% din punctaj.
CAPITOLUL 27. ONI 2011 27.2. GOE 348

Exemple
goe.in goe.out Explicaţii
5 15 15 numere a scris Goe ı̂n primele 5 zile.
8 111 Primele 8 palindroame scrise corect de Goe sunt:
3 91 1, 3, 8, 11, 33, 88, 101, 111.
Cel mai mare număr scris de Goe ı̂n primele 3 zile este 91.

Timp maxim de executare/test: 1.0 secunde

27.2.1 Indicaţii de rezolvare


prof. Ana Întuneric, C.N. ”Ferdinand I” Bacău
prof. Dana Lica, C.N. ”I.L.Caragiale” Ploieşti

Cerinţa a):
Goe scrie ı̂ntr-o zi 5 numere sau niciunul. Este suficient să se numere câte dintre primele k
numere naturale strict pozitive (zile) nu au ı̂n componenţă una dintre cifrele 2, 4, 5 sau 7 şi să se
ı̂nmulţească acest număr cu 5.
Cerinţa b):
Un palindrom scris corect de Goe conţine doar cifrele 0, 1, 3 şi 8. El scrie 3 palindroame cu o
singură cifră, 3 palindroame cu 2 cifre, 9 palindroame cu 3 cifre, 12 palindroame cu 12 cifre etc.
Deci numărul de palindroame se multiplică cu 4 de fiecare dată când se trece de la un palindrom
cu un număr par de cifre la unul cu un număr impar de cifre (2c 2c  1).
Se determină iniţial nrc, numărul de cifre pe care le are cel de-al p-lea palindrom, apoi se con-
struiesc, pe rând, palindroamele de nrc cifre până la cel de-al p-lea palindrom. Pentru construcţie
se poate utiliza scrierea ı̂n baza 4, ı̂nlocuind ulterior cifra 2 cu 3 şi cifra 3 cu 8 (0 0, 1 1,
2 3, 3 8).
Cerinţa c):
Se observă că numărul maxim scris de Goe are prima cifră 9. Pentru a determina celelalte
cifre, se memorează cifrele numărul n ı̂ntr-un vector şi se prelucrează pe rând cifrele sale. Vectorul
se afişează ı̂n mod invers.

27.2.2 Cod sursă

Listing 27.2.1: GOE.CPP


#include <fstream>
#include <math.h>

using namespace std;

ifstream f("goe.in");
ofstream g("goe.out");

long n,k,p,bune,max,nrn,put,x,aux,nrbune,ok,d;
int s[11];
long v[11],sum,power;
long i,j,nr,nrcif,posib,nrc,schimbat,r,l,inv,pn,un,copie,cifra;

int main()
{
f>>k>>p>>n;
//a)**************************
nrn=0;
for(i=1;i<=k;i++)
{
aux=i-1;ok=1;
while(aux>0)
{
if(aux % 10 == 2 || aux % 10 == 4 ||
aux % 10 == 5 || aux % 10 == 7) ok=0;
aux/=10;
}
CAPITOLUL 27. ONI 2011 27.2. GOE 349

if(ok)nrn=nrn+5;
}
g<<nrn<<’\n’;

//b)**************************
nrc=1; d=3; //d reprezinta cate numere palindroame de nrc cifre exista
while(p>d)
{
p=p-d;
nrc++;
if(nrc%2) d=d*4;
}

//d este modificat o data la 2 pasi, intrucat numarul de palindroame este


// acelasi pentru o lungime de 2*k si 2*k+1
/*in p avem al catelea numar de nrc cifre trebuie sa determinam
in c construim palindromul, dar in baza 4, pentru a face iarasi o
bijectie intre baza 4 si o baza cu cifrele 0,1,3,8 (singurele cifre cu
care se pot construi palindroame)
*/
v[1]=1; v[nrc]=1; d=d/3; p--;
for(i=2;i<nrc;i++) v[i]=0;

i=1;
while(d>0)
{
v[i]=v[nrc-i+1]=v[i]+p/d;
p=p%d;
d/=4;
i++;
}

//trecem numarul din baza 4 in scrierea necesara


for(i=1;i<=nrc;i++)
{
if(v[i]==2) v[i]=3;
else
if(v[i]==3) v[i]=8;
}

for(i=1;i<=nrc;i++) g<<v[i];
g<<’\n’;

//c)**************************
nrc=log10(n)+1;
i=nrc;

while(n>0)
{
s[i]=n%10;
n=n/10;
i--;
}

i=1;
if(s[1]==1)
{
i++;
while(i<=nrc && s[i]==0)i++;
}

if(i==nrc+1)
{
for(j=1;j<=nrc;j++)g<<’9’;
g<<’\n’;
}
else
{
g<<’9’;
if(s[i]>1 && i<nrc && s[i+1]<6 || s[i]==1 && s[i+1]<6 || s[i]!=9)
{
s[i]--;
if(s[i]==2 || s[i]==4 || s[i]==5 || s[i]==7) s[i]--;
if(s[i]==4) s[i]=3;
}
CAPITOLUL 27. ONI 2011 27.3. PĂPUŞA 350

i++;
for(;i<=nrc;i++) s[i]=9;
for(i=nrc;i>=1;i--)
{
if(s[i]==6) s[i]=9;
g<<s[i];
}

g<<’\n’;
}

f.close();
g.close();
return 0;
}

27.2.3 *Rezolvare detaliată

27.3 Păpuşa
Problema 3 - Păpuşa 100 de puncte
Păpuşa Matrioşka este o jucărie din lemn,
goală pe dinăuntru. De aceea, ı̂n interiorul
său poate fi introdusă oricare altă păpuşă Ma-
trioşka de ı̂nălţime mai mică.
La un magazin de suveniruri se găsesc n Figura 27.3: papusa
păpuşi Matrioşka aşezate ı̂n şir, ı̂n număr egal, pe două rafturi alăturate. Pe raftul din stânga
sunt expuse prima jumătate de păpuşi, situate ı̂n şir pe poziţiile 1, 2, ...., n©2, iar raftul din
dreapta ultima jumătate de păpuşi, situate ı̂n şir pe poziţiile n©2  1, ..., n. Prin notaţia n©2
se ı̂nţelege jumătatea numărului n.
Ana şi Iulia vor să cumpere cât mai multe păpuşi Matrioşka, dar tatăl lor le impune următoarele
reguli:
a Iulia are voie să aleagă păpuşi din raftul din stânga, iar Ana din raftul din dreapta
a Dacă de pe un raft se cumpără mai multe păpuşi, atunci ele se vor afla pe poziţii consecutive
pe raft;
a Prima păpuşă cumpărată de o fetiţă va avea ı̂nălţimea mai mică decât cea de a doua, a
doua decât cea de a treia şi aşa mai departe astfel ı̂ncât fiecare păpuşă să poate fi introdusă ı̂n
următoarea păpuşă cumpărată;
a Ultimele păpuşi cumpărate trebuie să se situeze doar la capetele rafturilor şi ı̂n plus:
- dacă ultima păpuşă cumpărată de Iulia este pe poziţia 1 atunci ultima păpuşă cumpărată de
Ana trebuie să fie pe poziţia n;
- dacă ultima păpuşă cumpărată de Iulia este pe poziţia n©2 atunci ultima păpuşă cumpărată
de Ana trebuie să fie pe poziţia n©2  1.
Pentru a putea să aleagă cât mai multe păpuşi respectând regulile impuse de tatăl lor, fetiţelor
li se permite să execute ı̂n acelaşi timp următoarea operaţie, până se revine la aşezarea iniţială a
păpuşilor:
a Iulia mută păpuşa de pe poziţia 1 pe poziţia n©2, deplasând cu o poziţie spre stânga toate
celelalte păpuşi din raftul său;
a Ana mută păpuşa de pe poziţia n pe poziţia n©2  1, deplasând cu o poziţie spre dreapta
toate celelalte păpuşi din raftul său;

Cerinţe

Pentru a le ajuta pe Iulia şi Ana să achiziţioneze ı̂mpreună un număr maxim de păpuşi, scrieţi
un program care citeşte un număr natural n şi ı̂nălţimile celor n păpuşi şi determină:
a) numărul M de operaţii efectuate concomitent de fetiţe;
b) numărul maxim P de păpuşi care vor fi cumpărate.

Date de intrare
CAPITOLUL 27. ONI 2011 27.3. PĂPUŞA 351

Fişierul text papusa.in conţine pe prima linie un număr natural par n, reprezentând numărul
de păpuşi. Pe linia a doua sunt n numere naturale separate prin câte un spaţiu, reprezentând
ı̂nălţimile păpuşilor situate pe cele două rafturi, ı̂n ordine de la poziţia 1 la n.

Date de ieşire

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


a) pe prima linie, numărul natural M ;
b) pe a doua linie, numărul natural P .

Restricţii şi precizări

a 2 & n & 1000, n este număr par


a 1 & ı̂nălţimile păpuşilor & 10000
a Dacă numărul maxim de păpuşi se obţine fără a face operaţii de mutare atunci M 0
a Pentru toate testele de intrare există o singură configuraţie pentru care se poate cumpăra
un număr maxim de păpuşi
a Pentru rezolvarea cerinţei a) se acordă 40% din punctaj, pentru rezolvarea cerinţei b) 60%
din punctaj

Exemple
papusa.in papusa.out Explicaţii
8 2 Raftul Iuliei conţine păpuşile de ı̂nălţimi 5, 7, 2, 4, iar al Anei
5 7 2 4 6 10 14 8 7 păpuşile de ı̂nălţimi 6, 10, 14, 8. Pe această aşezare Iulia şi
Ana pot cumpăra păpuşile de ı̂nălţime 2 4 6 sau 5 8. Se pot
cumpăra cel mult 3 păpuşi.
Configuraţia obţinută după prima operaţie de mutare este: 7
2 4 5 8 6 10 14
Pe această aşezare Iulia şi Ana pot cumpăra păpuşile de
ı̂nălţime 2 4 5 6 8 sau 2 7 6 10 14. Se pot cumpăra cel mult 5
păpuşi.
Configuraţia obţinută după a doua operaţie 2 4 5 7 14 8 6
10. Pe această aşezare Iulia şi Ana pot cumpăra păpuşile cu
ı̂nălţimile 2 4 5 7 6 8 14 sau 2 6 10. Deci se pot cumpăra cel
mult 7 păpuşi.
Configuraţia obţinută după a treia operaţie 4 5 7 2 10 14 8 6.
Pe această aşezare Iulia şi Ana pot cumpăra păpuşile cu
ı̂nălţimile 2 10 sau 4 6. Deci se pot cumpăra cel mult 2 păpuşi.
Numărul maxim de păpuşi cumpărate este 7 şi se obţine după
a doua operaţie de mutare.

Timp maxim de executare/test: 1.0 secunde

27.3.1 Indicaţii de rezolvare


prof. Susana Gălăţan

Se generează concomitent toate permutările circulare ale primei jumătăţi a şirului, respectiv
ale celei de a doua jumătăţi. Pentru fiecare permutare, se determină următoarele valori:
L1 - lungimea secvenţei descrescătoare care ı̂ncepe la poziţia 1
L2 - lungimea secvenţei crescătoare care se termină pe poziţia n
L3 - lungimea secvenţei crescătoare care se termină pe poziţia n©2
L4 - lungimea secvenţei descrescătoare care ı̂ncepe pe poziţia n©2  1
Numărul maxim de păpuşi cumpărate este maximul dintre sumele L1  L2 şi L3  L4.
Numărul de operaţii cerute este egal cu numărul de ordine a permutării pentru care se obţine
numărul maxim de păpuşi.
CAPITOLUL 27. ONI 2011 27.3. PĂPUŞA 352

27.3.2 Cod sursă

Listing 27.3.1: papusa.cpp


//Suzana Galatan
#include <fstream>

using namespace std;

int main()
{
ifstream fin("papusa.in");
ofstream fout("papusa.out");

int n, x[1001];
int l11, l22, ok = 1;

fin >> n;

int i, pas = 0, l1, l2, aux1, aux2, secv = 0, perm = 0;


for(i = 1; i <= n; i++)
fin >> x[i];

while(pas < n/2)


{

l1 = l2 = 1;
l11 = 1, l22 = 1;
ok = 1;
for(i = n/2-1; i > 0 && ok; i--)
if(x[i+1] > x[i])l1++;
else ok = 0;

ok = 1;
for(i = n/2+2; i <= n&&ok; i++)
if(x[i-1] > x[i])l2++;
else ok = 0;

if(secv < (l1+l2))secv = l1+l2, perm = pas;

ok = 1;
for(i = n-1; i >= n/2 && ok; i--)
if(x[i+1] > x[i])l22++;
else ok = 0;

ok = 1;
for(i = 2; i <= n/2 && ok; i++)
if(x[i-1] > x[i])l11++;
else ok = 0;

if(secv <(l11+l22))secv =l11+l22, perm = pas;

pas++;
aux1 = x[1];
aux2 = x[n];
for(i = 1; i < n/2; i++)
{
x[i] = x[i+1];
x[n-i + 1] = x[n-i];
}

x[n/2] = aux1;
x[n/2+1] = aux2;
}

fout << perm<<"\n"<< secv<<"\n";


fin.close();
fout.close();
return 0;
}
CAPITOLUL 27. ONI 2011 27.3. PĂPUŞA 353

27.3.3 *Rezolvare detaliată


Capitolul 28

ONI 2010

28.1 cluburi
Problema 1 - cluburi 100 de puncte
La şcoala Iuliei, ı̂n clasa a V-a sunt n elevi. Pentru că aşa e moda la această şcoală, fiecare
dintre cei n copii şi-a creat câte un club.
Fiecare club are iniţial un singur membru: copilul care l-a creat. Copiii au hotărât că numărul
membrilor unui club poate să crească prin unificarea cu un alt club după următoarea regulă:
două cluburi se pot unifica dacă au acelaşi număr de membri. Prin unificare, unul dintre cluburi
continuă să existe, iar celălalt se desfiinţează. Clubul care continuă să existe preia toţi membrii
clubului care se desfiinţează.
Deoarece elevii se distrează mai bine atunci când clubul are mai mulţi membri, ei au hotărât
să unifice cluburile după regula de mai sus, cât timp unificarea este posibilă.

Cerinţe

Scrieţi un program care să citească numărul natural n şi care să determine:
a) cel mai mic număr natural k de cluburi care continuă să existe după ce s-au produs toate
unificările;
b) pentru fiecare dintre cluburi, numărul de membri.

Date de intrare

Fişierul de intrare cluburi.in conţine o singură linie pe care este scris un număr natural nenul
n, reprezentând numărul de elevi din clasa a V-a.

Date de ieşire

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


- pe prima linie un număr natural k, reprezentând cel mai mic număr de cluburi care continuă
să existe după ce s-au produs toate unificările
- pe a doua linie, k numere naturale nenule, separate prin câte un spaţiu, reprezentând numărul
de membri ai fiecărui club, ı̂n ordinea crescătoare a numărului de membri.

Restricţii şi precizări

a 1 & n & 30000


a În cazul ı̂n care numărul elevilor este impar se consideră că elevul rămas singur formează un
club.
a Pentru fiecare test de intrare se poate determina cel puţin un club.
a Se acordă punctaje parţiale: cerinţa a) 30% din punctaj, cerinţa b) 70% din punctaj

354
CAPITOLUL 28. ONI 2010 28.1. CLUBURI 355

Exemple:
cluburi.in cluburi.out Explicaţii
7 3 6 elevi formează 3 cluburi având fiecare câte 2 membri, iar elevul
124 rămas formează la rândul lui un club (cu un singur membru).
Apoi 2 dintre cluburile cu câte 2 membri se unesc şi formează un
singur club cu 4 membri, deci sunt 3 cluburi: 1 cu un membru, 1
cu 2 membri şi 1 cu 4 membri.
24 2 Iniţial se formează 12 cluburi cu câte 2 membri, apoi 6 cu câte 4
8 16 membri.
Din cele 6 cluburi se vor forma apoi 3 cu câte 8 membri.
Două dintre cluburile cu 8 membri se unesc formand unul cu 16
membri. ı̂n final rămân 2 cluburi, unul cu 8, iar celălalt cu 16
membri.

Timp maxim de executare/test: 1.0 secunde

28.1.1 Indicaţii de rezolvare


prof. Gălăţan Suzana - Inspectoratul şcolar Judeţean Bistriţa-Năsăud

Descrierea soluţiei
Numărul de cluburi care se formează este egal cu suma resturilor obţinute prin ı̂mpărţirea
repetată a numărului n la 2, atât timp cât n este diferit de 0.

Figura 28.1: cluburiIR1

k1
Numărul de membri ai fiecărui club este egal cu 2 , unde k este egal cu numărul de ı̂mpărţiri
la 2 al lui n şi la acel pas n%2 este egal cu 1.

Figura 28.2: cluburiIR2

Exemplu: Pentru n 13 se obţine:


r 1 0 1 1
k1 0 1 2 3
2 2 2 2 2
Număr membri 1 - 4 8
CAPITOLUL 28. ONI 2010 28.1. CLUBURI 356

Figura 28.3: cluburiIR3

28.1.2 Cod sursă

Listing 28.1.1: cluburi CS.cpp


//autor Sichim Cristina - 100p

#include<fstream>
#include <cstring>

using namespace std;

int main()
{ int n,k=0,i;
long p=1;
char s[50];

ifstream f("cluburi.in");
ofstream g("cluburi.out");

f>>n;
itoa(n,s,2);

for(i=0;i<strlen(s);i++)
if(s[i]==’1’)k++;

g<<k<<’\n’;

for(i=strlen(s)-1;i>=0;i--)
{
if(s[i]==’1’) g<<p<<’ ’;
p=p*2;
}

g<<’\n’;

f.close();g.close();
return 0;
}

Listing 28.1.2: cluburi fara vectori.CPP


CAPITOLUL 28. ONI 2010 28.1. CLUBURI 357

//autor Suzana Galatan


#include <fstream>

using namespace std;

ifstream fin("cluburi.in");
ofstream fout("cluburi.out");

int main()
{
int N;
fin >> N ;
int k = 0, c = N, cant = 1;

int x = N;
while(x)
{
if(x % 2 == 1)k++;
x = x/2;
}

fout << k <<"\n";

while(c)
{
if(c % 2 == 0)
c = c/2, cant = cant * 2;
else
{
c = c/2;
fout << cant <<" ";
cant = cant * 2;
}
}

fout << "\n";

fin.close();
fout.close();
return 0;
}

Listing 28.1.3: cluburi SG.CPP


//autor Suzana Galatan -100p
#include <fstream>
using namespace std;

ifstream fin("cluburi.in");
ofstream fout("cluburi.out");
int main()
{
long int N;
fin >> N ;

long int nr = 0, c = N, cant = 1, gasit = 0, c1;


int x[100] = {0};

while(c)
{
if(c % 2 == 0)
c = c/2, cant = cant * 2;
else
{
/* if(gasit == 0)
{
c1 = cant;
gasit = 1;
} */
nr = nr + 1;
c = c/2;
x[nr] = cant;
cant = cant * 2;
}
}
CAPITOLUL 28. ONI 2010 28.2. DOMINO 358

fout << nr <<"\n";

// fout << c1 << " " << cant/ 2 <<"\n";

for(int i = 1; i < nr; i++)


fout << x[i] << " ";

fout << x[nr] << ’\n’;

fin.close();
fout.close();
return 0;
}

28.1.3 *Rezolvare detaliată

28.2 domino
Problema 2 - domino 100 de puncte
Ionel are n piese de domino de diverse ı̂nălţimi. În joacă, el aşează piesele vertical ı̂ntr-un şir
(pe o riglă gradată), la distanţe nu neapărat egale una faţă de alta. Ionel atinge prima piesă,
aceasta cade şi poate antrena ı̂n cădere după ea şi alte piese din şir. Dacă mai rămân piese ı̂n
picioare, el merge la prima piesă care nu a căzut şi o atinge. Aceasta cade şi poate antrena ı̂n
cădere după ea şi alte piese. Continuă procedeul până când nu mai rămâne nicio piesă ı̂n picioare.

Cerinţe

Scrieţi un program care să citească numărul natural n de piese, poziţia pe riglă şi ı̂nălţimea
fiecărei piese, ı̂n această ordine, şi care să determine numărul minim necesar de atingeri ale pieselor
astfel ı̂ncât să cadă toate piesele de domino precum şi numărul maxim de piese răsturnate la o
singură atingere.

Date de intrare

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


- pe prima linie numărul natural n
- pe fiecare dintre următoarele n linii câte două numere naturale p şi h, separate printr-un
spaţiu, p reprezentând pozitia piesei pe riglă şi h ı̂nălţimea piesei de domino, ı̂n acestă ordine.

Date de ieşire

Fişierul de ieşire domino.out va conţine o singură linie pe care sunt scrise două numere
naturale a şi b, ı̂n această ordine, separate printr-un spaţiu, a reprezentând numărul minim necesar
de atingeri ale pieselor, iar b numărul maxim de piese ce sunt răsturnate la o singură atingere a
unei piese.

Restricţii şi precizări

aNumerele n, p şi h sunt numere naturale nenule


a1 & n & 1000; 1 & p & 5000; 1 & h & 5000
a O piesă de domino aflată pe pozitia p de ı̂nălţime h răstoarnă piese până la poziţia p  h
inclusiv.
a În fişierul de intrare datele sunt ı̂n ordinea crescătoare a poziţiei pieselor de domino.
a Pe o poziţie de pe riglă se poate afla o singură piesă de domino.
a Ionel ı̂ncepe ı̂ntotdeauna cu piesa aşezată la poziţia cea mai mică
a Se acordă 50 din punctaj pentru rezolvarea corectă a fiecărei cerinţe.
CAPITOLUL 28. ONI 2010 28.2. DOMINO 359

Figura 28.4: domino

Exemple:
domino.in domino.out Explicaţii
5 23 La atingerea primei piese vor cădea primele două piese;
10 10 Atingea piesei de pe poziţia 27 răstoarnă piesa de pe poziţia
14 10 28 iar aceasta o răstoarnă şi pe ultima.
27 2 Numărul de atingeri este 2 iar numărul maxim de piese
28 10 doborâte la o atingere este 3.
37 5

Timp maxim de executare/test: 1.0 secunde

28.2.1 Indicaţii de rezolvare


prof. Adriana Simulescu, Liceul ”Grigore Moisil” Timişoara

Descrierea soluţiei
Soluţia propusă memorează ı̂n variabila dist poziţia maximă la care acţionează o piesă care a
căzut, ı̂n variabila nd numărul de piese doborâte la o atingere şi ı̂n nmax numărul maxim de piese
doborâte la o atingere.
Pentru fiecare piesă de domino se verifică dacă este doborâtă de o piesă anterioară, se ac-
tualizează numărul de piese doborâte la atingerea curentă şi poziţia până la care se doboară ı̂n
continuare alte piese.
CAPITOLUL 28. ONI 2010 28.2. DOMINO 360

Figura 28.5: dominoIR

28.2.2 Cod sursă

Listing 28.2.1: domino AS 1.CPP


// Simulescu Adriana -100p
#include<fstream>

using namespace std;

struct domino{int h,p;};

domino d[1001];
int n,nd,dmax,nmax,nr,dist;

ifstream f("domino.in");
ofstream g("domino.out");

int main()
{ int i;

f>>n;
for(i=1;i<=n;i++)
f>>d[i].p>>d[i].h;

f.close();

dist=0;
for(i=1;i<=n;i++)
if(d[i].p>dist||nd==0)
{
nd++;
if(nr>nmax) nmax=nr;
dist=d[i].p+d[i].h;
nr=1;
}
else
{
nr++;
if(dist< d[i].p+d[i].h )
dist=d[i].p+d[i].h;
}

if(nr>nmax) nmax=nr;
CAPITOLUL 28. ONI 2010 28.2. DOMINO 361

g<<nd<<" "<<nmax;
g.close();
return 0;
}

Listing 28.2.2: domino AS 2.CPP


//Simulescu Adriana -100p
#include<fstream>

using namespace std;

int n,nd,dmax,nmax,nr,dist,h,p;

ifstream f("domino.in");
ofstream g("domino.out");

int main()
{
int i;

f>>n;
dist=0;
nd=0;
for(i=1;i<=n;i++)
{
f>>p>>h;

if(p>dist)
{
nd++;
if(nr>nmax) nmax=nr;
dist=p+h;
nr=1;
}
else
{
nr++;
if(dist< p+h )
dist=p+h;
}
}

if(nr>nmax) nmax=nr;
g<<nd<<" "<<nmax;
g.close();

return 0;
}

Listing 28.2.3: domino CM.CPP


// Carmen Minca -100p
#include<fstream>

using namespace std;

ifstream fi("domino.in");
ofstream fo("domino.out");

struct interval
{
int a, b, nr;
}
v[5000];

int comun(int a, int b, int c, int d)


{ if ((b<c)||(d<a)) return 0;
return 1;
}

void rez(int a, int b, int c, int d, int &e, int &f)


CAPITOLUL 28. ONI 2010 28.2. DOMINO 362

{ e=a;
if(e>c) e=c;
f=b;
if(f<d) f=d;
}

int main()
{
int N,p,h,i,k=0,j,max=1,ok;

fi>>N;
fi>>p>>h;
k++;
v[k].a=p;
v[k].b=p+h;
v[k].nr=1;

for(i=2;i<=N;i++)
{
fi>>p>>h;ok=0;
for(j=1;(j<=k)&&(ok==0);j++)
if(comun(v[j].a,v[j].b,p,p+h))
{
rez(v[j].a, v[j].b,p,p+h,v[j].a,v[j].b);
v[j].nr++;
if(max<v[j].nr)max=v[j].nr;
ok=1;
}

if(ok==0)
{ k++;
v[k].a=p; v[k].b=p+h;
v[k].nr=1;
}
}

fo<<k<<’ ’<<max;
fi.close();
fo.close();

return 0;
}

Listing 28.2.4: domino CS.CPP


// Cristina Sichim - 100p
# include <fstream>

using namespace std;

int main()
{
ifstream f("domino.in");
ofstream g("domino.out");

int N,p,h,a=1,b=1,nrb=1,i,unde;

f>>N;
f>>p>>h;
unde=p+h;

for(i=2;i<=N;i++)
{
f>>p>>h;
if(p<=unde)
{
nrb++;
if(p+h>unde) unde=p+h;
}
else
{
if (nrb>b) b=nrb;
nrb=1;a++;
unde=p+h;
}
CAPITOLUL 28. ONI 2010 28.3. MAX 363

if(nrb>b) b=nrb;

g<<a<<’ ’<<b;
f.close();
g.close();
return 0;
}

Listing 28.2.5: domino SG.CPP


//Suzana Galatan - 100p
#include <fstream>

using namespace std;

ifstream fin("domino.in");
ofstream fout("domino.out");

int main()
{
int x[1000];
int p, h, smax = 1, pf, i, sfin = 1, buf = 1;
int n;

fin >> n;
fin >> p >> h;
pf = p + h;

for(i = 2; i <= n; i++)


{
fin >> p >> h;
if(pf >= p)
{
smax++;
if(p + h > pf)pf = p + h;
}
else
{
smax = 1;
buf++;
pf = p + h;
}

if(sfin < smax) sfin = smax;


}

fout << buf << " " <<sfin;


fout <<"\n";

return 0;
}

28.2.3 *Rezolvare detaliată

28.3 max
Problema 3 - max 100 de puncte
Fie n un număr natural nenul şi un şir de n numere naturale nenule, fiecare număr din şir
având cel mult 3 cifre. Şirul dat se ”maximizează” prin aplicarea următoarelor transformări:
T1: Fiecare număr y din şir este ı̂nlocuit cu cel mai mare număr care se poate obţine prin
aranjarea tuturor cifrelor lui y. De exemplu, pentru y 102, prin aranjarea cifrelor, se obţin
numerele: 12, 21, 102, 120, 201, 210, cel mai mare număr fiind 210. Astfel, y se va ı̂nlocui ı̂n şir
cu numărul 210.
CAPITOLUL 28. ONI 2010 28.3. MAX 364

T2: Se schimbă ordinea numerelor din şirul obţinut după aplicarea transformării T 1 astfel
ı̂ncât numărul x obţinut prin alipirea tuturor numerelor din şir, ı̂n ordinea ı̂n care apar după
schimbare, să fie cel mai mare posibil.
De exemplu, pentru n 3 şi şirul: 12, 132, 102, după aplicarea transformării T 1 noul şir este
format din numerele: 21, 321, 210. Din acest şir, se pot obţine, prin schimbarea ordinii numerelor,
următoarele 6 şiruri: 1) 21, 321, 210; 2) 21, 210, 321; 3) 321, 21, 210; 4) 321, 210, 21; 5) 210, 21,
321; 6) 210, 321, 21.
Numerele care rezultă prin alipirea numerelor din fiecare şir obţinut sunt:
1) 21321210; 2) 21210321; 3) 32121210; 4) 32121021; 5) 21021321; 6) 21032121.
După aplicarea transformării T 2, şirul ”maximizat” este: 321, 21, 210 deoarece cel mai mare
număr dintre cele 6 obţinute este x 32121210.

Cerinţe

Scrieţi un program care să citească numărul natural nenul n şi cele n numere naturale nenule
din şir şi care să determine:
a) cel mai mare număr m din şirul de numere obţinut ı̂n urma aplicării transformării T 1;
b) numărul x obţinut prin alipirea numerele din şirul ”maximizat” rezultat ı̂n urma aplicării
transformării T 2.

Date de intrare

Fişierul de intrare max.in conţine două linii. Pe prima linie este scris numărul natural nenul
n, iar pe a doua linie sunt scrise cele n numere naturale nenule din şir, separate prin câte un
spaţiu.

Date de ieşire

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


- pe prima linie numărul natural m, reprezentând cel mai mare număr din şirul de numere
obţinut ı̂n urma aplicării transformării T 1
- pe a doua linie numărul natural x, reprezentând numărul obţinut prin alipirea numerelor din
şirul ”maximizat”, rezultat ı̂n urma aplicării transformării T 2.

Restricţii şi precizări

a Numărul n este număr natural 2 & n & 3500


a Cele n numere din şirul citit sunt numere naturale nenule, fiecare număr din şir având cel
mult 3 cifre
a Dacă un număr din şir are cel puţin o cifră nulă iar prin aranjarea cifrelor acestui număr se
obţine un alt număr care are prima cifră 0, atunci această cifră se ignoră
a Numărul natural x determinat poate avea cel mult 10500 de cifre
a Se acordă punctaje parţiale: cerinţa a) 20% din punctaj, cerinţa b) 80% din punctaj

Exemple
max.in max.out Explicaţii
9 321 După aplicarea transformării T1, şirul
34 23 9 43 21 67 121 79 213 9977643433232121211 devine: 43, 32, 9, 43, 21, 76, 211, 97,
321. Cel mai mare număr din acest
şir este m=321. După aplicarea trans-
formării T2, şirul maximizat este: 9, 97,
76, 43, 43, 32, 321, 21, 211 iar numărul
x 9977643433232121211

Timp maxim de executare/test: 1.0 secunde


CAPITOLUL 28. ONI 2010 28.3. MAX 365

28.3.1 Indicaţii de rezolvare


prof. Carmen Mincă, Liceul Teoretic ”Ion Neculce” - Bucureşti

Descriere soluţie
O soluţie posibilă se poate obţine prin utilizarea a doi vectori v şi p, fiecare având maxim 3500
de componente ı̂ntregi.
În vectorul v se vor memora numerele din şirul obţinut ı̂n urma transformării T 1, rezultate
din numerele din fişierul de intrare. Acestea pot fi citite succesiv ı̂ntr-o variabilă x.
Pentru fiecare număr memorat ı̂n x se separă cifrele, se ordonează descrescător aceste cifre
iar numărul obţinut se memorează ı̂n v i. În acelaşi timp se memorează ı̂n componenta pi
k
valoarea pi 10 , unde k reprezintă numărul de cifre ale lui v i, pi fiind utilă ı̂n construirea
numerelor rezultate prin alipirea a două valori din vectorul v.
În timp ce se aplică T 1, se determină şi valoarea maximă din şirul obţinut.
Pentru a obţine şirul maximizat rezultat din T 2, se poate utiliza un algoritm de sortare, de
exemplu sortarea prin selectarea maximului.
Pentru fiecare i 1, .., n  1 şi j i  1.., n se construiesc cele două numere rezultate prin prin
alipirea, ı̂n această ordine, a numerelor v i şi v j , respectiv v j  şi v i, adică v i ˜ pj   v j 
şi v j  ˜ pi  v i. Se selectează maximul dintre aceste valori.
Numărul x cerut se obţine prin alipirea tuturor numerelor din şirul maximizat. Acest lucru se
realizează prin scrierea ı̂n fişierul de ieşire a tuturor numerelor din şirul maximizat, ı̂n ordinea din
acest şir, fără spaţii ı̂ntre numere.

Figura 28.6: maxIR1


CAPITOLUL 28. ONI 2010 28.3. MAX 366

Descriere soluţie - prof. Cristina Sichim, C.N. ”Ferdinand I” Bacău


O altă soluţie posibilă pentru rezolvarea cerinţei b) utilizează un vector caracteristic v cu 999
de elemente.
Pentru fiecare cifră x (de la 9 la 1) se afişează mai ı̂ntâi cifra de un număr de ori egal cu
valoarea v x din vectorul caracteristic.
În continuare, ı̂n ordine descrescătoare se afişează numerele y cu două cifre care au prima cifră
x, după fiecare dintre ele afişându-se, ı̂n ordine descrescătoarele numerele cu trei cifre ce au ca
prefix numărul y.

Figura 28.7: maxIR2

28.3.2 Cod sursă

Listing 28.3.1: MAX CM.CPP


//prof.Carmen Minca - 100p
#include <fstream>

using namespace std;

int main()
{
int n, v[3505], p[3505];
long d,e;
int i, max=0,x,a,b,c,j;
CAPITOLUL 28. ONI 2010 28.3. MAX 367

ifstream f("max.in");
ofstream g("max.out");

f>>n;
for(i=1;i<=n;i++)
{ f>>x; v[i]=x;
if(x<10) p[i]=10;
else
if(x<100)
{ a=x/10; b=x%10; p[i]=100;
if (a<b)v[i]=b*10+a;
}
else
{ a=x/100; x=x%100; b=x/10; c=x%10;p[i]=1000;
if(a<b) { x=a; a=b; b=x;}
if(a<c) { x=a; a=c; c=x;}
if(b<c) { x=b; b=c; c=x;}
v[i]=100*a+10*b+c;
}
if(max<v[i])max=v[i];
}

g<<max<<endl;

for(i=1;i<n;i++)
for(j=i+1;j<=n;j++)
{ d=v[i];d=d*p[j]+v[j];
e=v[j]; e=e*p[i]+v[i];
if (d<e)
{
x=v[i]; v[i]=v[j]; v[j]=x;
x=p[i]; p[i]=p[j]; p[j]=x;
}
}

for(i=1;i<=n;i++) g<<v[i];

g.close();
return 0;
}

Listing 28.3.2: MAX CS.CPP


//prof. Cristina Sichim -100p

#include<fstream>

using namespace std;

int n,v[1001],i,x,aux,maxx,y,z,a,b,c;

int main()
{
ifstream f("max.in");
ofstream g("max.out");
f>>n;

for(i=1;i<=n;i++)
{
f>>x;
if(x>9 && x<100 && x/10<x%10) x=x%10*10+x/10;
if(x>99)
{
a=x%10;b=x/10%10;c=x/100;
if(a<b) {aux=a;a=b;b=aux;}
if(a<c) {aux=a;a=c;c=aux;}
if(b<c) {aux=b;b=c;c=aux;}
x=a*100+b*10+c;
}

v[x]++;
if(maxx<x) maxx=x;
}

g<<maxx<<’\n’;
CAPITOLUL 28. ONI 2010 28.3. MAX 368

for(x=9;x>0;x--)
{
//toate care incep cu cifra x
while(v[x]--) g<<x; //cele de o cifra
for(y=x*10+9;y>=x*10;y--)
{
while(v[y]--)g<<y;
for(z=y*10+x;z>=y*10;z--)
while(v[z]--)g<<z;
}
}

g<<’\n’;
f.close();
g.close();
return 0;
}

Listing 28.3.3: MAX SG.CPP


//prof. Suzana Galatan -100p
#include <fstream>

using namespace std;

void Sorteaza();
int maxim(int nr);
void Afiseaza();

ifstream fin ("max.in");


ofstream fout("max.out");

int n, max2, m;
int c[1001];

int main()
{
int nr, m = 0, max2 = 0;
fin >> n;
for(int i = 1; i <= n; i++)
{
fin >> nr;
nr = maxim(nr);

c[nr]++;
if(nr > m) m = nr;
if(nr < 100 && nr > 9)
{
if(max2 < nr) max2 = nr;
}
}

fout << m;
fout << "\n";
// Sorteaza();
Afiseaza();

fin.close();
fout.close();
return 0;
}

int maxim(int nr)


{
int a[10] = {0};
while(nr)
{
a[nr%10]++;
nr/=10;
}
for(int i = 9; i >= 0; i--)
while(a[i])
{
nr = nr*10 + i;
CAPITOLUL 28. ONI 2010 28.3. MAX 369

a[i]--;
}
return nr;
}

void Afiseaza()
{
int i = 9, j, k;
/* for(i = 999; i >= 0; i--)
while(c[i])
{fout<< i<< " ";
c[i]--;
}*/

for(i = 9;i > 0; i--)


for(j = i*10 +9; j >= i*10; j--)
for(k = j*10+9; k >= j*10; k--)
{
while(c[i])
{
if(i >= j /10 || i >= k/100)
{
fout << i;
c[i]--;
}
}

while(c[j])
if(j >= k/10)
{
fout << j;
c[j]--;
}

while(c[k])
{
fout << k;
c[k]--;
}
}
}

28.3.3 *Rezolvare detaliată


370
Appendix A

Programa olimpiadei - gimnaziu

A.1 Clasa a V-a


1. Algoritmi elementari
– Tipuri simple de date. Tipul ı̂ntreg (pe 4 octeţi), tipul logic
– Structura liniară, alternativă şi repetitivă
– Prelucrarea cifrelor numerelor naturale scrise ı̂n baza 10
– Divizibilitate (divizorii numerelor naturale, numere prime, determinarea cmmdc prin
algoritmul lui Euclid, cmmmc, numere prime ı̂ntre ele, simplificarea fracţiilor)
– Calculul unor expresii (de exemplu, factorial, ridicare la putere)
2. Generări de şiruri
– Generarea şirurilor pe baza unor reguli
– Şirul lui Fibonacci şi alte şiruri recurente
3. Fişiere text
4. Prelucrări de şiruri de numere citite succesiv, fără memorarea lor
– Prelucrări ce necesită stocarea ultimului element
(de exemplu, determinare maxim/minim, primele două maxime sau minime)
– Prelucrări ce necesită stocarea ultimelor p (p=2, 3, ..) elemente (de exemplu, cea mai
lungă subsecvenţă cu anumite proprietăţi, numărarea secvenţelor cu anumite pro-
prietăţi)

Doar pentru etapa naţională

5. Algoritmi elementari. Tablouri unidimensionale


– Prelucrări elementare (de exemplu, parcurgere, inversare, verificare proprietăţi)
– Căutarea liniară a unor valori
– Vectori caracteristici/ de frecvenţă
– Algoritmi de sortare ı̂n complexitate pătratică (sortarea prin selecţie, sortarea prin
inserţie, metoda bulelor)
– Sortare prin numărare (folosind vectori de frecvenţă)

A.2 Clasa a VI-a


1. Tipuri simple de date (ı̂ntregi, reale, char)
2. Sisteme de numeraţie şi reguli de conversie
3. Aritmetica modulară (adunări, scăderi, ı̂nmulţiri)
4. Divizibilitate
– Ciurul lui Eratostene
– Descompunerea numerelor naturale ı̂n factori primi
5. Tablouri unidimensionale (vectori)
– Operaţii cu mulţimi
– Căutare binară

371
APPENDIX A. PROGRAMA OLIMPIADEI - GIMNAZIU A.3. CLASA A VII-A 372

– Precalcularea unor informaţii pentru prefixe/sufixe ı̂n tablouri unidimensionale


(de exemplu sume parţiale, maxime parţiale)
– Probleme cu secvenţe de valori (de exemplu, determinarea unei secvenţe maximale cu o
anumită proprietate, numărarea secvenţelor, prelucrarea secvenţelor de lungime fixată
ce nu implică stive, cozi sau alte structuri de date avansate)
– Căutarea apariţiilor unei subsecvenţe ı̂ntr-o secvenţă de valori ı̂n timp pătratic
– Interclasarea tablourilor unidimensionale

Doar pentru etapa naţională

6. Tablouri bidimensionale
– Prelucrări elementare ale tablourilor bidimensionale (de exemplu, parcurgeri pe linii/-
coloane/diagonale/ı̂n spirală, generări, transpunere, bordare)
– Prelucrări specifice tablourilor bidimensionale pătratice (de exemplu, diagonale şi zone
determinate de diagonale)
– Căutări secvenţiale ı̂n tablouri bidimensionale (de exemplu, a unui element, a unei
secvenţe de valori, a unei submatrice)
– Utilizarea vectorilor de direcţie
7. Simulări
– reprezentarea sistemului de simulat, starea sistemului
– bucla de evenimente ce modifică starea sistemului

A.3 Clasa a VII-a


1. Funcţii
– Declarare, definire, apel
– Variabile locale, variabile globale
– Transmiterea parametrilor prin valoare şi prin referinţă
2. Tablouri
– Tehnica Two Pointers
– Tablouri de diferenţe - Difference Arrays
– Determinarea secvenţei de sumă maximă
– Determinarea elementului majoritar
– Precalcularea unor informaţii ı̂n tablouri bidimensionale (de exemplu sume parţiale
pe prefixe/sufixe de linii/coloane, suma elementelor dintr-o submatrice cu unul dintre
colţuri fixat ı̂n unul dintre colţurile matricei)
– Tablouri multidimensionale
3. Tipuri de date neomogene (struct)
4. Utilizarea funcţiilor din biblioteca STL pentru sortare şi căutare
5. Metoda Greedy

Doar pentru etapa naţională

6. Operaţii cu numere mari


– Adunarea numerelor mari
– Scăderea numerelor mari
– ı̂nmulţirea unui număr mare cu un număr natural
– ı̂mpărţirea cu rest a unui număr mare la un număr natural nenul
7. Algoritmul de exponenţiere rapidă
8. Stiva. Aplicaţii specifice

A.4 Clasa a VIII-a


1. Şiruri de caractere. Funcţii specifice
2. Generarea elementelor combinatoriale prin algoritmi de tip succesor
– Submulţimi
– Produs cartezian
APPENDIX A. PROGRAMA OLIMPIADEI - GIMNAZIU A.5. BARAJUL DE SELECŢIE
A LOTULUI NAŢIONAL LĂRGIT 373

– Permutări
– Combinări
– Aranjamente
– Utilizarea funcţiilor din biblioteca STL pentru permutări

Doar pentru etapa naţională

3. Coada. Aplicaţii specifice


4. Coada cu dublă prioritate (deque). Aplicaţii specifice
5. Elemente de geometrie
– sistemul de coordonate cartezian ı̂n plan
– puncte ı̂n planul cartezian
– distanţa dintre două puncte
– arii

A.5 Barajul de selecţie a lotului naţional lărgit


1. Operaţii pe biţi
2. Indicatorul lui Euler
3. Tablouri de diferenţe (Difference Arrays) 2D
4. Recursivitate
5. Algoritmul de fill
6. Algoritmul lui Lee
7. Tehnica Square root decomposition
8. Metoda programării dinamice

A.6 Note
ˆ Exceptând clasa a V-a, programa fiecărei clase include şi programele pentru toate clasele
precedente.
ˆ Barajul de selecţie a lotului naţional lărgit include programele pentru clasele V-VIII, precum
şi temele suplimentare specificate.
ˆ Pentru barajele de selecţie a echipelor reprezentative ale României vor fi abordate teme
suplimentare.
Appendix B

main(), cin, cout, fin, fout

B.1 Funcţia main()


Toţi suntem obişnuiţi cu structura unui program C/C++ pe care trebuie să-l scriem la olimpiadă!
28
El arată cam aşa :

Listing B.1.1: sss1.cpp


#include <iostream>
#include <fstream>

using namespace std;

int n, c, sum, L, sol1, sol2, x, k, sc, nr, i;

ifstream fin ("sss.in");


ofstream fout("sss.out");

int main()
{
fin>>c;
fin>>n;
// instructiuni

return 0;
}

Chiar dacă utilizarea funcţiilor definite de utilizator este prevăzută ı̂ncepând cu clasa a VII-a,
este bine să le folosim ı̂ncă din clasa a V-a! Asta pentru că utilizarea lor permite o mai bună
29
lizibilitate a programelor! Şi oricum ... participanţii la olimpiadă citesc mai mult decât este
30
prevăzut ı̂n programa olimpiadei! Vom folosi modelul de la funcţia main().

Listing B.1.2: sss2.cpp


#include <iostream>
#include <fstream>

using namespace std;

int n, c, sum, L, sol1, sol2, x, k, sc, nr, i;

ifstream fin ("sss.in");


ofstream fout("sss.out");

int calcul()
{
// instructiuni

return 0;
}
28
https://sepi.ro/page/oni2022
29
https://ro.wikipedia.org/wiki/Lizibilitate
30
tot ce nu este interzis, este permis!

374
APPENDIX B. MAIN(), CIN, COUT, FIN, FOUT B.1. FUNCŢIA MAIN() 375

int main()
{
fin>>c;
fin>>n;

calcul();

return 0;
}
Appendix C

”Instalare” C++

Ca să putem ”lucra” cu C++ avem nevoie de

ˆ un compilator pentru C++, şi

ˆ un IDE (Integrated Development Enviroment) pentru C++.

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

376
APPENDIX C. ”INSTALARE” C++ C.1. KIT OJI 2017 377

Kitul Kit_OJI_2017 se instalează implicit pe C:¯OJI¯


31
t IDE-ul Code::Blocks ,
t compilatorul pentru C: gcc.exe,
32
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 C.2: CodeBlocks & C++ Reference

Figura C.3: Ce conţine C:¯ OJI ¯

C.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
31
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
32
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 C. ”INSTALARE” C++ C.1. KIT OJI 2017 378

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

C.1.2 Folder de lucru

Figura C.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 C. ”INSTALARE” C++ C.1. KIT OJI 2017 379

Figura C.5: New -¿ Text document

Figura C.6: Schimbare nume fişier şi nume extensie fişier


APPENDIX C. ”INSTALARE” C++ C.1. KIT OJI 2017 380

Figura C.7: Confirmare schimbare extensie ı̂n .cpp

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

C.1.3 Utilizare Code::Blocks

Figura C.9: Pregătit pentru a scrie cod de program C++ ı̂n Code::Blocks
APPENDIX C. ”INSTALARE” C++ C.1. KIT OJI 2017 381

Figura C.10: Primul cod de program C++ ı̂n Code::Blocks

Figura C.11: Build - compilare


APPENDIX C. ”INSTALARE” C++ C.1. KIT OJI 2017 382

Figura C.12: 0 error(s), 0 warning(s)

Figura C.13: Run - execuţie


APPENDIX C. ”INSTALARE” C++ C.1. KIT OJI 2017 383

Figura C.14: Executat corect: a făcut “nimic”

C.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 C.15: Settings  % Compiler


APPENDIX C. ”INSTALARE” C++ C.1. KIT OJI 2017 384

Figura C.16: Toolchain executables

Figura C.17: Unde sunt acele programe


APPENDIX C. ”INSTALARE” C++ C.1. KIT OJI 2017 385

C.1.5 Multe surse ı̂n Code Blocks


Settings Environment: pe calculatorul meu setările sunt:

Figura C.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 C.19: Multe surse in Code Blocks - exemple


APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 386

C.2 winlibs
C.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 C.20: mingw64 pe D:

C.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 C. ”INSTALARE” C++ C.2. WINLIBS 387

Figura C.21: search path

Apare fereastra “System properties”:

Figura C.22: System properties –¿ Advanced

Fereastra este poziţionată pe tab-ul “Advanced”. Se selectează “Environment Variables”.


APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 388

Figura C.23: Environment Variables

Se selecteaza “Path” şi click pe “Edit”. Apare fereastra “Edit Environment Variables”

Figura C.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 C. ”INSTALARE” C++ C.2. WINLIBS 389

Figura C.25: Calea şi versiunea pentru gcc

Dacă totul este OK atunci se trece la instalarea IDE-ului preferat (Integrated Development
33
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."

C.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!).
33
https://en.wikipedia.org/wiki/Integrated_development_environment
https://ro.wikipedia.org/wiki/Mediu_de_dezvoltare
APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 390

Figura C.26: Settings –¿ Compiler

Figura C.27: Toolchain executables –¿ Auto-detect


APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 391

Figura C.28: New –¿ Text Document

Figura C.29: New text Document.txt

Figura C.30: Schimbare nume şi extensie


APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 392

Figura C.31: Moore apps

Figura C.32: Look for another app


APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 393

Figura C.33: Cale pentru codeblocks.exe

Figura C.34: Selectare codeblocks.exe


APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 394

Figura C.35: Editare test01.cpp

Figura C.36: Compilare test01


APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 395

Figura C.37: Mesaje după compilare

Figura C.38: Execuţie test01


APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 396

Figura C.39: Rezultat execuţie test01

Figura C.40: Fişiere apărute după compilare!

Figura C.41: Creare test02.cpp gol! + ¡dublu click¿ sau ¡Enter¿


APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 397

Figura C.42: Lista programelor de utilizat

Figura C.43: Selectare Code::Blocks IDE pentru fişierele .cpp

Figura C.44: Editare+Compilare+Execuţie pentru test02


APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 398

Figura C.45: Selectare tab ce conţine test01.cpp


Appendix D

Exponenţiere rapidă

D.1 Analogie baza 2 cu baza 10

Figura D.1: Analogie B2 cu B10

În figura D.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)

399
APPENDIX D. EXPONENŢIERE RAPIDĂ D.2. NOTAŢII, RELAŢII ŞI FORMULE 400

D.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;
„
„
„
‚
„ (D.2.1)
„
„
„
„
„nk nk1 ©2 k ' 1; nk1 j 0 desigur ! ... dar şi nk1 j 1 
„
„
„ ak1 , k ' 1;
2
„
„a k
„
„
„
„
„e k 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 ,

D.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 D. EXPONENŢIERE RAPIDĂ D.4. CODUL 401

D.4 Codul
Codul pentru relaţiile (D.2.1) devine:

Listing D.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 (D.4.2).
APPENDIX D. EXPONENŢIERE RAPIDĂ D.4. CODUL 402

Listing D.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;
„
„
„
„n 1 n;
„
„
„
„
„
„a1 a;
„
„
„
„
„calcul pentru k ' 0:
„
„e
‚
„ k nk1 %2 " r0, 1x; k ' 0 (D.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 D. EXPONENŢIERE RAPIDĂ D.4. CODUL 403

Observaţia 4. Instrucţiunile care sunt ”ı̂n plus” se pot elimina. Codul următor arată acest lucru:

Listing D.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 D.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 D. EXPONENŢIERE RAPIDĂ D.5. CHIAR ESTE RAPIDĂ? 404

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 */

D.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 D.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 D. EXPONENŢIERE RAPIDĂ D.6. REZUMAT INTUITIV! 405

Iar aceasta este metoda ”rapidă”:

Listing D.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)!

D.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 D. EXPONENŢIERE RAPIDĂ D.6. REZUMAT INTUITIV! 406

Asta este tot!


Deci, secvenţa de cod este:

Listing D.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 }

34
şi nu mai trebuie ”atâtea formule matematice”!

34
Este o glumă!
Appendix E

Căutare binară

E.1 Mijlocul = ?
Care este poziţia (indicele) ”mijlocului” unei zone dintr-un vector?

Figura E.1: căutare binară: mijlocul zonei ı̂n vector

În figura E.1 sunt trei formule pentru determinarea mijlocului unei zone [i1, i2] din vector:
ˆ mij1 = (i1+i2)/2
ˆ mij2 = i1+(i2-i1)/2
ˆ mijdr = (i1+i2+1)/2
Toate trei dau rezultat corect dacă secvenţa [i1, ..., i2] are un număr impar de elemente.
Când secvenţa [i1, ..., i2] are un număr par de elemente apar două elemente la mijloc ... şi ...
primele două formule dau ”mijlocul din stânga” iar a treia formulă dă ”mijlocul din dreapta”.
Atunci când căutăm o valoare ı̂ntr-un vector avem la dispoziţie căutarea secvenţială. Dacă
ştim că vectorul este sortat (şir crescător de numere) atunci este bine să folosim căutarea binară
pentru că aceasta ”găseste” numărul căutat (sau ”spune” că acel număr nu este ı̂n şir)
ˆ ı̂n 10 paşi dacă şirul are 1000 de elemnte (de fapt 1024 dar ... aproximăm!),
ˆ ı̂n 20 de paşi dacă şirul are 1,000,000 de elemente,
ˆ ı̂n 30 de paşi dacă şirul are 1,000,000,000 de elemente,
ˆ ...
Explicaţia simplă este că noi tot ı̂njumătăţim intervalul de căutare până când acest interval
rămâne cu un singur element ... şi vedem dacă acel element este cel căutat (dacă elementul rămas
nu este cel căutat ... ı̂nseamnă că acel element ”căutat” nu există ı̂n şir).
Putem să ne gândim la drumul invers: plecăm de la o secvenţă cu un singur element şi dublăm
secvenţa (invers faţă de cum am făcut ı̂njumătăţind secvenţa) până ajungem la o secvenţă care
are atâtea elemente câte a avut şirul iniţial (ne oprim imediat dacă am depăşit acel număr!).
Lungimile secvenţelor sunt: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, ...

Observăm că ı̂n 10 paşi, plecând din 1, ajungem să depăşim 1000.

407
APPENDIX E. CĂUTARE BINARĂ E.2. POZIŢIE OARECARE 408

E.2 Poziţie oarecare


E.2.1 Varianta iterativă

Listing E.2.1: cautare binara-v1-iterativ.cpp


1 // are rost NUMAI daca vectorul este SORTAT (aici crescator ... !!!)
2 // gaseste o pozitie oarecare din secventa x...x...x (a doua din stanga!)
3 // daca x nu exista --> v[dr] < x < v[st] unde dr=st-1 (initial st < dr)
4
5 #include<iostream>
6
7 using namespace std;
8
9 int nrc=0; // numarul de cautari
10
11 void afisv(int v[], int st, int dr) // afisez v[] intre st si dr
12 {
13 int i;
14 for(i=st; i<=dr; i++)
15 {
16 cout<<v[i]<<" ";
17 }
18 }
19 // ------------------------------------------------------------------
20 bool cautareBinaraIter1(int x, int v[], int st, int dr)
21 {
22 int mij;
23
24 while(st <= dr)
25 {
26 nrc++;
27 mij=(st+dr)/2; // actualizez zona de cautare
28 cout<<"caut "<<x<<" in ";
29 afisv(v,st,dr);
30 cout<<"\n\n";
31
32 if(x == v[mij])
33 {
34 cout<<"am gasit "<<x<<" pe pozitia mij = "<<mij
35 <<" st="<<st<<" dr="<<dr<<"\n";
36 return true;// l-a gasit pe x
37 }
38 else // aici x != v[mij] ...
39 {
40 if(x < v[mij])
41 dr=mij-1; // caut in stanga lui mij, st ramane neschimbat
42 else
43 st=mij+1; // caut in dreapta lui mij, dr ramane neschimbat
44 }
45
46 cout<<"v["<<st<<"] = "<<v[st]<<" v["<<dr<<"] = "<<v[dr]<<endl;
47 }
48
49 if(st>dr)
50 {
51 cout<<x<<" nu exista in vector ...!"<<" st="<<st<<" dr="<<dr
52 <<" v[st]="<<v[st]<<" v[dr]="<<v[dr]<<"\n";
53 //return;
54 return false;
55 }
56
57 return true; // sau return false; ... oricum nu ajunge aici ... !!!
58 }
59 // ------------------------------------------------------------------
60
61 int main()
62 {
63 int x; // caut x in vectorul a[]
64
65 //x=1; // secventa pe primele pozitii
66 x=2; // nu exista 2 ... ultima cautare in (dr,st)
67 //x=3; // exista numai un 3
68 //x=4; // exista secventa de 4
69 //x=9; // secventa pe ultimele pozitii
APPENDIX E. CĂUTARE BINARĂ E.2. POZIŢIE OARECARE 409

70
71 int a[]={1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 7, 7, 8, 8, 9, 9, 9, 9};
72
73 int n=sizeof(a)/sizeof(int);
74
75 cout<<"prima pozitie in vector = 0\n";
76 cout<<"ultima pozitie in vector = "<<n-1<<endl<<endl;
77
78 cautareBinaraIter1(x,a,0,n-1); // caut x in vectorul a[] de dimensiune=n
79
80 cout<<endl;
81 cout<<"nr cautari = "<<nrc<<"\n";
82
83 return 0;
84 }

E.2.2 Varianta recursivă

Listing E.2.2: cautare binara-v1-recursiv.cpp


1 // are rost NUMAI daca vectorul este SORTAT (aici crescator ... !!!)
2 // gaseste o pozitie oarecare din secventa x...x...x (a doua din stanga!)
3 // daca x nu exista --> v[dr] < x < v[st] unde dr=st-1 (initial st < dr)
4
5 #include<iostream>
6
7 using namespace std;
8
9 int nrc=0; // numarul de cautari
10
11 void afisv(int v[], int st, int dr) // afisez v[] intre st si dr
12 {
13 int i;
14 for(i=st; i<=dr; i++)
15 {
16 cout<<v[i]<<" ";
17 }
18 }
19 // ------------------------------------------------------------------
20 void cautareBinaraRec1(int x, int v[], int st, int dr)
21 {
22 nrc++; // o noua cautare,
23
24 cout<<"caut "<<x<<" in ";
25 afisv(v,st,dr);
26 cout<<"\n\n";
27
28 int mij=(st+dr)/2;
29
30 if(st>dr)
31 {
32 cout<<x<<" nu exista in vector ...!"<<" st="<<st<<" dr="<<dr
33 <<" v[st]="<<v[st]<<" v[dr]="<<v[dr]<<"\n";
34 return;
35 //return false;
36 }
37
38 if(x == v[mij])
39 {
40 cout<<"am gasit "<<x<<" pe pozitia "<<mij<<"\n";
41 return;
42 //return true;
43 }
44 else // mai caut
45 {
46 if(x < v[mij])
47 cautareBinaraRec1(x,v,st,mij-1); // caut in stanga lui mij
48 else
49 cautareBinaraRec1(x,v,mij+1,dr); // caut in dreapta lui mij
50 }
51
52 return;
53 }
54 // ------------------------------------------------------------------
APPENDIX E. CĂUTARE BINARĂ E.3. POZIŢIA DIN STÂNGA 410

55 int main()
56 {
57 int x; // caut x in vectorul a[]
58
59 //x=1; // secventa pe primele pozitii
60 x=2; // nu exista 2 ... ultima cautare in (dr,st) dr=st-1
61 //x=3; // exista numai un 3
62 //x=4; // exista secventa de 4
63 //x=9; // secventa pe ultimele pozitii
64
65 int a[]={1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 7, 7, 8, 8, 9, 9, 9, 9};
66
67 int n=sizeof(a)/sizeof(int);
68
69 cout<<"prima pozitie in vector = 0\n";
70 cout<<"ultima pozitie in vector = "<<n-1<<endl<<endl;
71
72 cautareBinaraRec1(x,a,0,n-1); // caut x in vectorul a[] de dimensiune=n
73
74 cout<<endl;
75 cout<<"nr cautari = "<<nrc<<"\n";
76
77 return 0;
78 }

E.3 Poziţia din stânga


E.3.1 Varianta iterativă

Listing E.3.1: cautare binara-v2-iterativ.cpp


1 // are rost NUMAI daca vectorul este SORTAT (aici crescator ... !!!)
2 // gaseste pozitia din stanga din secventa x...x...x
3 // daca x nu exista --> st = dr = prima pozitie spre dreapta cu v[st] > x
4
5 #include<iostream>
6
7 using namespace std;
8
9 int nrc=0; // numarul de cautari
10
11 void afisv(int v[], int st, int dr) // afisez v[] intre st si dr
12 {
13 int i;
14 for(i=st; i<=dr; i++)
15 {
16 cout<<v[i]<<" ";
17 }
18 }
19 // ------------------------------------------------------------------
20 bool cautareBinaraIter1(int x, int v[], int st, int dr)
21 {
22 int mij;
23
24 while(st != dr)
25 {
26 nrc++;
27 mij=(st+dr)/2; // actualizez zona de cautare
28
29 cout<<"caut "<<x<<" in ";
30 afisv(v,st,dr);
31 cout<<"\n\n";
32
33 if(x <= v[mij])
34 dr=mij; // caut in stanga
35 else
36 st=mij+1; // caut in dreapta
37
38
39
40 cout<<"v["<<st<<"] = "<<v[st]<<" v["<<dr<<"] = "<<v[dr]<<endl;
41 }
42
APPENDIX E. CĂUTARE BINARĂ E.3. POZIŢIA DIN STÂNGA 411

43 if(st==dr) // am terminat (gasit cel mai din stanga sau nu exista deloc)
44 {
45 if(v[st]==x)
46 {
47 cout<<"am gasit "<<x<<" pe pozitia "<<st<<"\n";
48
49 return true;
50 }
51
52 else
53 {
54 cout<<x<<" nu exista in vector ...!"<<" st="<<st<<" dr="<<dr
55 <<" v[st]="<<v[st]<<" v[dr]="<<v[dr]<<"\n";
56
57 return false;
58 }
59 }
60
61 return true; // sau return false; ... oricum nu ajunge aici ... !!!
62 }
63
64 // ------------------------------------------------------------------
65
66 int main()
67 {
68 int x; // caut x in vectorul a[]
69
70 //x=1; // secventa pe primele pozitii
71 x=2; // nu exista 2 ... ultima cautare in (dr,st) dr=st-1
72 //x=3; // exista numai un 3
73 //x=4; // exista secventa de 4
74 //x=9; // secventa pe ultimele pozitii
75
76 int a[]={1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 7, 7, 8, 8, 9, 9, 9, 9};
77
78 int n=sizeof(a)/sizeof(int);
79
80 cout<<"prima pozitie in vector = 0\n";
81 cout<<"ultima pozitie in vector = "<<n-1<<endl<<endl;
82
83 cautareBinaraIter1(x,a,0,n-1); // caut x in vectorul a[] de dimensiune=n
84
85 cout<<endl;
86 cout<<"nr cautari = "<<nrc<<"\n";
87
88 return 0;
89 }

E.3.2 Varianta recursivă

Listing E.3.2: cautare binara-v2-recursiv.cpp


1 // are rost NUMAI daca vectorul este SORTAT (aici crescator ... !!!)
2 // gaseste pozitia din stanga din secventa x...x...x
3 // daca x nu exista --> st = dr = prima pozitie spre dreapta cu v[st] > x
4
5 #include<iostream>
6
7 using namespace std;
8
9 int nrc=0; // numarul de cautari
10
11 // ------------------------------------------------------------------
12
13 void afisv(int v[], int st, int dr) // afisez v[] intre st si dr
14 {
15 int i;
16 for(i=st; i<=dr; i++)
17 {
18 cout<<v[i]<<" ";
19 }
20 }
21
22 // ------------------------------------------------------------------
APPENDIX E. CĂUTARE BINARĂ E.4. POZIŢIA DIN DREAPTA 412

23 void cautareBinaraRec2(int x, int v[], int st, int dr)


24 {
25 nrc++; // o noua cautare,
26 cout<<"nrc = "<<nrc<<": caut "<<x<<" in zona indicilor "
27 <<st<<" ... "<<dr<<" : "<<endl;
28 afisv(v,st,dr);
29 cout<<"\n\n";
30 //getchar(); // while si recursivitatea ... pot "scapa" de sub control!
31
32 int mij=(st+dr)/2;
33
34 if(st==dr) // am terminat (gasit cel mai din stanga sau nu exista deloc)
35 {
36 if(v[st]==x)
37 cout<<"am gasit "<<x<<" pe pozitia "<<st<<"\n";
38 else
39 cout<<x<<" nu exista in vector ...!"<<" st="<<st<<" dr="<<dr
40 <<" v[st]="<<v[st]<<" v[dr]="<<v[dr]<<"\n";
41 return;
42 //return false;
43 }
44
45 // mai caut
46 if(x <= v[mij])
47 cautareBinaraRec2(x,v,st,mij); // caut in stanga
48 else// aici x > v[mij]
49 cautareBinaraRec2(x,v,mij+1,dr); // caut in dreapta
50
51 return; // oricum nu ajunge aici !
52 }
53
54 // ------------------------------------------------------------------
55
56 int main()
57 {
58 int x; // caut x in vectorul a[]
59
60 //x=1; // secventa pe primele pozitii
61 //x=2; // nu exista 2 ... ultima cautare in (dr,st) dr=st-1
62 //x=3; // exista numai un 3
63 x=4; // exista secventa de 4
64 //x=9; // secventa pe ultimele pozitii
65
66 int a[]={1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 7, 7, 8, 8, 9, 9, 9, 9};
67 int n=sizeof(a)/sizeof(int);
68
69 cout<<"prima pozitie in vector = 0\n";
70 cout<<"ultima pozitie in vector = "<<n-1<<endl<<endl;
71
72 cautareBinaraRec2(x,a,0,n-1); // caut x in vectorul a[] de dimensiune=n
73
74 cout<<endl;
75 cout<<"nr cautari = "<<nrc<<"\n";
76
77 return 0;
78 }

E.4 Poziţia din dreapta


E.4.1 Varianta iterativă

Listing E.4.1: cautare binara-v3-iterativ.cpp


1 // are rost NUMAI daca vectorul este SORTAT (aici crescator ... !!!)
2 // gaseste pozitia din dreapta din secventa x...x...x
3 // daca x nu exista --> st = dr = prima pozitie spre stanga cu v[st] < x
4
5 #include<iostream>
6
7 using namespace std;
8
9 int nrc=0; // numarul de cautari
10
APPENDIX E. CĂUTARE BINARĂ E.4. POZIŢIA DIN DREAPTA 413

11 void afisv(int v[], int st, int dr) // afisez v[] intre st si dr
12 {
13 int i;
14 for(i=st; i<=dr; i++)
15 {
16 cout<<v[i]<<" ";
17 }
18 }
19
20 // ------------------------------------------------------------------
21
22 bool cautareBinaraIter1(int x, int v[], int st, int dr)
23 {
24 int mij;
25
26 while(st != dr)
27 {
28 nrc++;
29 mij=(st+dr+1)/2; // actualizez zona de cautare
30
31 cout<<"caut "<<x<<" in ";
32 afisv(v,st,dr);
33 cout<<"\n\n";
34
35 if(x >= v[mij])
36 st=mij; // caut in dreapta
37 else
38 dr=mij-1; // caut in stanga
39
40 cout<<"v["<<st<<"] = "<<v[st]<<" v["<<dr<<"] = "<<v[dr]<<endl;
41 //getchar();
42 }
43
44 if(st==dr) // am terminat (gasit cel mai din stanga sau nu exista deloc)
45 {
46 if(v[st]==x)
47 {
48 cout<<"am gasit "<<x<<" pe pozitia "<<st<<"\n";
49 return true;
50 }
51 else
52 {
53 cout<<x<<" nu exista in vector ...!"<<" st="<<st<<" dr="<<dr
54 <<" v[st]="<<v[st]<<" v[dr]="<<v[dr]<<"\n";
55 return false;
56 }
57 }
58
59 return true; // sau return false; ... oricum nu ajunge aici ... !!!
60 }
61 // ------------------------------------------------------------------
62
63 int main()
64 {
65 int x; // caut x in vectorul a[]
66
67 //x=1; // secventa pe primele pozitii
68 x=2; // nu exista 2 ... ultima cautare in (dr,st) dr=st-1
69 //x=3; // exista numai un 3
70 //x=4; // exista secventa de 4
71 //x=9; // secventa pe ultimele pozitii
72
73 int a[]={1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 7, 7, 8, 8, 9, 9, 9, 9};
74 int n=sizeof(a)/sizeof(int);
75
76 cout<<"prima pozitie in vector = 0\n";
77 cout<<"ultima pozitie in vector = "<<n-1<<endl<<endl;
78
79 cautareBinaraIter1(x,a,0,n-1); // caut x in vectorul a[] de dimensiune=n
80
81 cout<<endl;
82 cout<<"nr cautari = "<<nrc<<"\n";
83
84 return 0;
85 }
APPENDIX E. CĂUTARE BINARĂ E.4. POZIŢIA DIN DREAPTA 414

E.4.2 Varianta recursivă

Listing E.4.2: cautare binara-v3-recursiv.cpp


1 // are rost NUMAI daca vectorul este SORTAT (aici crescator ... !!!)
2 // gaseste pozitia din stanga din secventa x...x...x
3 // daca x nu exista --> st = dr = prima pozitie spre stanga cu v[st] < x
4
5 #include<iostream>
6
7 using namespace std;
8
9 int nrc=0; // numarul de cautari
10
11 void afisv(int v[], int st, int dr) // afisez v[] intre st si dr
12 {
13 int i;
14 for(i=st; i<=dr; i++) { cout<<v[i]<<" "; }
15 }
16
17 // ------------------------------------------------------------------
18
19 void cautareBinaraRec2(int x, int v[], int st, int dr)
20 {
21 nrc++; // o noua cautare,
22 cout<<"nrc = "<<nrc<<": caut "<<x<<" in zona indicilor "
23 <<st<<" ... "<<dr<<" : "<<endl;
24 afisv(v,st,dr);
25 cout<<"\n\n";
26 //getchar(); // while si recursivitatea ... pot "scapa" de sub control!
27
28 int mij=(st+dr+1)/2;
29 if(st==dr) // am terminat (gasit cel mai din stanga sau nu exista deloc)
30 {
31 if(v[st]==x) cout<<"am gasit "<<x<<" pe pozitia "<<st<<"\n";
32 else
33 cout<<x<<" nu exista in vector ...!"<<" st="<<st<<" dr="<<dr
34 <<" v[st]="<<v[st]<<" v[dr]="<<v[dr]<<"\n";
35 return;
36 //return false;
37 }
38
39 // mai caut
40 if(x >= v[mij])
41 cautareBinaraRec2(x,v,mij,dr); // caut in dreapta
42 else// aici x < v[mij]
43 cautareBinaraRec2(x,v,st,mij-1); // caut in stanga
44
45 return; // oricum nu ajunge aici !
46 }
47 // ------------------------------------------------------------------
48 int main()
49 {
50 int x; // caut x in vectorul a[]
51
52 //x=1; // secventa pe primele pozitii
53 x=2; // nu exista 2 ... ultima cautare in (dr,st) dr=st-1
54 //x=3; // exista numai un 3
55 //x=4; // exista secventa de 4
56 //x=9; // secventa pe ultimele pozitii
57
58 int a[]={1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 7, 7, 8, 8, 9, 9, 9, 9};
59 int n=sizeof(a)/sizeof(int);
60
61 cout<<"prima pozitie in vector = 0\n";
62 cout<<"ultima pozitie in vector = "<<n-1<<endl<<endl;
63
64 cautareBinaraRec2(x,a,0,n-1); // caut x in vectorul a[] de dimensiune=n
65
66 cout<<endl;
67 cout<<"nr cautari = "<<nrc<<"\n";
68
69 return 0;
70 }
Appendix F

”Vecini” ...

F.1 Direcţiile N, E, S, V

Figura F.1: ”vecini” ı̂n matrice şi sistem Oxy

În figura F.1 sunt două modele (notaţii) utile ı̂n probleme ı̂n care se folosesc directiile N, E, S şi
V (NE, NV, SE şi SV se deduc uşor!).

Figura F.2: Toţi ”pereţii” sunt la N sau la V ı̂n matricea ”bordată”

În figura F.2 ...

415
APPENDIX F. ”VECINI” ... F.1. DIRECŢIILE N, E, S, V 416

Figura F.3: Toţi ”pereţii” sunt codificaţi

În figura F.3 ...


Index

¶ ¶, 283, 289, 304 int v[40]=0;, 293


’¯n’, 298 islower, 298
(char)(’A’+i), 298
... ? ... : ..., 176 lexicografic, 194
&&, 290, 304 Liceul Militar Dimitrie Cantemir, vi
ı̂ncadrare ı̂n timp, 207 listă, 332
şir sortat, 322 long long, 47
şirul Fibonacci, 245 long long pz[], 47
1 nu e prim, 3
18 cifre, 286 matematică, 331
max, 47
algoritm de sortare, 365 maximul, 286
alipirea numerelor, 365 memset, 289
assert, 34 minimul, 286
mod, 195
baza 4, 348
bool prim(long long x), 47 număr de divizori, 76, 268
break, 301 număr prim, 2, 276
numărul de cifre, 365
căutare binară, 407 numărul divizorilor, 197
căutare secvenţială, 407 numere ”economice”, 245
case, 301 numere mari, 263, 286
cel mai mic palindrom, 103
char nrmin[40]=, 294 ofstream, 42
CINOR, vi ordonare, 273, 322, 365
citire caracter, 297
ciurul lui Eratostene, 243, 246 păstrare indicii elementelor ordonate, 273
concatenare, 286 palindrom, 347
contor, 33, 194 permutări circulare, 76, 351
precalcul, 322
default, 301 prefix, 366
depăşire valoare maximă, 102 printf, 34
descompunere ı̂n factori primi, 268 printf(%llu ¯n,Y);, 290
divizori, 76
răsturnare număr, 103
endl, 47 reverse, 324

factor prim, 268 scanf, 34


frecvenţa de apariţie, 322 scanf(%lld %lld ¯n,&x, &y);, 290
freopen, 34, 290 se divide, 2
short int, 143
generare ı̂n baza 4, 322 sizeof, 289
sort, 324, 327
I.d.k.: sortare, 273
I don’t know who the author is., i, v strcmp, 294
I64d, 342 strcpy, 294
ifstream, 42 strlen, 294
int comp(...), 289 structură alternativă, 204
int compar(int v1[],int v2[]), 293 structură repetitivă, 39, 198, 204
int nrc(long long x), 47 structura repetitivă for, 199

417
INDEX INDEX 418

suma cifrelor, 2 Universitatea Ovidius, vi


suma Gauss, 268 unsigned long long, 287, 343
swap, 327 unsigned long long x, y, Y, X;, 290
switch, 301, 320
break, 320 vector, 270, 276, 277, 297, 348, 365
case, 320 vector caracteristic, 157, 332, 366
switch ... case, 31 vector de frecvenţă, 190, 197, 204, 242, 243,
297
vectori, 198
tablou unidimensional, 194, 310, 322 void aduna(...), 289
tipul ı̂ntreg, 49 void copie(int v1[], int v2[]), 293
tipul caracter, 49
trage cu tunul, iv X=(x$y ? y-x: x-y);, 290
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.

419
BIBLIOGRAFIE BIBLIOGRAFIE 420

[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 421

[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
[84] *** - https://www.viitoriolimpici.ro/
[85] *** - https://oni2023.ro/blog/
Lista autorilor
problemelor şi indicaţiilor

Adriana Simulescu, 253, 338, 359 Gavril Petru Florin, 345


Ana Întuneric, 123, 348 Georgeta Iulia Balacea, 28, 204
Ana-Maria Arişanu, 218, 268 Gheorghe Dodescu, vi
Gina Balacea, 342
Carmen Mincă, 72, 130, 243, 335, 365
Cerasela-Daniela Cardaş, 84, 262 Ilie Dumitru, 187
Constantin Tudor, vi Ion Văduva, vi
Cristian Frâncu, 102, 268
Cristina Iordaiche, 234 Jakab Irma-Tunde, 90
Cristina Sichim, 175, 366
Lucia Miron, 137
Dan Pracsiu, 272
Dana Lica, 211, 348 Manz Victor-Claudiu, 190
Daniela Tătaru, 240 Marinel Şerban, 139
Daniela Tarasă, 345 Marius Nicoli, 27, 97, 207, 270
Dumitrascu Dan Octavian, 29
Nicoleta Şandor, 246
Emanuela Cerchez, 246
Nicoli Marius, 184
Flavius Boian, 76, 242
Florentina Ungureanu, 30, 202, 318 Susana Gălăţan, 351, 355

Gabor Ioana, 3 Violeta-Marilena Grecea, 22

422
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!

You might also like