Documente Academic
Documente Profesional
Documente Cultură
Olimpiada - cls7
2023-10
PROBLEME DE INFORMATICĂ
date la olimpiade
OJI + ONI
ı̂n
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!
”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
1
I.d.k.: ”I don’t know who the author is.”
Dedication
( 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
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
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”
and
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 - ...
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
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
2 OJI 2022 16
2.1 patratele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.1.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.1.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2 pseudocmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.2.2 *Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.2.3 Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
4 OJI 2020 57
4.1 foto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
4.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
4.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.2 wind . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
viii
4.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
5 OJI 2019 77
5.1 poarta - OJI 2019 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
5.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
5.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
5.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5.2 valutar - OJI 2019 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
5.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
5.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
6 OJI 2018 91
6.1 puzzle - OJI 2018 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
6.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
6.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
6.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
6.2 tbile - OJI 2018 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
6.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
6.2.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
6.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
7 OJI 2017 99
7.1 Cursuri - OJI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
7.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
7.1.2 Cod sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
7.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
7.2 joc - OJI 2017 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
7.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
7.2.2 Codul sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
7.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Index 403
Bibliografie 405
2.1 oji2022-patratele12 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2 oji2022-patratele3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3 oji2022-patratele un patratel fără linii . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.4 oji2022-patratele-NS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.5 oji2022-patratele-VE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6 oji2022-patratele-pereti-codificati . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.7 oji2022-pseudocmp-frecvenţe1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.8 oji2022-pseudocmp-frecvenţe2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
6.1 Puzzle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
6.2 tbile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
xv
C.8 Pregătit pentru Code::Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
C.9 Pregătit pentru a scrie cod de program C++ ı̂n Code::Blocks . . . . . . . . . . . . 366
C.10 Primul cod de program C++ ı̂n Code::Blocks . . . . . . . . . . . . . . . . . . . . . 367
C.11 Build - compilare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
C.12 0 error(s), 0 warning(s) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
C.13 Run - execuţie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
C.14 Executat corect: a făcut “nimic” . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
C.15 Settings % Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
C.16 Toolchain executables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
C.17 Unde sunt acele programe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
C.18 Multe surse ı̂n Code Blocks - setări . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
C.19 Multe surse in Code Blocks - exemple . . . . . . . . . . . . . . . . . . . . . . . . . 371
C.20 mingw64 pe D: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
C.21 search path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
C.22 System properties –¿ Advanced . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
C.23 Environment Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
C.24 Edit Environment Variables –¿ New . . . . . . . . . . . . . . . . . . . . . . . . . . 374
C.25 Calea şi versiunea pentru gcc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
C.26 Settings –¿ Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
C.27 Toolchain executables –¿ Auto-detect . . . . . . . . . . . . . . . . . . . . . . . . . . 376
C.28 New –¿ Text Document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
C.29 New text Document.txt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
C.30 Schimbare nume şi extensie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
C.31 Moore apps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
C.32 Look for another app . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
C.33 Cale pentru codeblocks.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
C.34 Selectare codeblocks.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
C.35 Editare test01.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
C.36 Compilare test01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
C.37 Mesaje după compilare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
C.38 Execuţie test01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
C.39 Rezultat execuţie test01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
C.40 Fişiere apărute după compilare! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
C.41 Creare test02.cpp gol! + ¡dublu click¿ sau ¡Enter¿ . . . . . . . . . . . . . . . . . . 382
C.42 Lista programelor de utilizat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
C.43 Selectare Code::Blocks IDE pentru fişierele .cpp . . . . . . . . . . . . . . . . . . 383
C.44 Editare+Compilare+Execuţie pentru test02 . . . . . . . . . . . . . . . . . . . . . 383
C.45 Selectare tab ce conţine test01.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 384
xvii
Lista programelor
1.1.1 oji2023-palindrom.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.2 oji2023-cecker-palindrom.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.1 oji2023-primprim.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2.2 oji2023-cecker-primprim.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.1 oji2022-patratele-v1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.1.2 oji2022-patratele-v2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.1.3 patratele-checker.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.2.1 oji2022-pseudocmp-v1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.2.2 oji2022-pseudocmp-v2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.2.3 oji2022-pseudocmp-v3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.2.4 oji2022-pseudocmp-frecvenţe3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.2.5 pseudocmp-checker.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
4.1.1 foto 1 c.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.1.2 foto 2 c.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
4.1.3 foto 1 cpp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
4.1.4 foto 2 cpp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
4.1.5 foto AB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.1.6 foto AF.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.1.7 foto cm rec.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4.1.8 fotoCS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.1.9 fotoFB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
4.1.10 fotoKB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.1.11 fotoMM.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.2.1 wind.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4.2.2 wind.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4.2.3 windCM.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4.2.4 windCS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
5.1.1 poarta1 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
5.1.2 poarta2 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
5.1.3 poarta3 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.1.4 poarta4 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.2.1 valutar cpp 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
5.2.2 valutar1 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.2.3 valutar2 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
6.1.1 p2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
6.1.2 p4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
6.2.1 t1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
6.2.2 t2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
7.1.1 cursuri Dan 100p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
7.1.2 cursuri NlogN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
7.1.3 cursuri NxN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
7.1.4 cursuri raluca 100p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
7.1.5 cursuri rm.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
7.2.1 joc.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
7.2.2 joc dl.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
7.2.3 joc pracsiu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
7.2.4 joc rm.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
8.1.1 axyz.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
8.2.1 galerie0.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
xviii
8.2.2 galerie1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
9.1.1 ech add11.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
9.1.2 ech lucia miron.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
9.1.3 ech Ovidiu Dumitrescu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
9.1.4 ech raluca costinescu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
9.1.5 ech vasile pit rada.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
9.2.1 lasere adrian pintea.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
9.2.2 lasere emanuela cerchez.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
9.2.3 lasere lucia miron.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
9.2.4 lasere nicu vlad.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
9.2.5 lasere raluca costinescu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
9.2.6 lasere vasile pit rada.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
10.1.1 patratdl.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
10.1.2 patratdt.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
10.1.3 patratMN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
10.1.4 patratsj.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
10.1.5 patratvg.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
10.2.1 schi.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
10.2.2 schidL.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
10.2.3 schidt.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
10.2.4 schiNQ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
10.2.5 schiNQcb.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
10.2.6 schiSortQ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
11.1.1 compar dm.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
11.1.2 compara en.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
11.2.1 unific em.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
11.2.2 unific eugen 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
12.1.1 arme Adrian.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
12.1.2 arme ema.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
12.1.3 arme Ovidiu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
12.2.1 tri adrian .cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
12.2.2 tri marinel .cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
12.2.3 triunghi Eugen00.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
12.2.4 triunghi Eugen11.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
12.2.5 triunghi Eugen22.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
12.2.6 triunghi O Marcu matrice.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
12.2.7 triunghi O Marcuo.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
13.1.1 RCGRUPE.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
13.2.1 litere.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
14.1.1 7 pr1 s.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
14.2.1 7 pr2 s.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
15.1.1 7 dominew.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
15.2.1 7 pix.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
15.3.1 7 secvmin.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
19.1.1 Domino 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
19.1.2 domino 2 assert.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
19.1.3 domino 3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
19.2.1 tuburi 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
19.2.2 tuburiOficial.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
19.3.1 venus 1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
19.3.2 venus 2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
21.1.1 carte.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
21.2.1 ghinde.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
21.3.1 submat cpp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
22.1.1 ABbirouri.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
22.1.2 CSbirouri.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
22.1.3 FUbirouri.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
22.2.1 ABcristale.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
22.2.2 CIcristale.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
22.2.3 CMcristale.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
22.2.4 CScristale.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
22.3.1 ABparchet.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
22.3.2 CSparchet.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
22.3.3 MSparchetBiti.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
22.3.4 MSparchetVector.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
23.1.1 cript emcerchez 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
23.1.2 cript LuciaMiron.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
23.1.3 cript odumitrascu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
23.1.4 cript rcostineanu 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
23.2.1 scadere 100 emcerchez.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
23.2.2 scadere 100 odumitrascu.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
23.3.1 tv odumitrascu 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
24.1.1 codat mn.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
24.1.2 codat patratic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
24.1.3 codat stack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
24.2.1 nod.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
24.2.2 nod dl pct1 2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
24.2.3 nod dt ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
24.3.1 placa.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
24.3.2 placa1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
24.3.3 placa2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
24.3.4 placa3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
24.3.5 placa4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
24.3.6 placa5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
24.3.7 placa6.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
24.3.8 placa8.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
24.3.9 placa10.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
25.1.1 secvp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
26.1.1 bile.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
26.2.1 proiecte1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
26.2.2 proiecte2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
26.3.1 zigzag.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
28.1.1 CHAR.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
28.2.1 MARATON.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
28.2.2 MARAton2.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
28.3.1 Roboti.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
B.1.1 sss1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
B.1.2 sss2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
D.4.1 exponentiere rapida1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
D.4.2 exponentiere rapida2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
D.4.3 exponentiere rapida3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
D.4.4 exponentiere rapida MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
D.5.1 exponentiere naiva MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
D.5.2 exponentiere rapida MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
D.6.1 secventa cod.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
E.2.1 cautare binara-v1-iterativ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394
E.2.2 cautare binara-v1-recursiv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
E.3.1 cautare binara-v2-iterativ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
E.3.2 cautare binara-v2-recursiv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
E.4.1 cautare binara-v3-iterativ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
E.4.2 cautare binara-v3-recursiv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
Part I
1
Capitolul 1
OJI 2023
1.1 palindrom
Problema 1 - Palindrom 100 de puncte
Un număr se numeşte palindrom dacă citit de la stânga la dreapta este identic cu numărul
citit de la dreapta la stânga. De exemplu, numerele 131 şi 15677651 sunt palindromuri. Un număr
care nu este palindrom poate fi transformat ı̂n palindrom adăugând la dreapta sa una sau mai
multe cifre.
Cerinţă
Dat fiind un şir de n numere naturale, scrieţi un program care să rezolve următoarele două
cerinţe:
1. să se determine numărul minim total de cifre care trebuie să fie adăugate, astfel ı̂ncât fiecare
valoare din şir să fie palindrom;
2. considerând că putem adăuga cel mult S cifre, să se determine numărul maxim de termeni
palindrom aflaţi pe poziţii consecutive ı̂n şirul obţinut.
Date de intrare
Fişierul de intrare palindrom.in conţine pe prima linie numărul C, reprezentând cerinţa care
trebuie să fie rezolvată (1 sau 2). Pe cea de a doua linie se află un număr natural n, reprezentând
numărul de valori din şir. Pe următoarele n linii se află cele n numere din şir, câte un număr pe o
linie. Dacă C 2, pe ultima linie a fişierului de intrare se va afla numărul natural S reprezentând
numărul maxim de cifre ce pot fi adăugate.
Date de ieşire
# Punctaj Restricţii
1 15 C 1 şi n 1.
2 10 C 2, S 0, 1 $ n100 şi numerele din şir au cel mult 18 cifre.
3 14 C 1, 1 $ n 1 000 şi numerele din şir au cel mult 18 cifre.
4 15 C 2, S % 0, 1 $ n 1 000 şi numerele din şir au cel mult 18 cifre.
5 16 C 2, 1 000 $ n 50 000 şi numerele din şir au cel mult 18 cifre.
6 13 C 1, 1 000 $ n 50 000 şi numerele din şir au ı̂ntre 19 şi 50 de cifre.
7 17 C 2, 1 000 $ n 50 000 şi numerele din şir au ı̂ntre 19 şi 50 de cifre.
Exemple:
2
CAPITOLUL 1. OJI 2023 1.1. PALINDROM 3
Propusă de: Prof. Emanuela Cerchez, Colegiul Naţional ”Emil Racoviţă”, Iaşi
Cerinţa 1. Vom citi succesiv numerele şi vom determina pentru fiecare număr citit numărul
minim de cifre care trebuie să fie adăugate pentru a transforma numărul respectiv ı̂n palindrom.
Pentru numere mari (de maximum 50 de cifre), vom citi fiecare număr caracter cu caracter,
până la ı̂ntâlnirea marcajului de sfârşit de linie şi vom reţine cifrele numărului ı̂ntr-un vector.
Pentru punctaj parţial (numere de maximum 18 cifre) se va citi numărul ı̂ntr-o variabilă de
tip long long int, apoi se vor extrage cifrele numărului şi se vor plasa ı̂ntr-un vector.
Pentru a determina numărul minim de cifre care trebuie adăugate la finalul numărului pentru a
transforma acest număr ı̂n palindrom putem determina lungimea celui mai lung sufix al numărului
care are proprietatea de a fi palindrom. Să notăm această lungime cu lgs iar lungimea numărului
cu lg. Numărul minim de cifre care trebuie să fie adăugate este nr lg lgs (se adaugă la final
primele nr cifre ale numărului ı̂n ordine inversată). Desigur, pentru punctaj parţial este posibilă
şi o abordare ”prin ı̂ncercări”:
Nu este necesar să reţinem toate numerele citite, vom reţine ı̂ntr-un vector nr cu n elemente
numărul minim de cifre care trebuie să fie adăugate pentru a transforma fiecare număr din şir ı̂n
palindrom. Rezultatul la cerinţa 1 este suma valorilor memorate ı̂n vectorul nr.
Cerinţa 2. Trebuie să determinăm cea mai lungă subsecvenţă a vectorului nr, construit
la cerinţa anterioară, care are suma elementelor mai mică sau egală cu S. Pentru aceasta vom
parcurge vectorul nr cât timp suma elementelor din secvenţa curentă (să o notăm sum) este & S.
Când am ajuns la o poziţie i pentru care sum nri % S elementul curent nu mai poate fi
”ı̂nghiţit” ı̂n soluţie. Prin urmare:
comparăm lungimea secvenţei curente cu lungimea maximă şi o reţinem dacă este mai mare;
eliminăm elementele de la ı̂nceputul secvenţei curente, actualizând corespunzător sum, până
când este posibil să ”ı̂nghiţim” valoarea nri ı̂n soluţie (sum nri & S).
CAPITOLUL 1. OJI 2023 1.1. PALINDROM 4
Când parcurgerea vectorului nr s-a ı̂ncheiat, trebuie să comparăm şi lungimea ultimei secvenţe
cu lungimea maximă.
2 3
Pentru punctaje parţiale sunt posibile şi abordări de complexitate O n sau O n .
Pentru S=0 este necesara determinarea lungimii maxime a zonelor de zerouri consecutive.
//ifstream fin("palindrom.in");
//ifstream fin("palindrom1.in");
//ifstream fin("palindrom2.in");
//ifstream fin("..//teste_palindrom//01-palindrom.in"); // C1
//ifstream fin("..//teste_palindrom//02-palindrom.in"); // C1
//ifstream fin("..//teste_palindrom//03-palindrom.in"); // C1
//ifstream fin("..//teste_palindrom//06-palindrom.in"); // C1
//ifstream fin("..//teste_palindrom//08-palindrom.in"); // C1
//ifstream fin("..//teste_palindrom//10-palindrom.in"); // C1
//ifstream fin("..//teste_palindrom//12-palindrom.in"); // C1
//ifstream fin("..//teste_palindrom//18-palindrom.in"); // C1
//ifstream fin("..//teste_palindrom//20-palindrom.in"); // C1
//ifstream fin("..//teste_palindrom//22-palindrom.in"); // C1
ofstream fout("palindrom.out");
int C; // cerinta
int n; // nr de numere
int S; // nr max cifre adaugate
char a[50001][51];
char nrp[105]; // construiesc palindrom
int nrca[50001]; // nr cifre adaugate
if(epalindrom == 1)
{
//cout<<"pentru lgs = "<<lgs
// <<" a devenit palindrom "<<nrp
// <<" adaugant lgs = "<<lgs<<" cifre"<<endl;
nmtca=nmtca+lgs;
nrca[i]=lgs;
//cout<<"\n<-- calcul1()"<<endl<<endl;
return 0;
} // sf calcul1()
calcul1();
sumc=nrca[i1];
//cout<<"sumc = "<<sumc<<endl;
//getchar();
i2=i1;
lgsc=i2-i1+1;
if(lgsc > lgsmax) lgsmax=lgsc;
//cout<<"lgsc = "<<lgsc<<" lgsmax = "<<lgsmax<<endl;
if(i2>n)
{
//cout<<"ATENTIE i2 = "<<i2
// <<" a depasit n = "<<n<<" **************"<<endl;
//getchar();
break; // a depasit n
}
sumc=sumc-nrca[i1];
i1=i1+1;
if(i1<=n)
{
sumc=nrca[i1];
i2=i1;
}
}// sf while(i2<=n)
//cout<<"\n<-- calcul2()"<<endl<<endl;
return 0;
} // sf calcul2()
calcul1();
// initializari
lgsc=0; // lg secventa curenta
lgsmax=0; // lg secventa maxima = 0
i1=0; // inceput secventa
i2=0; // sfarsit secventa
insecventa=0; // nu sunt in secventa
}// sf for i
i2=i;
lgsc=i2-i1;
if(lgsc > lgsmax) lgsmax=lgsc;
//cout<<"\n<-- calcul2S0()"<<endl<<endl;
return 0;
} // sf calcul2S0()
CAPITOLUL 1. OJI 2023 1.1. PALINDROM 8
int main()
{
fin>>C; //cout<<"C = "<<C<<endl;
fin>>n; //cout<<"n = "<<n<<endl<<endl;
if(C==2) fin>>S;
//cout<<"S = "<<S<<endl;
//cout<<"------------------"<<endl;
if(C==1)
{
calcul1();
//cout<<nmtca;
fout<<nmtca;
//cout<<endl<<endl;
} // sf if(C==2)
else
if(C==2)
{
if(S==0)
{
calcul2S0();
}
else
{
calcul2();
}
//cout<<lgsmax;
fout<<lgsmax;
}// sf if(C==2)
fin.close();
fout.close();
return 0;
}
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../teste_palindrom/24-palindrom.in", // input
(char*)"../teste_palindrom/24-palindrom.ok", // rezultat corect
(char*)"palindrom.out", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
compareRemainingLines();
}
CAPITOLUL 1. OJI 2023 1.2. PRIMPRIM 9
1.2 primprim
Problema 2 - Primprim 100 de puncte
Pentru un număr natural a definim costul ca fiind valoarea absolută (modulul) diferenţei dintre
a şi numărul prim cel mai apropiat de a.
Asupra unui şir de n numere naturale, situate pe poziţii numerotate de la 1 la n, se aplică, ı̂n
ordine, o succesiune de q operaţii.
O operaţie constă dintr-o ı̂nlocuire şi o afişare şi este descrisă sub forma i x p, cu semnificaţia:
Cerinţe
Cunoscând n şi cele n elemente ale şirului, scrieţi un program care să determine:
Date de intrare
Date de ieşire
1 & q & 2 10
5
# Punctaj Restricţii
1 20 C = 1, n 1
2 22 C = 1, 1 $ n & 1000
3 28 C = 2, n & 1000, q & 10
4 30 C = 2, nu există restricţii suplimentare
Exemple:
Cerinţa 1. Vom citi succesiv numerele şi vom afla succesiv costul pentru fiecare număr de la
intrare, reţinând ı̂ntr-o variabilă suma costurilor. În funcţie de abordarea folosită pentru calcularea
costurilor, se pot obţine diverse punctaje parţiale, dar punctajul maxim pe cerinţă se poate obţine
doar folosind metoda bazată pe ciurul lui Eratostene, abordare explicată mai sus.
Cerinţa 2. Pentru această cerinţă vom citi succesiv operaţiile şi le vom executa.
Pentru a obţine un cost total minim trebuie să adunăm cele mai mici p costuri. O abordare
eficientă se bazează pe observaţia că pentru orice număr costul este cel mult 57, fapt ce ne permite
să utilizăm un vector de frecvenţă f r, unde f ri = numărul de elemente din vectorul v care au
costul i.
Pentru fiecare operaţie, la modificarea unei valori din vector, vom decrementa frecvenţa costului
pentru vechea valoare şi vom incrementa frecvenţa costului pentru noua valoare.
Pentru a determina costul total minim pentru a obţine cel puţin p numere prime ı̂n vector
(valoarea afişată după executarea operaţiei), vom parcurge vectorul de frecvenţă de la stânga la
dreapta (i 0, ..., 57).
La fiecare pas i, pentru a calcula costul total minim adunăm la o variabilă cmin produsul
dintre f ri şi i (există f ri numere care pot fi transformate ı̂n numere prime cu costul i), iar
ı̂ntr-o variabilă nr reţinem câte numere prime au fost deja obţinute.
În momentul ı̂n care nr f ri % p, parcurgerea se opreşte şi adunăm la cmin doar costul
obţinerii celor p nr numere prime care mai sunt necesare (adică adunăm f ri p nr.
În funcţie de cum selectăm cele mai mici p costuri şi ı̂n funcţie de cum calculăm costurile, se
pot obţine diverse punctaje parţiale.
ifstream fin("primprim.in");
//ifstream fin("primprim1.in");
//ifstream fin("primprim2.in");
//ifstream fin("..//teste_primprim//01-primprim.in"); // C1
//ifstream fin("..//teste_primprim//07-primprim.in"); // C1
//ifstream fin("..//teste_primprim//12-primprim.in"); // C1
//ifstream fin("..//teste_primprim//13-primprim.in"); // C2
//ifstream fin("..//teste_primprim//21-primprim.in"); // C2
//ifstream fin("..//teste_primprim//29-primprim.in"); // C2
ofstream fout("primprim.out");
int C; // cerinta
int n; //
int a[1000001];
int q;
int i, x, p;
bool ciur[1000005];
int fr[100]; // este initializat automat cu zero ("zona globala")
int cost;
int costmax;
int primstanga;
int primdreapta;
int diststanga;
int distdreapta;
void ciurEratostene()
{
//cout<<"--> ciurEratostene()"<<endl;
ciur[0]=true; // rezulta din exemplul dat in enunt ... !
ciur[1]=false;
//cout<<"\ndistmaxprime = "<<distmaxprime<<endl<<endl;
//cout<<"<-- calcDistMax()"<<endl;
} // calcDistMax()
int costval;
primstanga=val;
primdreapta=val;
while(ciur[primstanga]==false) primstanga=primstanga-1;
while(ciur[primdreapta]==false) primdreapta=primdreapta+1;
diststanga=val-primstanga;
distdreapta=primdreapta-val;
costval=diststanga;
//cout<<primstanga
// <<" <= "<<val
// <<" <= "<<primdreapta
// <<" costval = "<<costval<<endl;
//cout<<"<-- calculCost("<<val<<")\n\n";
return costval;
}
int sumfr=0;
costmax=0;
sumacost=0;
while(ciur[primstanga]==false) primstanga=primstanga-1;
while(ciur[primdreapta]==false) primdreapta=primdreapta+1;
diststanga=a[i]-primstanga;
distdreapta=primdreapta-a[i];
//cout<<diststanga<<" "<<a[i]<<" "<<distdreapta<<endl;
cost=diststanga;
if(distdreapta < cost) cost = distdreapta;
//cout<<i<<" : "<<primstanga
// <<" <= "<<a[i]
// <<" <= "<<primdreapta
// <<" cost = "<<cost<<endl;
fr[cost]++; // ***********************
if(cost > costmax) costmax = cost;
//cout<<"fr["<<cost<<"] = "<<fr[cost]<<endl<<endl;
sumacost=sumacost + cost;
//cout<<cost<<" "<<a[i]<<" "<<sumacost<<endl<<endl;
//getchar();
}// sf for i
//cout<<"<-- calcul1()"<<endl;
} // sf calcul1()
int costvalai;
int costvalx;
int nrpoz; // numarul pozitiilor alese
int sumamin;
calcul1();
//afisfr();
CAPITOLUL 1. OJI 2023 1.2. PRIMPRIM 14
fin>>i>>x>>p;
//cout<<"----------------------------------------------------\n";
//cout<<"k = "<<k<<" : "<<"i = "<<i<<" x = "<<x<<" p = "<<p<<endl;
//cout<<"a["<<i<<"] = "<<a[i]<<endl;
costvalai=calculCost(a[i]);
costvalx=calculCost(x);
fr[costvalai]--;
fr[costvalx]++;
//afisfr();
int j;
j=0;
sumamin=sumamin+fr[j]*j;
nrpoz=nrpoz+fr[j];
//cout<<sumamin<<" *********************************\n"<<endl;
fout<<sumamin<<endl;
//getchar();
}// sf for k
//cout<<"<-- calcul2()"<<endl;
} // sf calcul2()
CAPITOLUL 1. OJI 2023 1.2. PRIMPRIM 15
int main()
{
fin>>C; //cout<<"C = "<<C<<endl;
fin>>n; //cout<<"n = "<<n<<endl<<endl;
ciurEratostene();
calcDistMax();
if(C==1)
{
calcul1();
//cout<<sumacost;
fout<<sumacost;
}
if(C==2)
{
fin>>q;
//cout<<"q = "<<q<<endl;
calcul2();
}
fin.close();
fout.close();
return 0;
}
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../teste_primprim/29-primprim.in", // input
(char*)"../teste_primprim/29-primprim.ok", // rezultat corect
(char*)"primprim.out", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
compareRemainingLines();
}
Capitolul 2
OJI 2022
2.1 patratele
Problema 1 - Pătrăţele 100 de puncte
Gigel are ı̂n faţa sa pe o foaie de matematică un desen obţinut prin trasarea mai multor linii
orizontale şi verticale de lungime 1 de-a lungul modelului foii de matematică.
Privind desenul de pe foaie el se ı̂ntreabă: ”Oare câte pătrate s-au format
din liniile trasate?”
În desenul alăturat se vede foaia formată din 3 linii şi 5 coloane, precum
şi liniile trasate până la un moment dat. Se pot distinge trei pătrate de
latură 1, două pătrate de latură 2 şi un pătrat de latură 3.
În problema noastră vom codifica fiecare pătrat de latură 1 de pe foaie cu un număr natural
cuprins ı̂ntre 0 şi 15 obţinut prin ı̂nsumarea codificării fiecărei laturi astfel:
1 - dacă latura de sus este trasată
2 - dacă latura din dreapta este trasată
4 - dacă latura de jos este trasată
8 - dacă latura din stânga este trasată
În acest fel desenul alăturat poate fi codificat printr-un tablou bidimensional de dimensiuni
3 5 cu valorile:
9 7 15 13 7
14 15 11 15 11
1 3 12 7 14
Cerinţe
Fiind date dimensiunile n şi m ale foii de matematică, precum şi tabloul bidimensional de
dimensiune n m care conţine codificarea foii, să se determine:
1. numărul total de pătrate existente pe foaia de matematică ı̂n desenul realizat conform
codificării
2. distribuţia numărului de pătrate ı̂n ordinea strict crescătoare a lungimii laturilor
3. unde poate fi trasată ı̂ncă o linie astfel ı̂ncât numărul total de pătrate să crească şi să devină
maxim posibil
Date de intrare
Fişierul de intrare patratele.in conţine pe prima linie trei numere naturale n m t, separate
prin câte un spaţiu, indicând dimensiunile foii de matematică n m, respectiv cerinţa care trebuie
rezolvată (1, 2 sau 3).
Fiecare dintre următoarele n linii conţine câte m numere naturale, fiecare dintre acestea
reprezentând codificarea foii de matematică.
Date de ieşire
16
CAPITOLUL 2. OJI 2022 2.1. PATRATELE 17
2. Dacă t 2, pe fiecare linie vor fi afişate câte două numere naturale nenule a şi b, separate
printr-un spaţiu, indicând lungimea laturii pătratelor - a, respectiv numărul de pătrate cu
latura de lungimea respectivă - b, ı̂n ordinea strict crescătoare a valorilor lui a;
3. Dacă t 3, prima linie va conţine numărul maxim de pătrate, iar linia a doua va conţine
2 valori naturale lin, col şi un cuvânt pozitie separate printr-un spaţiu, unde: lin, col
reprezintă coordonatele pătratului de latură 1 unde se trasează linia suplimentară; pozitie "
{SUS, DREAPTA, JOS, STANGA, NU} (se va afişa NU ı̂n cazul ı̂n care nu se poate trasa
nicio linie - ı̂n acest caz cele 3 valori numerice afişate vor fi de asemenea 0).
# Punctaj Restricţii
1 30 t=1
2 30 t=2
3 10 t = 3 şi 1 n,m 20
4 30 t=3
Exemple:
pentru latura de sus, dacă această latură există, atunci x&1 1 sau x%2 1
pentru latura din dreapta, dacă această latură există, atunci x&2 = 1 sau x©2%2 1
pentru latura de jos, dacă această latură există, atunci x&2 4 sau x©4%2 1
pentru latura din stânga, dacă această latură există, atunci x&2 8 sau x©8%2 1
2
Cerinţele 1 şi 2. Complexitate timp O n m min n, m
(1) determinăm latura maximă lmax min n, m pe care o poate avea un pătrat
(2) pentru toate laturile posibile 1 & l & lmax verificăm toate posibilităţile de a exista un pătrat
de latura l, cu colţul stânga-sus ı̂n poziţia xs , ys (evident xs parcurge valorile de la 1 la
n l 1 iar ys toate valorile de la 1 la m l 1)
(3) pentru fiecare pătrat de latură l şi colţul stânga-sus ı̂n xs , ys verificăm dacă cele 4 laturi
sunt complet desenate, iar dacă da incrementam un contor.
Pentru prima cerinţă doar numărăm pătratele care respectă condiţia de mai sus.
Pentru cea de-a doua cerinţă, vom cunstrui un vector de frecvenţă cntk = numărul de pătrate
de latură k ce respectă condiţia. Se afisează toate perechile k, cntk , pentru care cntk % 0.
2 2
Cerinţa 3. Complexitate timp O n m min n, m
Pentru fiecare celulă i, j şi pentru fiecare perete 0 & d & 3 se verifică dacă peretele d al celulei
i, j este desenat sau nu. Dacă peretele nu este desenat:
se desenează (a nu se uita să se marcheze această desenare şi celulei cu care se ı̂nvecinează
celula i, j prin peretele d)
CAPITOLUL 2. OJI 2022 2.1. PATRATELE 19
Soluţia 3 - Asist. Drd. Alexandru Ioniţă. Universitatea ”Alexandru Ioan Cuza” din Iaşi
Pentru rezolvarea cerinţei 3 există o soluţie mai eficientă. Această soluţie obţine de asemenea
100 de puncte.
2 2
Complexitate timp O n m
Soluţia presupune următoarea precalculare:
Fiecare linie orizontală din partea de sus a unei celule i, j din foaie va fi marcată ı̂ntr-o
matrice: sp0i,j 1. Peste matricea sp0 vom face apoi sume parţiale pentru a putea afla ı̂n O 1
câte linii din partea de sus sunt setate pe un anumit interval dintr-un rând. Vom repeta aceste
operaţii pentru toate tipurile de linii rămase, generând cate o astfel de matrice pentru fiecare
direcţie rămasă: sp1 dreapta, sp2 jos, sp3 stanga.
Vom itera astfel prin fiecare patrat (determinat unic de o celula x, y si o lungime l) ce poate
fi ı̂ncadrat in foaia de dimensiune n m, având 3 cazuri:
(1) pătratul are toate laturile complet acoperite de linii deja trasate
(2) pătratul mai are nevoie ca exact o singura linie sa fie trasată pentru a fi complet acoperit
(3) Pătratul are nevoie de mai mult de o linie sa fie trasată pentru a fi complet acoperit.
Cazurile (1) si (3) nu ne interesează ı̂n mod special (trebuiesc doar numărate câte pătrate sunt
in cazul (1), pentru a fi adăugate la răspuns).
În schimb, cazul (2) este de interes: pentru aceste pătrate trebuie să vedem care este linia
lipsă.
Dacă notăm cu x, y celula liniei respective şi cu z tipul liniei (z 0 dacă este SUS, z 1, dacă
este DREAPTA, etc..) incrementând cu o unitate la coordonatele liniei ı̂ntr-o matrice usedx,y,z .
Această marcare trebuie făcută şi pentru celula vecina acestei linii (daca tocmai am analizat
o linie de tipul SUS din celula x, y , va trebui să incrementăm valoarea ı̂n used şi pentru celula
x 1, y linia de JOS).
Observaţi că, făcând aceste marcări pentru fiecare pătrat, la final, ı̂n matricea used vom avea
la fiecare poziţie x, y, z numărul de pătrate care vor fi completate ı̂n cazul in care trasăm linia
corespunzătoare acelei poziţii.
Astfel, nu ne rămâne decât să căutăm care este celula cu cea mai mare valoare din vectorul
used si să ı̂i afişăm coordonatele.
// Atentie la prioritati: ... mai bine pun mereu paranteze ... !!!
// 10: == si !=
// 11: a&b
//if( a[n][j]&sud != 0) // asa da gresit ... !!!
//if((a[n][j]&sud) != 0) // asa da corect ... !!!
//#include <bits/stdc++.h>
//ifstream fin("patratele.in");
// ------------------------------------------------------
//ifstream fin("../teste_patratele/01-patratele.in"); //
//ifstream fin("../teste_patratele/05-patratele.in"); //
//ifstream fin("../teste_patratele/10-patratele.in"); //
// ------------------------------------------------------
//ifstream fin("../teste_patratele/11-patratele.in"); //
//ifstream fin("../teste_patratele/15-patratele.in"); //
//ifstream fin("../teste_patratele/20-patratele.in"); //
// ------------------------------------------------------
//ifstream fin("../teste_patratele/21-patratele.in"); // time : 0.035 s
//ifstream fin("../teste_patratele/31-patratele.in"); // time : 1.085 s
//ifstream fin("../teste_patratele/32-patratele.in"); // time : 1.142 s
//ifstream fin("../teste_patratele/37-patratele.in"); // time : 0.935 s
//ifstream fin("../teste_patratele/38-patratele.in"); // time : 2.142 s
//ifstream fin("../teste_patratele/42-patratele.in"); // time : 3.371 s
ifstream fin("../teste_patratele/44-patratele.in"); // time : 4.083 s s
//ifstream fin("../teste_patratele/45-patratele.in"); // time : 3.979 s
// ------------------------------------------------------
ofstream fout("patratele.out");
int n; // linii
int m; // coloane
int t; // cerinta
int sus=1;
int dreapta=2;
int jos=4;
int stanga=8;
// ----------------------------------------------------------------
void afisa() // pentru faza de testare ... datele din enunt ... !!!
{
for(int i=1; i<=n+1; i++)
{
for(int j=1; j<=m+1; j++)
{
cout<<setw(3)<<a[i][j];
}
cout<<endl;
}
cout<<endl;
//getchar();
}// void afisa()
// ====================================================================
}
CAPITOLUL 2. OJI 2022 2.1. PATRATELE 23
}
}
if(ok==false) continue; // iau alt lg
}
}
if(ok==false) continue; // alt lg
}// void verific(int iss, int jss) // pentru lg=1, ..., ***
// ------------------------------------------------------
// =============================================================
void cerinta2()
{
cerinta1();
for(int i=1; i<=lgmaxnm; i++)
{
if(distributia[i] > 0) // nu se afiseaza cele cu 0 ... !!!
{
fout<<i<<" "<<distributia[i]<<endl;
}
}
} // void cerinta2()
// =============================================================
cerinta1();
// ------------------------------------------------------------------
cerinta1();
// ============================================
CAPITOLUL 2. OJI 2022 2.1. PATRATELE 25
void cerinta3()
{
t1 = clock();
t2 = clock();
t21=(double)(t2 - t1) / CLOCKS_PER_SEC;
//cout<<" t21 = "<<t21<<endl;
//---------------------------
if(nrp1max==nrp1initial)
{
cout<<"0"<<endl; cout<<"0 0 NU";
fout<<"0"<<endl; fout<<"0 0 NU";
return;
}
//cout<<nrp1max<<endl;
//cout<<pozitia3i<<" "<<pozitia3j<<" ";
//if(pozitia3d==1) cout<<"SUS"; else
//if(pozitia3d==2) cout<<"DREAPTA"; else
//if(pozitia3d==4) cout<<"JOS"; else
//if(pozitia3d==8) cout<<"STANGA";
fout<<nrp1max<<endl;
fout<<pozitia3i<<" "<<pozitia3j<<" ";
if(pozitia3d==1) fout<<"SUS"; else
if(pozitia3d==2) fout<<"DREAPTA"; else
if(pozitia3d==4) fout<<"JOS"; else
if(pozitia3d==8) fout<<"STANGA";
return;
} // cerinta3()
// ==========================================================
CAPITOLUL 2. OJI 2022 2.1. PATRATELE 26
int main()
{
fin>>n>>m>>t;
if(t==1)
{
cerinta1();
cout<<"nrp1 = "<<nrp1<<endl;
fout<<nrp1<<endl;
}
else
if(t==2)
{
cerinta2();
}
else
if(t==3)
{
// linia n+1
for(int j=1; j<=m; j++)
if((a[n][j]&sud) != 0) a[n+1][j]=nord;
// coloana m+1
for(int i=1; i<=n; i++)
if((a[i][m]&est) != 0) a[i][m+1]=vest;
cerinta3();
//cout<<"\n\n";
//cout<<" t21 = "<<t21<<endl;
//cout<<" t32 = "<<t32<<endl;
}
fin.close();
fout.close();
return 0;
}
303
304 // patratel pe linia i si col=j1...j2, (pe linia i la N este ok)
305 bool calculSpreSud(int i, int j, int j1,int j2)
306 {
307 int lg=j2-j1+1;
308 int i1, i2;
309
310 i1=i;
311 i2=i1+lg-1; // unde ajunge in jos
312
313 if(i2>n) // iese afara in jos
314 {
315 depasireSud=true;
316 return false;
317 }
318
319 // linia la N este ok
320
321 if(lg==1) // j1=j2=j
322 {
323 if(((a[i][j] & vest) == 0) || // nu are la vest
324 ((a[i][j] & sud) == 0) || // nu are la sud
325 ((a[i][j] & est) == 0)) // nu are la est
326 {
327 if((a[i][j] & vest)==0)
328 {
329 lipsaVestj1=true;
330 }
331
332 return false;
333 }
334 else
335 {
336 return true;
337 }
338 }
339
340 // verific coloana j1
341 // cand j2=j --> j2 este primul in secventa lui j1
342 if(j2==j) //j2=primul --> j1 se verifica tot
343 {
344 for(int ii=i1; ii<=i2; ii++)
345 {
346 if((a[ii][j1]&vest) == 0)
347 {
348 lipsaVestj1=true; return false;
349 }
350 }
351 }
352 else // j2 nu este primul --> se verifica numai ultimul din coloana j1
353 {
354 verificNumaiUltimul++;
355 if((a[i2][j1]&vest) == 0)
356 {
357 lipsaVestj1=true; return false;
358 }
359 }
360
361 // aici coloana j1 este ok
362 // verific coloana j2 la E care este si coloana j2+1 la Vest ... !!!
363 for(int ii=i1; ii<=i2; ii++)
364 if((a[ii][j2+1]&vest) == 0) { return false; }
365
366 // verific linia i2 la S care este si linia i2-1 la N
367 for(int jj=j1; jj<=j2; jj++)
368 {
369 if((a[i2+1][jj]&nord) == 0)
370 {
371 return false;
372 }
373 }
374
375 return true;
376 } // calculSpreSud(int i, int j, int j1,int j2)
377
378 // =================================================================================
CAPITOLUL 2. OJI 2022 2.1. PATRATELE 32
379
380 // patratel spre Vest, pe coloana j, intre liniile i1 ... i2
381 bool calculSpreVest(int i, int j, int i1,int i2)
382 {
383 int lg=i2-i1+1;
384 int j1, j2;
385
386 j2=j-1;
387 j1=j2-lg+1; // unde ajunge in stanga
388
389 if(j1<1) // iese afara in stanga
390 {
391 depasireVest=true; return false;
392 }
393
394 if(lg==1) // i1=i2=i
395 {
396 if(((a[i][j-1] & nord) == 0) || // nu are la nord
397
398 ((a[i][j-1] & vest) == 0) || // nu are la vest
399
400 ((a[i][j-1] & sud) ==0)) // nu are la sud
401 {
402 if((a[i][j-1] & nord)==0)
403 {
404 lipsaNordi1=true;
405 }
406
407 return false;
408 }
409 else
410 {
411 return true;
412 }
413 }
414
415 // verific linia i1 la Nord
416 // cand i2=i --> i2 este primul in secventa lui i1
417 if(i2==i) //i2=primul --> se verifica toata linia i1
418 {
419 for(int jj=j1; jj<=j2; jj++)
420 if((a[i1][jj]&nord) == 0)
421 {
422 lipsaNordi1=true;
423 return false;
424 }
425 }
426 else // i2 nu este primul --> se verifica numai ultimul din linia i1
427 {
428 if((a[i1][j1]&nord) == 0) // nu mai are rost verificare in i2 ... !!!
429 {
430 lipsaNordi1=true;
431 return false;
432 }
433 }
434
435 // verific linia i2 la S care este si linia i2+1 la Nord ... !!!
436 for(int jj=j1; jj<=j2; jj++)
437 if((a[i2+1][jj]&nord) == 0)
438 {
439 return false;
440 }
441
442 // verific linia V ... pe j=j1
443 for(int ii=i1; ii<=i2; ii++)
444 {
445 if((a[ii][j1]&vest) == 0)
446 {
447 return false;
448 }
449 }
450
451 return true;
452 }// bool calculSpreVest(int i, int j, int i1,int i2)
453
454 // ---------------------------------------------------------------------------
CAPITOLUL 2. OJI 2022 2.1. PATRATELE 33
455
456 bool calculSpreEst(int i, int j, int i1,int i2)
457 {
458 int lg=i2-i1+1;
459 int j1, j2;
460
461 j1=j;
462 j2=j1+lg-1; // unde ajunge in stanga
463
464 if(j2>m) // iese afara in dreapta
465 {
466 depasireEst=true;
467 return false;
468 }
469
470 if(lg==1) // i1=i2=i
471 {
472 if(((a[i][j] & nord) == 0) || // nu are la nord
473
474 ((a[i][j] & est) == 0) || // nu are la est
475
476 ((a[i][j] & sud) == 0)) // nu are la sud
477 {
478 if((a[i][j] & nord)==0)
479 {
480 lipsaNordi1=true;
481 }
482
483 return false;
484 }
485 else
486 {
487 return true;
488 }
489 }
490
491 // verific linia i1
492 // cand i2=i --> i2 este primul in secventa lui i1
493 if(i2==i) //i2=primul --> se verifica toata linia i1
494 {
495 for(int jj=j1; jj<=j2; jj++)
496 if((a[i1][jj]&nord) == 0)
497 {
498 lipsaNordi1=true;
499 return false;
500 }
501 }
502 else // i2 nu este primul --> se verifica numai ultimul din linia i1
503 {
504 if((a[i1][j2]&nord) == 0) // nu mai are rost verificare in i2 ... !!!
505 {
506 lipsaNordi1=true;
507 return false;
508 }
509 }
510
511 // verific linia i2 la S care este si linia i2+1 la Nord ... dar nu conteza aici !!!
512 //cout<<"verific linia "<<i2<<" la S\n";
513 for(int jj=j1; jj<=j2; jj++)
514 if((a[i2+1][jj]&nord) == 0)
515 {
516 return false;
517 }
518
519 // verific coloana j2 la Este care este sicoloana j2+1 la Vest
520 for(int ii=i1; ii<=i2; ii++)
521 if((a[ii][j2+1]&vest) == 0)
522 {
523 return false;
524 }
525
526 return true;
527 }// calculSpreEst(int i, int j, int i1,int i2)
528
529 // =================================================================================
530
CAPITOLUL 2. OJI 2022 2.1. PATRATELE 34
531 void verificLaNord(int i, int j, int jj1, int jj2) // am pus linie la N in a[i][j]
532 {
533 // caut patrate spre N care sa contina latura de N din a[i][j]
534 // cu coloanele [j1,j2] in zona [jj1,jj2]
535
536 for(int j1=j; j1>=jj1; j1--) // numai Nord ... !!!
537 {
538 for(int j2=j; j2<=jj2; j2++)// cand j2=j --> j2 este primul in secventa lui j1
539 {
540 // j2 modifica lg ...
541 depasireNord=false;
542 lipsaVestj1=false;
543
544 if(calculSpreNord(i,j,j1,j2)==true)
545 {
546 patrateleinplus++;
547 }
548 else // daca a depasit spre nord --> break la j2
549 {
550 if(depasireNord==true) break; // depasire la N --> alt i1
551 if(lipsaVestj1==true) break; // lipsa la V in j1 --> alt i1
552 }
553
554 }// for j2
555 }// for j1
556
557 // caut patrate spre S care sa contina latura de N din a[i][j]
558 // cu coloanele [j1,j2] in zona [jj1,jj2]
559
560 for(int j1=j; j1>=jj1; j1--) // numai Sud ... !!!
561 {
562 for(int j2=j; j2<=jj2; j2++)// cand j2=j --> j2 este primul in secventa lui j1
563 {
564 // j2 modifica lg ...
565 depasireSud=false;
566 lipsaVestj1=false;
567
568 if(calculSpreSud(i,j,j1,j2)==true)
569 { patrateleinplus++; }
570 else { }
571
572 if(depasireSud==true) break; // depasire la S --> alt j1
573 if(lipsaVestj1==true) break; // lipsa la V in j1 --> alt j1
574 }// for j2
575 }// for j1
576
577 }// void verificLaNord(int i, int j)
578
579 // ----------------------------------------------------------------------------
580
581 void verificLaVest(int i, int j, int ii1, int ii2) // am pus linie la N in a[i][j]
582 {
583 for(int i1=i; i1>=ii1; i1--)
584 {
585 for(int i2=i; i2<=ii2; i2++)// cand i2=i --> i2 este primul in secventa lui i1
586 {
587 // i2 modifica lg ...
588 depasireVest=false;
589 lipsaNordi1=false;
590
591 if(calculSpreVest(i,j,i1,i2)==true)
592 {
593 patrateleinplus++;
594 //cout<<patrateleinplus<<" V : "<<" i1 = "<<i1<<" i2 = "<<i2<<endl;
595 //getchar();
596 }
597 else // daca a depasit spre nord --> break la j2
598 {
599
600 }
601
602 if(depasireVest==true) break; // depasire la V --> alt i1
603 if(lipsaNordi1==true) break; // lipsa la N in i1 --> alt i1
604 }// for i2
605 }// for i1
606
CAPITOLUL 2. OJI 2022 2.1. PATRATELE 35
683
684 a[i][j]=a[i][j]-vest; // SCOT linie la V;
685 a[i][j-1]=a[i][j-1]-est; // SCOT linie la E pe coloana anterioara
686
687 if(patrateleinplus > patrateleinplusmax)
688 {
689 patrateleinplusmax=patrateleinplus;
690 pozitia3i=i;
691 pozitia3j=j;
692 pozitia3d=vest;
693 }
694 }// void lipsaLaVest(int i, int j)
695 // ========================================================================
696
697 void cerinta3()
698 {
699 t1 = clock();
700
701 // primul apel ...
702 cerinta1();
703 nrpmax1=nrp1; // nr initial de patratele
704
705 pozitia3d=0; // directie pentru cerinta 3: nord, est, sud, vest
706 pozitia3i=0; // i pozitia pentru cerinta 3: 1 <= i <= n
707 pozitia3j=0; // j pozitia pentru cerinta 3: 1 <= j <= m
708
709 t2 = clock();
710 t21=(double)(t2 - t1) / CLOCKS_PER_SEC;
711 //cout<<" t21 = "<<t21<<endl;
712 //---------------------------
713
714 // pentru cerinta 3 caut linii orizontale lipsa la N
715 for(int i=1; i<=n+1; i++) // si linia n+1="bordura"
716 {
717 for(int j=1; j<=m; j++) // a[i][j]
718 {
719 if((a[i][j] & nord) == 0) // nu are linie la nord
720 {
721 lipsaLaNord(i,j); // a[i][j] are lipsa N
722 }
723 }// for j
724 }// for i
725
726 //---------------------------
727
728 t3 = clock();
729 t32=(double)(t3 - t2) / CLOCKS_PER_SEC;
730 //cout<<" t32 = "<<t32<<endl;
731
732 // pentru cerinta 3 caut linii verticale lipsa la V
733 for(int i=1; i<=n; i++)
734 {
735 for(int j=1; j<=m+1; j++) // si coloana m+1="bordura"
736 {
737 if((a[i][j] & vest) == 0) // nu are linie la vest
738 {
739 lipsaLaVest(i,j); // a[i][j] are lipsa V
740 }
741 }// for j
742 }// for i
743
744 //---------------------------
745
746 t4 = clock();
747 t43 = (double)(t4 - t3) / CLOCKS_PER_SEC;
748 //cout<<" t43 = "<<t43<<endl;
749
750 if(patrateleinplusmax==0)
751 {
752 cout<<"0"<<endl; cout<<"0 0 NU";
753 fout<<"0"<<endl; fout<<"0 0 NU";
754 return;
755 }
756
757 nrpmax=nrpmax1+patrateleinplusmax;
758
CAPITOLUL 2. OJI 2022 2.1. PATRATELE 37
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../teste_patratele/45-patratele.in", // input
(char*)"../teste_patratele/45-patratele.ok", // rezultat corect
(char*)"patratele.out", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
compareRemainingLines();
}
2.2 pseudocmp
Problema 2 - Pseudocmp 100 de puncte
Àles a primit ca temă următoarea problemă: ”Fiind dat un şir A cu N numere naturale
distincte, să se calculeze suma cifrelor fiecărui element al şirului”.
După ce şi-a terminat tema, acesta observă că sunt mai multe perechi de indici i, j pentru
care dacă Ai $ Aj atunci Si % Sj , unde Si reprezintă suma cifrelor lui Ai . El le va numi pe acestea
perechi speciale de indici.
Cerinţe
Terminând prea repede tema, Àles primeşte o temă suplimentară cu două cerinţe:
1. Determină două numere aflate ı̂n şirul A, pentru care indicii corespunzători formează o
pereche specială.
2. Câte perechi speciale de indici i, j se găsesc ı̂n şirul A?
Date de intrare
Pe prima linie a fişierului pseudocmp.in se găsesc două numere naturale: T şi N . Pe
următoarea linie se găsesc N numere naturale, separate printr-un spaţiu, reprezentând valorile
din şirul A. Numărul T reprezintă numărul cerinţei.
Date de ieşire
Pe prima linie a fişierului pseudocmp.out:
1. Dacă T 1, se găsesc două numere naturale x, y, cu x $ y, separate printr-un spaţiu,
reprezentând răspunsul pentru cerinţa 1 dacă există soluţie sau -1, dacă nu există soluţie.
Dacă există mai multe soluţii, se acceptă oricare dintre acestea.
2. Dacă T 2, se găseşte un singur număr natural, reprezentând răspunsul la cerinţa 2.
Restricţii şi precizări
1 & N & 100 000
1 & Ai & 1 000 000, pentru 1 & i & N
# Punctaj Restricţii
1 15 T 1, N & 1000
2 25 T 1, 1000 $ N
3 25 T 2, N & 1000
4 35 T 2, 1000 $ N
CAPITOLUL 2. OJI 2022 2.2. PSEUDOCMP 39
Exemple:
//ifstream fin("pseudocmp1.in");
//ifstream fin("pseudocmp2.in");
//ifstream fin("pseudocmp3.in");
// cazul1
//ifstream fin("../teste_pseudocmp/10-pseudocmp.in"); // -1
//ifstream fin("../teste_pseudocmp/11-pseudocmp.in"); // 77 80 / 4 111
//ifstream fin("../teste_pseudocmp/12-pseudocmp.in"); // 89 101 / 6 101
//ifstream fin("../teste_pseudocmp/13-pseudocmp.in"); // 982656 982682
//ifstream fin("../teste_pseudocmp/14-pseudocmp.in"); // 993547 993555 time : 0.913 s
// cazul2
//ifstream fin("../teste_pseudocmp/18-pseudocmp.in"); // 1564 time: 0.033 s
//ifstream fin("../teste_pseudocmp/19-pseudocmp.in"); // 32573 time: 0.034 s
//ifstream fin("../teste_pseudocmp/20-pseudocmp.in"); // 30493 time: 0.030 s
//ifstream fin("../teste_pseudocmp/21-pseudocmp.in"); // 161975 time: 0.042 s
//ifstream fin("../teste_pseudocmp/22-pseudocmp.in"); // 163499 time: 0.045 s
ofstream fout("pseudocmp.out");
int T;
int N;
int ips, jps; // pereche speciala
void afisa()
{
cout<<"a[]: ";
for(int i=1; i<=N; i++) { cout<<setw(3)<<a[i]<<" "; }
cout<<endl;
}
void afiss()
{
cout<<"s[]: ";
for(int i=1; i<=N; i++) { cout<<setw(3)<<s[i]<<" "; }
cout<<endl;
}
CAPITOLUL 2. OJI 2022 2.2. PSEUDOCMP 41
while(nr>0)
{
sc=sc+nr%10;
nr=nr/10;
}
return sc;
}
void cerinta1()
{
// a[i]<a[j] --> s[i] <= s[j] pentru oricare i, j ...
bool existapereche=false;
if(existapereche==true) break;
}
if(existapereche==false)
{
cout<<"NU exista --> -1";
fout<<"-1";
return;
}
else
{
fout<<a[ips]<<" "<<a[jps];
return;
}
return;
}
void cerinta2()
{
for(int i=1; i <= N-1; i++)
{
for(int j=i+1; j<=N; j++) // i<j --> a[i]<a[j]
{
if(s[i]>s[j])
{
nrps++;
//cout<<a[i]<<" "<<a[j]<<endl;
}
}
}
//cout<<endl;
cout<<"nrps = "<<nrps<<endl;
fout<<nrps<<endl;
return;
}
CAPITOLUL 2. OJI 2022 2.2. PSEUDOCMP 42
int main()
{
t1 = clock();
fin>>T;
fin>>N;
cout<<"Cerinta = "<<T<<endl;
//afisa();
sort(a,a+N+1);
//afisa();
t3 = clock();
if(T==1)
{
cerinta1();
}
if(T==2)
{
cerinta2();
}
t4 = clock();
fin.close();
fout.close();
return 0;
}
//ifstream fin("pseudocmp1.in");
//ifstream fin("pseudocmp2.in");
//ifstream fin("pseudocmp3.in");
// cazul1
//ifstream fin("../teste_pseudocmp/10-pseudocmp.in"); // -1
//ifstream fin("../teste_pseudocmp/11-pseudocmp.in"); // 77 80 / 4 111
//ifstream fin("../teste_pseudocmp/12-pseudocmp.in"); // 89 101 / 6 101
//ifstream fin("../teste_pseudocmp/13-pseudocmp.in"); // 982656 982682
//ifstream fin("../teste_pseudocmp/14-pseudocmp.in"); // 993547 993555 time : 0.046 s
//ifstream fin("../teste_pseudocmp/15-pseudocmp.in"); // 995465 995473 time : 0.056 s
//ifstream fin("../teste_pseudocmp/16-pseudocmp.in"); // 996392 996409 time : 0.046 s
//ifstream fin("../teste_pseudocmp/17-pseudocmp.in"); // 994096 994149 time : 0.059 s
CAPITOLUL 2. OJI 2022 2.2. PSEUDOCMP 43
// cazul2
//ifstream fin("../teste_pseudocmp/18-pseudocmp.in"); // 1564 time: 0.033 s
//ifstream fin("../teste_pseudocmp/19-pseudocmp.in"); // 32573 time: 0.034 s
//ifstream fin("../teste_pseudocmp/20-pseudocmp.in"); // 30493 time: 0.030 s
//ifstream fin("../teste_pseudocmp/21-pseudocmp.in"); // 161975 time: 0.042 s
//ifstream fin("../teste_pseudocmp/22-pseudocmp.in"); // 163499 time: 0.045 s
ifstream fin("../teste_pseudocmp/23-pseudocmp.in"); // 407455698 time: 4.073 s
//ifstream fin("../teste_pseudocmp/24-pseudocmp.in"); // 929807449 time: 8.731 s
//ifstream fin("../teste_pseudocmp/25-pseudocmp.in"); // 1187288553 time: 11.090 s
//ifstream fin("../teste_pseudocmp/26-pseudocmp.in"); // 2 323 419 429 time: 8.178 s
//ifstream fin("../teste_pseudocmp/27-pseudocmp.in"); // 2631709609 time : 9.046 s
//ifstream fin("../teste_pseudocmp/28-pseudocmp.in"); // 2631683600 time : 9.077 s
//ifstream fin("../teste_pseudocmp/29-pseudocmp.in"); // 2631701158 time : 9.051 s
ofstream fout("pseudocmp.out");
int T;
int N;
int ips, jps; // pereche speciala
long long nrps=0; // nr perechi speciale
void afisa()
{
cout<<"a[]: ";
for(int i=1; i<=N; i++) { cout<<setw(3)<<a[i]<<" "; }
cout<<endl;
}
void afiss()
{
cout<<"s[]: ";
for(int i=1; i<=N; i++) { cout<<setw(3)<<s[i]<<" "; }
cout<<endl;
}
void cerinta1() // a[i]<a[j] --> s[i] <= s[j] pentru oricare i, j ...
{
bool existapereche=false;
for(int i=1; i <= N-1; i++) // a[i] < a[i+1]
{
if(s[i]>s[i+1])
{
existapereche=true;
ips=i;
break;
}
}
if(existapereche==false)
{
cout<<"NU exista --> -1";
fout<<"-1";
return;
}
else
{
fout<<a[ips]<<" "<<a[ips+1];
return;
}
return;
}
CAPITOLUL 2. OJI 2022 2.2. PSEUDOCMP 44
void cerinta2()
{
for(int i=1; i <= N-1; i++)
{
for(int j=i+1; j<=N; j++) // i<j --> a[i]<a[j]
{
if(s[i]>s[j])
{
nrps++;
//cout<<a[i]<<" "<<a[j]<<endl;
}
}
}
//cout<<endl;
cout<<"nrps = "<<nrps<<endl;
fout<<nrps<<endl;
return;
}
int main()
{
t1 = clock();
fin>>T;
fin>>N;
cout<<"T = "<<T<<" N = "<<N<<endl;
t2 = clock();
cout<<"Cerinta = "<<T<<endl;
//afisa();
sort(a,a+N+1);
//afisa();
t3 = clock();
if(T==1) { cerinta1(); }
if(T==2) { cerinta2(); }
t4 = clock();
fin.close();
fout.close();
return 0;
}
//ifstream fin("pseudocmp1.in");
//ifstream fin("pseudocmp2.in");
//ifstream fin("pseudocmp3.in");
// cazul1
//ifstream fin("../teste_pseudocmp/10-pseudocmp.in"); // -1
//ifstream fin("../teste_pseudocmp/11-pseudocmp.in"); // 77 80 / 4 111
//ifstream fin("../teste_pseudocmp/12-pseudocmp.in"); // 89 101 / 6 101
//ifstream fin("../teste_pseudocmp/13-pseudocmp.in"); // 982656 982682
//ifstream fin("../teste_pseudocmp/14-pseudocmp.in"); //993547 993555 : 0.046 s
//ifstream fin("../teste_pseudocmp/15-pseudocmp.in"); //995465 995473 : 0.056 s
//ifstream fin("../teste_pseudocmp/16-pseudocmp.in"); //996392 996409 : 0.046 s
//ifstream fin("../teste_pseudocmp/17-pseudocmp.in"); //994096 994149 : 0.059 s
// cazul2
//ifstream fin("../teste_pseudocmp/18-pseudocmp.in"); // 1564 time: 0.033 s
//ifstream fin("../teste_pseudocmp/19-pseudocmp.in"); // 32573 time: 0.034 s
//ifstream fin("../teste_pseudocmp/20-pseudocmp.in"); // 30493 time: 0.030 s
//ifstream fin("../teste_pseudocmp/21-pseudocmp.in"); // 161975 time: 0.042 s
//ifstream fin("../teste_pseudocmp/22-pseudocmp.in"); // 0.045 s--> 0.016 s
//ifstream fin("../teste_pseudocmp/23-pseudocmp.in"); // 4.073 s--> 0.033 s
//ifstream fin("../teste_pseudocmp/24-pseudocmp.in"); // 8.731 s --> 0.045 s
//ifstream fin("../teste_pseudocmp/25-pseudocmp.in"); // 11.090 s --> 0.073 s
//ifstream fin("../teste_pseudocmp/26-pseudocmp.in"); // 8.178 s --> 0.072 s
//ifstream fin("../teste_pseudocmp/27-pseudocmp.in"); // 9.046 s --> 0.077 s
ifstream fin("../teste_pseudocmp/28-pseudocmp.in"); // 9.077 s --> 0.074 s
//ifstream fin("../teste_pseudocmp/29-pseudocmp.in"); // 9.051 s --> 0.075 s
ofstream fout("pseudocmp.out");
int T;
int N;
int smaxcif=6*9; // nr <= 1.000.000 ... 999 999 --> suma cifrelor = 9*6
int smaxcif2=0; // suma maxima a cifrelor pe exemplul concret ... !!!
int fr[55];
void afisa()
{
cout<<"a[]: ";
for(int i=1; i<=N; i++)
{
cout<<setw(2)<<a[i]<<" ";
}
cout<<endl;
}
CAPITOLUL 2. OJI 2022 2.2. PSEUDOCMP 46
void afiss()
{
cout<<"s[]: ";
for(int i=1; i<=N; i++)
cout<<setw(2)<<sc[i]<<" ";
cout<<endl;
}
void afisfr()
{
cout<<"fr[]: ";
for(int i=1; i<=smaxcif2+1; i++)
cout<<setw(2)<<fr[i]<<" ";
cout<<endl;
}
int sumacifre(int nr) // sc[i] <= 100 000 * 6*9 = 5 400 000
{
int sc=0;
while(nr>0) { sc=sc+nr%10; nr=nr/10; }
return sc;
}
void cerinta1()
{
bool existapereche=false;
for(int i=1; i <= N-1; i++) // a[i] < a[i+1]
{
if(sc[i]>sc[i+1])
{
existapereche=true;
ips=i;
break;
}
}
if(existapereche==false)
{
//cout<<"NU exista --> -1";
fout<<"-1";
return;
}
else
{
fout<<a[ips]<<" "<<a[ips+1];
return;
}
return;
}
void cerinta2()
{
for(int j=1; j <= N; j++)
{
int aj=a[j];
int scj=sc[j];
int frscj=fr[scj];
fr[scj]++;
sp=0;
for(int k=sc[j]+1; k<=smaxcif2; k++)//a[..] mici <--> sc[..] mari !!!
{
sp=sp+fr[k];
}
st=st+sp;
}
nrps=st;
//cout<<"nrps = "<<nrps<<endl;
fout<<nrps<<endl;
return;
}
CAPITOLUL 2. OJI 2022 2.2. PSEUDOCMP 47
int main()
{
t1 = clock();
fin>>T;
fin>>N;
//cout<<"T = "<<T<<" N = "<<N<<endl; // verificare citire fisier ... !!!
//afisa();
t2 = clock();
sort(a,a+N+1);
t3 = clock();
//afisa();
if(T==1)
{
cerinta1();
}
if(T==2)
{
cerinta2();
}
t4 = clock();
fin.close();
fout.close();
return 0;
}
Numerele fiind distincte, trebuie să ştim numai dacă un numar i apare sau nu apare ı̂n şir.
Tipul bool permite ı̂nregistrarea numai a două valori: false şi true. Putem să declarăm vectorul
a[ ] de tip bool şi astfel vom ocupa ı̂n spaţiul de memorie numai câte 1 octet (= 8 biţi), pentru
fiecare element a[i] ı̂n loc să declarăm vectorul a[ ] de tip int şi să ocupăm ı̂n spaţiul de memorie
câte 4 octeti (= 4*8 = 32 de biţi) pentru fiecare element a[i].
CAPITOLUL 2. OJI 2022 2.2. PSEUDOCMP 48
Dacă ”ne ambiţionăm” putem să ocupăm ı̂n spaţiul de memorie câte 1 singur bit pentru
fiecare element a[i] (dacă folosim tipul bitset).
Din păcate, atunci când micşorăm spatiul de memorie, ”plătim” cu mărirea timpului de
execuţie!
Nu este nicio supărare pentru că se ı̂ntâmplă şi invers: când micşorăm timpul de execuţie
plătim cu mărirea spatiului de memorie!
Micşorarea spaţiului de memorie cu tipul bool este, ı̂n cazul acestei probleme, o iluzie
pentru că:
100 000 de numere * 4 octeţi = 400 000 de octeti
valoarea maximă a elementelor a[i] este 1 000 000 şi pentru fiecare valoare avem nevoie de
câte 1 octet, deci avem nevoie de 1 000 000 de octeţi.
Cu tipul bitset se face economie de memorie
valoarea maximă a elementelor a[i] este 1 000 000 şi pentru fiecare valoare avem nevoie de
câte 1 bit, deci avem nevoie de 1 000 000 de biţi adică de 125 000 de octeţi (1 octet = 8 biţi)
şi ... este mai puţin decât 400 000 de octeţi de la tipul int
dar ... timpul de execuţie este cam la fel!
//ifstream fin("pseudocmp1.in");
//ifstream fin("pseudocmp2.in");
//ifstream fin("pseudocmp3.in");
// cazul1
//ifstream fin("../teste_pseudocmp/10-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/11-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/12-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/13-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/14-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/15-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/16-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/17-pseudocmp.in");
// cazul2
//ifstream fin("../teste_pseudocmp/18-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/19-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/20-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/21-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/22-pseudocmp.in");
//ifstream fin("../teste_pseudocmp/23-pseudocmp.in"); // 4.073 s--> 0.065 s
//ifstream fin("../teste_pseudocmp/24-pseudocmp.in"); // 8.731
//ifstream fin("../teste_pseudocmp/25-pseudocmp.in"); // 11.090
//ifstream fin("../teste_pseudocmp/26-pseudocmp.in"); // 8.178 s
//ifstream fin("../teste_pseudocmp/27-pseudocmp.in"); // 9.046 s
//ifstream fin("../teste_pseudocmp/28-pseudocmp.in"); // 9.077 s --> 0.071 s
ifstream fin("../teste_pseudocmp/29-pseudocmp.in"); // 9.051 s --> 0.074 s
ofstream fout("pseudocmp.out");
int T;
int N;
int i1=0; // a[i] dupa "sortare" prin pozitionarea lui a[i] pe locul lui
int i2=0; // a[i+1] dupa "sortare" ...
int fr[55];
int sumacifre(int nr) // sc[i] <= 100 000 * 6*9 = 5 400 000
{
int sc=0;
while(nr>0) { sc=sc+nr%10; nr=nr/10; }
return sc;
}
void cerinta1()
{
bool existapereche=false;
i1=1;
while(i1 < aimax)
{
while((i1<aimax) && (abit[i1]==0)) { i1++; }
i2=i1+1;
while((i2<aimax) && (abit[i2]==0)) { i2++; }
if(sc[i1]>sc[i2])
{
existapereche=true;
break;
}
i1=i2;
}
CAPITOLUL 2. OJI 2022 2.2. PSEUDOCMP 50
if(existapereche==false)
{
//cout<<"NU exista --> -1";
fout<<"-1";
return;
}
else
{
//cout<<i1<<" "<<i2; cout<<" : "<<sc[i1]<<" >? "<<sc[i2]<<endl;
fout<<i1<<" "<<i2;
return;
}
return;
}
void cerinta2()
{
for(int j=1; j <= aimax; j++)
{
int aj=abit[j];
if(aj==0) continue;
int scj=sc[j];
int frscj=fr[scj];
fr[scj]++;
sp=0;
for(int k=sc[j]+1; k<=smaxcif2; k++)//a[..] mici <--> sc[..] mari !!!
{
sp=sp+fr[k];
}
st=st+sp;
}
nrps=st;
//cout<<"nrps = "<<nrps<<endl;
fout<<nrps<<endl;
return;
}
int main()
{
t1 = clock();
fin>>T;
fin>>N;
//cout<<"T = "<<T<<" N = "<<N<<endl; // verificare citire fisier ... !!!
t2 = clock();
//sort(a,a+N+1); // nu mai este nevoie de sortare
t3 = clock();
//afisabit();
sc[i]=sumacifre(i);
if(sc[i]>smaxcif2) smaxcif2=sc[i];
}
//afissc();
CAPITOLUL 2. OJI 2022 2.2. PSEUDOCMP 51
if(T==1) { cerinta1(); }
if(T==2) { cerinta2(); }
t4 = clock();
fin.close();
fout.close();
return 0;
}
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../teste_pseudocmp/15-pseudocmp.in", // input
(char*)"../teste_pseudocmp/15-pseudocmp.ok", // rezultat corect
(char*)"pseudocmp.out", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
compareRemainingLines();
}
Capitolul 3
3.1 campionat
Problema 1 - campionat 100 de puncte
Ne aflăm la un anumit moment al desfăşurării campionatului naţional de fotbal. O parte dintre
meciuri s-au jucat, altele urmează să fie disputate. Se cunoaşte numărul de puncte acumulate deja
de fiecare echipă ı̂naintea desfăşurării meciurilor restante.
Se cunoaşte, de asemenea, că un meci se poate termina egal, caz ı̂n care fiecare dintre echipe
primeşte câte un punct, sau cu victoria uneia dintre echipe, iar ı̂n acest caz acea echipă primeşte
trei puncte, iar cealaltă zero puncte.
Cerinţe
1. Care echipe ar fi pe locul I dacă toate meciurile restante s-ar termina la egalitate? O echipa
este pe locul I dacă are număr maxim de puncte.
2. Care echipe depind strict de propriile rezultate pentru a deveni campioane? O echipă devine
campioană (câştigă campionatul) dacă termină cu număr de puncte strict mai mare decât
oricare dintre celelalte echipe. Spunem că o echipă depinde strict de propriile rezultate
pentru a deveni campioană dacă ea devine campioană câştigând toate meciurile pe care
trebuie să le mai joace, indiferent de rezultatele celorlalte meciuri.
Date de intrare
Date de ieşire
Dacă T 1, linia va conţine etichetele echipelor care termină pe locul I, ı̂n cazul ı̂n care
toate meciurile restante se termină la egalitate.
Dacă T 2, linia va conţine etichetele echipelor care depind strict de propriile rezultate
pentru a deveni campioane. Dacă nicio echipă nu poate deveni campioană depinzând doar
de rezultatele sale, ı̂n fişierul de ieşire se va scrie doar numărul 0.
Atat pentru T 1, cât şi pentru T 2 etichetele echipelor vor fi scrise ı̂n ordine crescătoare,
separate prin câte un spaţiu.
52
CAPITOLUL 3. OJI 2021 - OSEPI 3.1. CAMPIONAT 53
Regulile de desfăşurare a campionatului sunt mai ciudate, nu trebuie să vă puneţi problema
dacă este posibil ca echipele să aibă şirul dat al punctajelor ı̂n urma meciurilor disputate deja
(considerăm că până la momentul de faţă federaţia a acordat diverse bonusuri şi depunctări).
Dacă ı̂ntre meciurile rămase de jucat este vreunul care apare de mai multe ori (fie sub forma
i, j fie sub forma j, i), el se va disputa o singură dată.
Programarea meciurilor s-a făcut ı̂n mod indisciplinat, deci este posibil ca unele echipe să
mai aibă de jucat mai multe meciuri decât altele, iar unele chiar să nu mai aibă de jucat
niciun meci.
Pentru teste valorând 22 de puncte T 1.
Pentru alte teste valorând 9 puncte T 2 şi fiecare echipă are de disputat exact 2 meciuri
cu alte echipe.
Pentru alte teste valorând 8 puncte T 2 şi fiecare echipă are de disputat câte un meci cu
fiecare altă echipă.
Pentru alte teste valorând 10 puncte T 2 şi există o singură echipă care joacă câte un meci
cu fiecare altă echipă, celelalte echipe neavând alte meciuri restante de jucat.
Exemple:
cu scori vom nota scorul iniţial al echipei i, pe care ı̂l vom citi din input.
cu meciurii vom nota numărul de meciuri restante pe care le mai are de jucat echipa i.
CAPITOLUL 3. OJI 2021 - OSEPI 3.2. EXCLUSIV 54
Deoarece meciurile restante pot apărea ı̂n mod repetat ı̂n fişierul de intrare, vom construi
un tablou A cu N linii şi N coloane cu elemente din mulţimea x0, 1x astfel ı̂ncat Aij
Aj i 1 dacă echipele i şi j mai au de jucat un meci restant, respectiv 0 ı̂n caz contrar.
Pentru a determina numărul de meciuri restante pe care trebuie să le mai joace echipa i este
suficient să adunăm valorile de pe linia i a tabloului A:
Cerinţa 1.
Pentru cerinţa 1 este suficient să determinăm punctajul final pe care fiecare echipă ı̂l va obţine
atunci când toate jocurile se termină la egalitate.
Acest scor este egal cu suma dintre punctajul iniţial al echipei şi numărul de jocuri restante pe
care echipa respectivă le mai are de jucat. Aflăm maximul dintre aceste punctaje finale scori
meciurii, ¾i " r1, 2, ..., N x, iar pe locul I se vor situa toate echipele care au punctajul final egal
cu punctajul final maxim.
Cerinţa 2.
O echipă i poate deveni campioană strict pe baza propriilor rezultate dacă după ce va câştiga
toate meciurile pe care le mai are de jucat, indiferent de rezultatele celorlalte meciuri, va avea un
punctaj final strict mai mare decât al tuturor celorlalte echipe.
Vom parcurge toate echipele succesiv şi vom verifica pentru fiecare dacă poate ı̂ndeplini acest
criteriu.
Să analizăm dacă echipa i poate deveni campioană strict pe baza propriilor rezultate. Punctajul
final al echipei, dacă va câştiga toate meciurile, va fi egal cu scori 3 meciurii. Să notăm
acest punctaj cu scorM axi.
Vom determina pentru fiecare echipă j, (j j i) care ar fi punctajul maxim pe care aceasta l-ar
putea obţine (considerăm că j va câştiga toate meciurile restante ı̂n care este implicată, exceptând
meciul pe care eventual l-ar juca cu echipa i). Astfel scorul maxim pe care il poate obţine echipa
j este scorM axj 3 Aij .
Dacă scorM axi este strict mai mare decât punctajul maxim al oricărei alte echipe j, atunci
ipoate deveni campioană.
Obs: https://ebooks.infobits.ro/culegere_OJI_2021.pdf
3.2 exclusiv
Problema 2 - exclusiv 100 de puncte
Se consideră doi vectori care conţin numere naturale: s cu M elemente şi v cu N elemente.
Numim secvenţă i-exclusivă o secvenţă a vectorului s care nu conţine niciuna dintre valorile v 1,
v 2, ..., v i.
Cerinţe
Scrieţi un program care să determine, pentru orice 1 & i & N , lungimea maximă a unei secvenţe
i-exclusive.
Date de intrare
Fişierul de intrare exclusiv.in conţine pe prima linie numerele naturale M şi N . Pe linia a
doua se află M numere naturale reprezentând elementele vectorului s, iar pe linia a treia N numere
naturale reprezentând elementele vectorului v. Valorile scrise pe aceeaşi linie sunt separate prin
câte un spaţiu.
Date de ieşire
CAPITOLUL 3. OJI 2021 - OSEPI 3.2. EXCLUSIV 55
Fişierul de ieşire exclusiv.out va conţine N linii. Pe linia i (1 & i & N ) va fi scris un număr
natural care reprezintă lungimea maximă a unei secvenţe i-exclusive.
Restricţii şi precizări
1&N & 2 000
3 & M & 10
5
Vectorii s şi v conţin numere naturale &2 9
10 , memorate ı̂ncepând cu poziţia 1
Valorile din fiecare vector nu sunt obligatoriu distincte două câte două.
O subsecvenţă nevidă ı̂n s este formată din elemente situate pe poziţii consecutive
(si, si 1, ..., sj ), i & j. O subsecvenţă i-exclusivă poate fi şi vidă, lungimea ei fiind 0.
Pentru teste valorând 10 puncte N 1.
Pentru alte teste valorând 30 de puncte 1 $ N & 50 şi M & 1 000.
Pentru alte teste valorând 40 de puncte 50 $ N & 2 000 şi 1 000 $ M & 2 000.
Pentru alte valorand 20 de puncte N 2 000 şi 10 $ M & 10 .
4 5
Exemple:
exclusiv.in exclusiv.out
20 6 12
11 5 11 7 2 10 11 9 2 77 88 88 88 2 7 2 2 77 2 11 12
11 5 7 9 5 2 7
6
6
4
Explicaţii:
Cea mai lungă secvenţă 1-exclusivă (care nu conţine valoarea 11)
este 9 2 77 88 88 88 2 7 2 2 77 2 şi are lungimea 12.
Cea mai lungă secvenţă 2-exclusivă (care nu conţine valorile 11 şi 5)
este 9 2 77 88 88 88 2 7 2 2 77 2 şi are lungimea 12.
Cea mai lungă secvenţă 3-exclusivă (care nu conţine valorile 11; 5 şi 7)
este 9 2 77 88 88 88 2 şi are lungimea 7.
Cea mai lungă secvenţă 4-exclusivă (care nu conţine valorile 11; 5; 7 şi 9)
este 2 77 88 88 88 2 şi are lungimea 6.
Cea mai lungă secvenţă 5-exclusivă (care nu conţine valorile 11; 5; 7; 9 şi 5)
este 2 77 88 88 88 2 şi are lungimea 6.
Cea mai lungă secvenţă 6-exclusivă (care nu conţine valorile 11; 5; 7; 9; 5 şi 2)
este 77 88 88 88 şi are lungimea 4.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 16 MB din care pentru stivă 8 MB
Dimensiune maximă a sursei: 10 KB
După ce se citesc datele de intrare se ordonează perechile v i, i crescător ı̂n funcţie de
valoare, iar ı̂n caz de egalitate crescător după poziţie.
Pentru fiecare element sj se caută, utilizând o căutare binară, cea mai mică poziţie i astfel
incat sj v i şi se ı̂nlocuieşte sj cu i. În cazul in care sj nu apare ı̂n v vom ı̂nlocui
sj cu valoarea N 1. Astfel am obţinut un vector echivalent cu cel citit din punct de
vedere al răspunsului, dar care are valori din mulţimea r1, 2, ..., N, N 1x.
În continuare, vom realiza următoarele construcţii pentru a actualiza cât mai rapid actualizarea
de la o ı̂ntrebare la alta.
Vom construi un vector urm definit prin urmj = următoarea poziţie din s unde apare
sj , respectiv urmj M 1, dacă sj nu mai apare ı̂n dreapta poziţiei j. Cu ajutorul
acestui vector urm vom parcurge, pentru fiecare valoare v i, doar poziţiile din s unde apare
valoarea i. Astfel parcurgerea tuturor valorilor din v ı̂n s se poate trecând o singură dată
peste fiecare element din s.
Vom utiliza şi vectorii stanga şi dreapta, cu semnificaţia, stangaj = ı̂nceputul intervalului
maximal din care face parte elementul de pe poziţia j, respectiv dreaptaj = sfârşitul
intervalului maximal din care face parte elementul de pe poziţia j. Aceşti vectori ne vor
ajuta să identificăm secvenţele maximale din s care nu conţin valori interzise la acea etapă.
Vectorii vor fi iniţializaţi cu stangaj dreaptaj 0, ¾j " r1, 2, ..., M x.
Obs: https://ebooks.infobits.ro/culegere_OJI_2021.pdf
OJI 2020
4.1 foto
Problema 1 - foto 100 de puncte
O fotografie alb-negru a surprins imaginea fulgerelor pe cerul ı̂ntunecat ı̂n timpul unei furtuni
electrice. Mărită, fotografia arată ca un caroiaj format din mici pătrate identice, albe sau negre,
dispuse alăturat pe N rânduri şi M coloane, câte M pe fiecare rând.
Pătratele albe formează fulgerele din fotografie, iar pătratele negre reprezintă cerul.
În fotografie, nu există două pătrate albe dispuse alăturat pe acelaşi rând. Un fulger este
format din pătrate albe situate pe rânduri consecutive care respectă următoarele condiţii:
a) pătratele albe situate pe două rânduri consecutive au un vârf comun sau o latură comună;
b) un fulger poate avea un singur pătrat alb pe un rând.
În fotografie, fulgerele sunt distincte, ele neavând pătrate albe cu laturi sau vârfuri comune.
Înălţimea unui fulger este dată de numărul de pătrate albe ale acelui fulger.
Pentru a putea fi analizată de către programatori,
fotografia este codificată cu ajutorul unui tablou bidi-
mensional cu N linii si M coloane, ale cărui elemente
sunt 0 şi 1. Valoarea 0 este codificarea pătratului negru,
iar valoarea 1 este codificarea pătratului alb.
Având codificarea, programatorii trebuie să găsească
numărul maxim P de pătrate negre dispuse alăturat pe
acelaşi rând, numărul de fulgere F precum şi ı̂nălţimea
maximă H a unui fulger din fotografie. De exemplu, fotografia alăturată este codificată de tabloul
T alăturat fotografiei .
Cerinţe
Scrieţi un program care citeşte numerele N şi M , cele N M elemente ale tabloului T care
codifică fotografia, şi rezolvă următoarele cerinţe:
1) afişează numărul maxim P de pătrate negre dispuse alăturat pe un rând ı̂n fotografie;
2) afişează numărul F de fulgere şi ı̂nălţimea maximă H a unui fulger din fotografie.
Date de intrare
Fişierul de intrare foto.in conţine pe prima linie un număr natural C reprezentând cerinţa
care trebuie rezolvată (1 sau 2).
Pe a doua linie se află cele două numere naturale N şi M , separate printr-un spaţiu, cu
semnificaţia din enunţ.
Pe fiecare dintre următoarele N linii se află câte M valori 0 sau 1, separate prin câte un spaţiu,
reprezentând elementele tabloului care codifică fotografia, ı̂n ordinea parcurgerii lor pe rânduri,
de sus ı̂n jos, şi de la stânga la dreapta ı̂n cadrul unui rând.
Date de ieşire
57
CAPITOLUL 4. OJI 2020 4.1. FOTO 58
Exemple:
O soluţie posibilă, la nivelul programei clasei a VII-a, se poate poate obţine astfel:
Cerinţa 1.
Iniţializam variabila P 0
Se parcurge fiecare linie a tabloului (matrice).
La ı̂ntâlnirea primei valori de 0, ı̂ncepem să contorizăm 0-rile succesive din linia curentă (adică
determinăm lungimea maximă a unei secvenţe de valori 0 succesive ı̂n linie). Contorizarea se
ı̂ncheie la ı̂ntâlnirea primei valori 1 sau la ı̂ncheierea parcurgerii liniei.
Actualizăm valoarea lui P cu maximul dintre P şi valoarea contorului.
Apoi reiniţializăm contorul cu 0 şi căutăm următorul 0 ı̂n linie. Dacă a fost parcursă toată
linia, se trece la linia următoare.
Cerinţa 2.
Folosim variabila F pentru a număra fulgerele din fotografie. Iniţial F 0.
Folosim variabila H pentru a memora ı̂nălţimea maximă a unui fulger. Iniţial H 0.
I. Solutie complexitate O N N M
Pentru a evita ieşirea din matrice, e recomandat să bordaţi cu 0 matricea, adică să adaugaţi
linia 0, linia N 1, coloana 0 şi coloana M 1, toate având doar valori egale cu 0.
CAPITOLUL 4. OJI 2020 4.1. FOTO 59
Parcurgem matricea, de la linia 1 către linia N , iar fiecare linie este parcursă de la prima
coloană către ultima.
Prima valoare 1 ı̂ntâlnită, reprezintă primul pătrat alb dintr-un fulger.
Dacă T lincol 1 atunci vom proceda astfel:
a) Numărăm noul fulger: F=F+1; Iniţializam contorul h care va numără patratele albe ce
formează un fulger: h=0. El va fi ı̂nălţimea fulgerului. Fie I=lin şi J=col
b) Cât timp T[I][J]=1 procedăm astfel:
b1) Modificăm ı̂n matrice T[I][J]=0. Contorizam pătratul alb (h=h+1).
b2) Căutăm ı̂n linia I+1 următorul pătrat alb al fulgerului, ı̂n coloanele J-1 sau J+1.
Dacă T[I+1][J-1]=1, atunci pătratul alb este ı̂n coloana J-1 şi vom actualiza I=I+1
şi J=J-1. Mergi la b1)
Altfel dacă T[I+1][J-1]=1 atunci pătratul alb este ı̂n coloana J+1 şi vom actualiza
I=I+1şi J=J+1. Mergi la b1)
Altfel dacă T[I+1][J]=1atunci pătratul alb este ı̂n coloana J+1 şi vom actualiza
I=I+1. Mergi la b1)
Altfel, (adică dacă T[I+1][J-1]=0, T[I+1][J]=0 şi T[I+1][J+1]=0) atunci au fost
găsite toate pătratele albe care formează fulgerul. Actualizăm H=max(H,h) apoi
se va căuta următoarea valoare de 1 ı̂n matrice, revenind la pasul a) pentru noile
valori lin si col cu proprietatea că T[lin][col]=1. Mergi la pas a)
OBS: cel mult una dintre valorile T[I+1][J-1], T[I+1][J] şi T[I+1][J+1] este egală
cu 1
La ı̂ncheierea parcurgerii matricei T , aceasta va avea toate valorile egale cu 0.
Se vor afişa valorile finale ale variabilelor F şi H.
II. Solutie complexitate O N M
Se parcurge matricea.
Pentru fiecare element T[I][J]=1 procedăm astfel:
a verificam dacă vreunul cei trei vecini T[I-1][J-1], T[I-1][J], T[I-1][J-1], situati in linia I-1 este
nenul. Doar unul poate fi nenul.
a dacă toţi trei sunt nuli, atunci T[I][J] este primul patrat alb dintr-un fulger nou si numărăm
acest fulger (F++);
a dacă unul dintre ei este nenul, fie T[LIN][COL] acest vecin nenul. Atunci T[I][J]
şiT[LIN][COL] fac parte din acelaşi fulger şi vom memora ı̂n T[i][j] lungimea actuală a
fulgerului. : T[I][J]=T[LIN][COL]+1;
a se actualizează variabila ce memorează lungimea maxima a fulgerelor H=max(H, T[I][J]);
La ı̂ncheierea parcurgerii matricei T , se vor afişa valorile finale ale variabilelor F şi H.
15 if(C==1)
16 {
17 int x,P=0,i,j,p=0;
18 for(i=1;i<=N;i++)
19 { p=0;
20 for(j=1;j<=M;j++)
21 { fscanf(f,"%d",&x);
22 if(x==0)p++;
23 else
24 {if(P<p)P=p;
25 p=0;}
26 }
27 if(P<p)P=p;
28 }
29 fprintf(g,"%d\n",P);
30 }
31 else
32 {
33 int H=0,F=0,i,j,h,r,c;
34
35 for(r=1;r<=N;r++)
36 for(c=1;c<=M;c++)
37 fscanf(f,"%d",&a[r][c]);
38
39 for(r=1; r<=N; r++)
40 for(c=1; c<=M; c++)
41 if(a[r][c]==1)
42 { F++;
43 i=r;
44 j=c;
45 h=0;
46
47 while(a[i][j]==1)
48 { h++;
49 a[i][j]=0;
50 if(a[i+1][j]==1)i++;
51 else
52 if(a[i+1][j-1]==1){i++;j--;}
53 else
54 if(a[i+1][j+1]==1){i++; j++;}
55 }
56
57 if(H<h) H=h;
58 }
59
60 fprintf(g,"%d %d\n",F,H);
61 }
62
63 return 0;
64 }
23 else
24 {if(P<p)P=p;
25 p=0;}
26 }
27
28 if(P<p)P=p;
29 }
30
31 fprintf(g,"%d\n",P);
32 }
33 else
34 {
35 int H=0,F=0,i,j,hant;
36
37 for(i=1;i<=N;i++)
38 for(j=1;j<=M;j++)
39 { fscanf(f,"%d",&T[i][j]);
40 if(T[i][j]==1)
41 { hant=T[i-1][j-1]+
42 T[i-1][j]+
43 T[i-1][j+1];///lg fulger pana in aceasta pozitie
44 /// doar una dintre valorile
45 /// T[i-1][j-1],T[i-1][j],T[i-1][j+1]este nenula
46 if (hant==0) F++; ///primul patrat alb din fulger
47 T[i][j]=1+hant;
48 if(H<T[i][j])H=T[i][j];
49 }
50 }
51
52 fprintf(g,"%d %d\n",F,H);
53 }
54
55 return 0;
56 }
ifstream f("foto.in");
ofstream g("foto.out");
int T[102][102];
int main()
{
int C,N,M;
f>>C>>N>>M;
if(C==1)
{
int x,P=0,i,j,p=0;
for(i=1;i<=N;i++)
{ p=0;
for(j=1;j<=M;j++)
{ f>>x;
if(x==0)p++;
else
{P=max(p,P); p=0;}
}
P=max(P,p);
}
g<<P<<endl;
}
else
{
int H=0,F=0,i,j,h,r,c;
for(r=1;r<=N;r++)
for(c=1;c<=M;c++)
CAPITOLUL 4. OJI 2020 4.1. FOTO 62
f>>T[r][c];
H=max(h,H);
}
g<<F<<" "<<H<<endl;
}
return 0;
}
ifstream f("foto.in");
ofstream g("foto.out");
int T[102][102];
int main()
{
int C,N,M;
f>>C>>N>>M;
if(C==1)
{
int x,P=0,i,j,p=0;
for(i=1;i<=N;i++)
{ p=0;
for(j=1;j<=M;j++)
{ f>>x;
if(x==0)p++;
else
{P=max(p,P); p=0;}
}
P=max(P,p);
}
g<<P<<endl;
}
else
{
int H=0,F=0,i,j,h,r,c;
for(r=1;r<=N;r++)
for(c=1;c<=M;c++)
f>>T[r][c];
j=c;
h=0;
while(T[i][j]==1)
{ h++;
T[i][j]=0;
if(T[i+1][j]==1)i++;
else
if(T[i+1][j-1]==1){i++;j--;}
else
if(T[i+1][j+1]==1){i++; j++;}
}
H=max(h,H);
}
g<<F<<" "<<H<<endl;
}
return 0;
}
int a[103][103];
int main()
{
int i,j,nr=0,nrmax=0,c, hmax=0,nrfulgere=0,n,m;
ifstream f("foto.in");
ofstream g("foto.out");
f>>c>>n>>m;
for(i=1; i<=n; i++)
{
nr=0;
for(j=1; j<=m; j++)
{
f>>a[i][j];
if(a[i][j]==0)
{
nr++;
if(nr>nrmax)
nrmax=nr;
}
else
{
nr=0;
if(a[i-1][j]!=0)
a[i][j]=a[i-1][j]+1;
else if(a[i-1][j-1]!=0)
a[i][j]=a[i-1][j-1]+1;
else if(a[i-1][j+1]!=0)
a[i][j]=a[i-1][j+1]+1;
if(hmax<a[i][j])
hmax=a[i][j];
if (a[i][j]==1)nrfulgere++;
}
}
}
if(c==1)
g<<nrmax;
else
g<<nrfulgere<<" "<<hmax;
return 0;
}
#include <iostream>
#include <fstream>
ifstream fin("foto.in");
ofstream fout("foto.out");
int a[105][105],i,j,n,m,c,k,mx,kmax,fmax,nr,kf;
int dl[]={-1,-1,-1,0,1,1,1,0};
int dc[]={-1,0,1,1,1,0,-1,-1};
int main()
{
fin>>c;
fin>>n>>m;
mx=0;
kmax=0;
for(i=1; i<=n; i++)
{
k=0;
for(j=1; j<=m; j++)
{
fin>>a[i][j];
if(a[i][j]==0)k++;
else
{if(k>kmax)
kmax=k;
k=0;}
}
if(k>kmax)
kmax=k;
}
if(c==1)
fout<<kmax;
else
{
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
if(a[i][j]==1)
{
nr=0;kf++;
lee(a,n,m,i,j,nr);
if(nr>fmax)
fmax=nr;
}
}
fout<<kf<<’ ’<<fmax;
}
return 0;
}
ifstream f("foto.in");
ofstream g("foto.out");
int a[102][102],h, N, M;
int main()
{
int C;//,N,M;
f>>C>>N>>M;
if(C==1)
{
int x,P=0,i,j,p=0;
for(i=1; i<=N; i++)
{
p=0;
for(j=1; j<=M; j++)
{
f>>x;
if(x==0)p++;
else
{
P=max(p,P);
p=0;
}
}
P=max(P,p);
}
g<<P<<endl;
}
else
{
int H=0,F=0,i,j,r,c;
for(i=1; i<=N; i++)
for(j=1; j<=M; j++)
f>>a[i][j];
ifstream fin("foto.in");
ofstream fout("foto.out");
int a[105][105],n,m,c,i,j;
{ int k=i;
for(;i<n;i++)
{ a[i][j]=2;
if(a[i+1][j]==1) continue;
if(a[i+1][j-1]==1) j--;
else if(a[i+1][j+1]==1) j++;
else break;
}
if(i==n)a[i][j]=2;
return i-k+1;
}
void c1()
{int zmax=0, z=0, i, j;
for(i=1;i<=n;i++)
{ z=0;
for(j=1;j<=m;j++) if(a[i][j]==0)z++;
else {zmax=max(zmax,z);z=0;}
zmax=max(zmax,z);
}
fout<<zmax<<’\n’;
}
void c2()
{ int i,j, h, hmax=0, f=0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(a[i][j]==1){f++; h=fulger(i,j);
hmax=max(hmax,h);
}
fout<<f<<’ ’<<hmax<<’\n’;
}
int main()
{fin>>c>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++) fin>>a[i][j];
if(c==1) c1();
else c2();
fin.close();
fout.close();
return 0;
}
ifstream f("foto.in");
ofstream g("foto.out");
int i,j,n,m,a[101][101],k,maxim,C,fulgere;
int main()
{
f>>C;
if(C==1)
{
f>>n>>m;
for(i=1; i<=n; i++)
{
k=0;
for(j=1; j<=m; j++)
{
f>>a[i][j];
if(a[i][j]==0)
k++;
else
{
if(k>maxim)
CAPITOLUL 4. OJI 2020 4.1. FOTO 67
maxim=k;
k=0;
}
}
if(k>maxim) maxim=k;
}
g<<maxim;
}
else
{
f>>n>>m;
for(i=1; i<=n; i++)
{
for(j=1; j<=m; j++)
{
f>>a[i][j];
if(a[i][j])
{
if(a[i-1][j-1]==0 and a[i-1][j]==0 and a[i-1][j+1]==0)
fulgere++;
if(a[i-1][j-1])
a[i][j]=a[i-1][j-1]+1;
if(a[i-1][j])
a[i][j]=a[i-1][j]+1;
if(a[i-1][j+1])
a[i][j]=a[i-1][j+1]+1;
if(a[i][j]>maxim)
maxim=a[i][j];
}
}
}
g<<fulgere<<" "<<maxim;
}
return 0;
}
#define Ni 105
#define Mi 105
int main()
{
ifstream f("foto.in");
ofstream g("foto.out");
short c;
f>>c;
f>>M;
if(c==1)
{
short maxi=0,kez;
for(i=1; i<=N; i++)
{
kez=0;
for(j=1; j<=M; j++)
CAPITOLUL 4. OJI 2020 4.1. FOTO 68
{
if(T[i][j]==1 && j>1)
{
if (maxi<kez)
{
maxi=kez;
}
kez=0;
}
else if(T[i][j]==0) kez++;
}
if(T[i][M]==0)
{
if (maxi<kez)
{
maxi=kez;
}
kez=0;
}
}
g<<maxi;
}
else
{
int ta=0,maxk=-1,k=0,l=0;
if(maxk<=T[i][j]) maxk=T[i][j];
}
}
g<<ta<<" "<<maxk;
}
return 0;
}
ifstream fin("foto.in");
CAPITOLUL 4. OJI 2020 4.1. FOTO 69
ofstream fout("foto.out");
if(l>lmax)
lmax=l;
return lmax;
}
void citire()
{
int i,j;
fin>>ct>>n>>m;
for(i=1; i<=n; i++)
for(j=1; j<=m; j++)
fin>>a[i][j];
}
int main()
{
citire();
int i, maxi=0,x,j,xmin,xmax,fulgere=0;
if(ct==1)
{
for(i=1; i<=n; i++)
{
x=platou(i);
if(x>maxi)
maxi=x;
}
fout<<maxi<<" ";
fout<<’\n’;
return 0;
}
umple(i,j,xmin,xmax);
if(xmax-xmin>maxi)
maxi=xmax-xmin;
}
fout<<fulgere<<" "<<maxi+1<<’\n’;
return 0;
}
4.2 wind
Problema 2 - wind 100 de puncte
Domnul Vânt a pus pe marginea unei şosele N centrale eoliene, dintre care unele produc energie
electrică, iar altele, deocamdată, doar consumă energie. El a etichetat centralele cu numerele
naturale distincte de la 1 la N , ı̂n ordinea poziţionării lor pe şosea. Fiecare centrală eoliană are
la bază un ecran pe care este afişat un număr ı̂ntreg, reprezentând cantitatea de energie pe care
o produce (dacă numărul este pozitiv) sau pe care o consumă (dacă numărul este negativ).
Pentru a construi corect k oraşe de-a lungul acestei şosele, un arhitect trebuie să aibă ı̂n vedere
că:
a fiecărui oraş ı̂i va fi atribuit câte un grup format din centrale eoliene vecine pe şosea, toate
grupurile având acelaşi număr de centrale;
a cantitatea de energie repartizată unui oraş este egală cu suma numerelor afişate pe ecranele
centralelor eoliene din grupul atribuit; uneori este posibil ca, deocamdată, suma obţinută să
fie negativă;
a fiecare dintre cele N centrale eoliene trebuie să fie atribuită unui oraş;
a factorul de dezechilibru, notat cu P k , este valoarea maximă a diferenţei dintre energiile
repartizate oricăror două oraşe diferite, dintre cele k.
Cerinţe
Scrieţi un program care citeşte numărul N , valorile afişate pe cele N ecrane ale centralelor
eoliene şi rezolvă următoarele două cerinţe:
1. afişează numărul M de moduri ı̂n care se pot grupa cele N centrale pentru construcţia
corectă de oraşe;
2. afişează numărul maxim X de oraşe ce pot fi construite corect, dintre cele care au factorul de
dezechilibru minim, precum şi eticheta E a primei centrale eoliene atribuită oraşului cu cea
mai mare cantitate de energie repartizată, dintre cele X oraşe; dacă sunt mai multe astfel
de oraşe, se ia ı̂n considerare cel care are atribuite centrale etichetate cu numere mai mari.
Date de intrare
Fişierul wind.in conţine pe prima linie un număr natural C reprezentând cerinţa care trebuie
rezolvată (1 sau 2).
A doua linie a fişierului conţine un număr natural N , cu semnificaţia din enunţ.
A treia linie din fişier conţine N numere ı̂ntregi, separate prin câte un spaţiu, reprezentând
valorile afişate pe cele N ecrane ale centralelor eoliene, ı̂n ordinea poziţionării acestora pe şosea.
Date de ieşire
a Numerele afişate pe ecranele centralelor sunt numere ı̂ntregi formate din cel mult 9 cifre;
a Se vor construi minimum 2 oraşe;
a Pentru rezolvarea cerinţei 1 se acordă 20 de puncte, pentru rezolvarea cerinţei 2 se acordă
70 de puncte (35 de puncte pentru X şi 35 de puncte pentru E).
Exemple:
Pentru a putea ı̂mpărţi cele n eoliene ı̂n mod egal ı̂n k oraşe trebuie să determinăm divizorii
numărului n.
Cerinţa 1: Se determină numărul de divizori al numărului de eoliene (n). Rezultatul va fi
numărul de divizori-1 deoarece se specifică ı̂n enunţ că se vor costrui cel puţin două oraşe, deci n
nu este un divizor valid.
Cerinţa 2: Se foloseşte un vector suma, fiecare element al acestuia memorând suma energiilor
dintre poziţia 1 (prima centrală) şi poziţia elementului respectiv (pozitia curentă).
sumai va reprezenta suma valorilor energiilor generate (pierdute) de centralele de la 1 la i.
Pentru a ı̂mpărţi centralele ı̂n mod corect trebuie să determinăm divizorii numărului n. Pentru
fiecare divizor se parcurge vectorul de sume din divizor in divizor şi se calculează diferenţa dintre
sumele de pe poziţiile respective. Se alege ı̂mpărţirea optimă.
CAPITOLUL 4. OJI 2020 4.2. WIND 72
71 minimm=dif;
72 divx=x;
73 pozmax=poz;
74 }
75 else if(dif==minimm && x<divx)
76 {
77 divx=x;
78 pozmax=poz;
79 }
80 }
81
82 n=n/divx;
83 fprintf(g,"%lli %lli\n",n,pozmax);
84 }
85
86 return 0;
87 }
ifstream f("wind.in");
ofstream g("wind.out");
smin=s[j]-s[j-x];
if (s[j]-s[j-x] >= smax)
{
smax=s[j]-s[j-x];
poz=j-x+1;
}
}
dif=smax-smin;
if(dif<minimm)
{
minimm=dif;
divx=x;
pozmax=poz;
}
else if(dif==minimm && x<divx)
{
divx=x;
pozmax=poz;
}
}
g<<n/divx<<" "<<pozmax;
}
return 0;
}
ifstream f("wind.in");
ofstream g("wind.out");
int nr_divizori()
{ if(N==1)return 1;
int k=2,d;
for(d=2;d*d<=N;d++)
{
if(N%d==0)
{ k++;
if(d*d!=N)k++;
}
}
return k;
}
int main()
{
f>>cer>>N;
if(cer==1)
{g<<nr_divizori()-1; return 0;}
///cerinta 2
int ind=1,d,k,indk,nro=N,i,j,tt=2;
long long x, dmin, sd,sdmin,sdmax,difkmin, xmin, xmax;
f>>s[1];
xmin=xmax=s[1];
for(i=2;i<=N;i++)
{
f>>x;
xmin=min(xmin,x);
if(x>=xmax){xmax=x; ind=i;}
s[i]=s[i-1]+x;
}
dmin=xmax-xmin;
s[0]=0;
for(d=2;d<=N/2;d++)
{
CAPITOLUL 4. OJI 2020 4.2. WIND 75
if(N%d==0)
{ k=N/d; sdmin=sdmax=s[d];indk=1;
for(j=d;j<=N;j=j+d)
{ sd=(s[j]-s[j-d]);
if(sd<sdmin)sdmin=sd;
if(sd>=sdmax)
{ sdmax=sd; indk=j-d+1; }
}
difkmin=sdmax-sdmin;
if(difkmin<dmin)
{ nro=k; dmin=difkmin;ind=indk; tt=d; }
else if(difkmin==dmin && nro<k)
{ nro=k; ind=indk; }
}
}
g<<nro<<" "<<ind;
return 0;
}
ifstream fin("wind.in");
ofstream fout("wind.out");
void c1()
{
int nrd=-1,d;
for(d=1;d*d<n;d++)if(n%d==0)nrd+=2;
fout<< nrd+(d*d==n);
}
void refresh(int d)
{ dif=diferenta(d,u);
if(dif<difm || dif==difm && d<dm)difm=dif,dm=d,um=u;
}
void c2()
{
dm=1;um=1;
fin>>e[1];emax=emin=e[1];
for(i=2;i<=n;i++){fin>>e[i];
if(e[i]<emin)emin=e[i];
else if(e[i]>=emax) emax=e[i],um=i;
e[i]+=e[i-1];}
difm=emax-emin;
for(d=2;d*d<n;d++)
if(n%d==0){ refresh(d);refresh(n/d);}
if(d*d==n)refresh(d);
fout<<n/dm<<’ ’<<um;
}
int main()
{ fin>>c>>n;
CAPITOLUL 4. OJI 2020 4.2. WIND 76
if(c==1)c1();
else c2();
fin.close();fout.close();
return 0;
}
OJI 2019
Cerinţe
Scrieţi un program care citeşte valorile N şi P cu semnificaţia din enunţ şi rezolvă următoarele
cerinţe:
1. afişează numărul minim de dale pe care trebuie să calce pentru a deschide poarta;
2. afişează numărul natural T , reprezentând numărul minim de picături de poţiune magică
necesare pentru deschiderea porţii.
Date de intrare
Fişierul de intrare poarta.in conţine pe prima linie un număr natural C reprezentând cerinţa
din problemă care trebuie rezolvată (1 sau 2). Pe a doua linie se află numărul natural N , iar pe
a treia linie se află numărul natural P cu semnificaţia din enunţ.
Date de ieşire
Fişierul de ieşire poarta.out va conţine o singură linie pe care va fi scris un număr natural
reprezentând răspunsul la cerinţa C.
2 & N $ 104
a P este număr natural nenul cu cel mult 1000 de cifre; pentru o parte dintre teste, valorând
ı̂n total 60 de puncte, P are cel mult 18 cifre.
a Recipientul conţine o cantitate suficientă de poţiune magică.
a Pentru rezolvarea cerinţei 1 se acordă maximum 60 de puncte, iar pentru rezolvarea cerinţei
2 se acordă maximum 30 de puncte.
77
CAPITOLUL 5. OJI 2019 5.1. POARTA - OJI 2019 78
Exemple
poarta.in poarta.out Explicaţii
1 3 Tunelul are 5 dale pe fiecare linie. Sindbad trebuie să ajungă pe dala
5 numerotată cu 9. Numărul minim de dale pe care trebuie să calce
9 pentru a ajunge pe dala 9 pentru a deschide poarta este 3.
De pe margine poate sări:
- pe dala numerotată cu 4 (consumă 0 picături de poţiune magică);
- de pe dala numerotată cu 4 pe cea numerotată cu 8 (consumă 2
picături de poţiune magică);
- de pe dala numerotată cu 8 pe cea numerotată cu 9 (consumă 1
picătură de poţiune magică).
2 3 Pentru a ajunge pe dala numerotată cu 9 are nevoie de cel puţin 3
5 picături de poţiune magică.
9
Acest pas se repeta cat timp valoarea lui P este mai mare decat N. in cazul in care
la ultimul pas, este posibil sa ajunga pe prima linie atat prin scadere cu 1 cat si
impartire la 2, vom alege sa scadem 1, astfel incat sa obtinem numarul minim de pic
magice.
Pentru rezolvarea cerintei 1: numarul minim de dale pe care calca este numarul de p
efectuati pana cand valoarea lui P devine mai mica sau egala cu N
//for(i=1;i<=nv;i++) g<<v[i];g<<"\n";
ck=n;
while(ck)
{
nk++;ck=ck/10;
}
while(!gata)
{
j=0;k++;
if(v[nv]%2==0)
{
T+=2;pas=2;
for(i=1;i<=nv;i++)
{
j=j*10+v[i];
v[i]=j/2;j=j%2;
}
}
else
{
T++;pas=1;
if(v[nv]>0) v[nv]--;
}
if(v[1]==0)
{
i=1;j=1;
while(v[i]==0)i++;nv=nv-i+1;
while(j<=nv)v[j++]=v[i++];
}
if(nv<=nk)
{
ck=0;
for(i=1;i<=nv;i++) ck=ck*10+v[i];
if(ck<=n)gata=1;
}
//for(i=1;i<=nv;i++) g<<v[i];g<<"\n";
}
if(pas==2&&ck*2==n+1){ck=n;T=T-1;}
if(cer==1) g<<k<<"\n";//ne minim de dale
else g<<T<<"\n";//nr minim de picaturi
//g<<k<<"\n"<<ck<<"\n"<<T<<"\n";
return 0;
}
ifstream in("poarta.in");
ofstream out("poarta.out");
void citire()
{
in>>c>>N;
in.get();
in.get(p,10001);
n=strlen(p)-1;
l=strlen(N)-1;
}
int main()
{
citire();
rev(p,n);
rev(N,l);
char pp[12];
unsigned long long pic=0,dal=1,pu;
while(Cmp(p,n,N)>0)
{
if(p[0]%2)
{
p[0]--;
dal++;
pic++;
}
else
{
if(n<=11)
{
strcpy(pp,p);
rev(pp,n);
pu=atoi(pp);
}
Divide(p,n);
pic+=2;
dal++;
}
//out<<p<<’ ’<<dal<<’ ’<<pic<<endl;
}
rev(N,l);
if(pu-1==atoi(N)) pic--;
if(c==1)
out<<dal<<’\n’;
else
out<<pic<<’\n’;
return 0;
}
ifstream fin("poarta.in");
ofstream fout("poarta.out");
int N, cerinta;
int P[LGMAX];
int lgp;
int T, nrmin=1, X;
int main()
{char c;
int st, dr, aux;
fin>>cerinta>>N;
while (fin>>c)
P[lgp++]=c-’0’;
for (st=0, dr=lgp-1; st<dr; st++, dr--)
{aux=P[st]; P[st]=P[dr]; P[dr]=aux;}
while (1)
{
if (compara(P, lgp, N)<=0) {X=convert(P, lgp); break;}
if (compara(P, lgp, N+1)==0) {X=N; T++; nrmin++; break;}
if (P[0]%2)
{
P[0]--; nrmin++; T++;
}
else
{
imparte2(P, lgp);
nrmin++; T+=2;
}
}
if (cerinta==1)
fout<<nrmin<<’\n’;
else
fout<<T<<’\n’;
return 0;
}
ifstream cin("poarta.in");
ofstream cout("poarta.out");
void read()
{
char cif;
cin >> pr >> n;
while(cin >> cif)
nr[++k] = cif -’0’;
int aux = n;
while(aux >0)
{
nc ++;
aux /= 10;
}
}
void drum()
{
int c[MaxC] = {0}, kc, rest = 0, i, val;
if(nr[k]%2==0)
{
potiune += 2;
if(nr[1] < 2)
{
kc = 1;
c[kc] = (nr[1]*10 + nr[2])/2;
rest = (nr[1]*10 + nr[2])%2;
i = 3;
}
else
{
i = 1;
rest = 0;
}
val = 0;
for(i=1; i<=k; i++)
val = val *10 + nr[i];
while(val > n)
{
if(val == n+1)
{
pasi ++;
potiune ++;
start = val-1;
break;
}
if(val % 2 == 0)
{
pasi ++;
potiune +=2;
val /=2;
}
else
{
pasi ++;
potiune ++;
val --;
}
if(val <= n)
start = val;
}
}
void write()
{
if(pr == 1)
cout << pasi << ’\n’;
else
cout << potiune << ’\n’;
}
int main()
{
read();
drum();
write();
return 0;
}
Exemple
CAPITOLUL 5. OJI 2019 5.2. VALUTAR - OJI 2019 84
Iniţial toţi jucătorii pornesc de la casa de schimb valutar 1 care este albă. Există N case
de schimb valutar şi M jucători. Jucătorii mută pe rând ı̂n ordinea jetoanelor. Mai ı̂ntâi mută
jucătorul 1, apoi 2, 3, ..., M . După jucătorul M va muta din nou 1 etc. La o mutare, un jucător
care nu a fost eliminat din joc:
- ”dă” cu zarul electronic; zarul va afişa un număr ı̂ntreg nr;
- avansează cu nr poziţii (adică dacă jetonul său este la casa i va ajunge la casa i nr);
- execută acţiunea asociată casei de schimb valutar ı̂n care a ajuns, ı̂n funcţie de culoarea
acesteia.
Zarul electronic funcţionează astfel: la mutarea cu numărul j este generat numărul nrj calculat
după formula nrj a nrj 1 b%N 1, unde nrj 1 este numărul generat la mutarea j 1;
a, b şi nr0 sunt trei valori cunoscute, iar % reprezintă restul ı̂mpărţirii ı̂ntregi (mod).
Cerinţe
Scrieţi un program care să rezolve următoarele cerinţe:
1. determină numărul de jucători existenţi ı̂n joc după X mutări;
2. determină jucătorul care a rămas ı̂n joc şi care are cea mai mare sumă de Euro după X
mutări.
Date de intrare
Fişierul de intrare valutar.in conţine pe prima linie cerinţa care trebuie să fie rezolvată (1 sau
2).
Pe a doua linie se află numerele naturale a b şi nr0, cu semnificaţia din enunţ.
Pe a treia linie se află numerele naturale N M L E X, reprezentând numărul de case de
schimb valutar, numărul de jucători, câţi lei şi câţi euro primeşte fiecare jucător la ı̂nceputul
jocului, respectiv numărul de mutări din joc. Pe următoarele N linii sunt descrise casele de schimb
valutar, câte o casă pe o linie, ı̂n ordinea de la 1 la N , sub forma Cod C V , cu semnificaţiile din
enunţ. Valorile scrise pe aceeaşi linie sunt separate prin câte un spaţiu.
Date de ieşire
Fişierul de ieşire valutar.out va conţine o singură linie. Dacă cerinţa este 1, linia va conţine
un număr natural reprezentând numărul de jucători existenţi ı̂n joc după X mutări. Dacă cerinţa
este 2, linia va conţine numărul jetonului jucătorului rămas ı̂n joc şi care are cea mai mare sumă
de euro după X mutări.
Restricţii şi precizări
1 & M, C, V & 100
a 1 & a, b, nr0, N, X & 10000
a 1lL, E & 106
a Toate casele de schimb valutar au suficienţi lei şi euro pentru efectuarea oricărei acţiuni.
a Se garantează că pentru datele de test la cerinţa 2 va rămâne ı̂n joc după X mutări un singur
jucător cu suma maximă de euro.
a Pentru fiecare cerinţă se acordă 50% din punctajul obţinut pe teste.
CAPITOLUL 5. OJI 2019 5.2. VALUTAR - OJI 2019 85
Exemple
Explicaţie:
Numerele care se obţin când se dă cu zarul se generează astfel: nrj 3 nrj 1 2%5 1,
unde nr0 7.
Există ı̂n joc 5 case de schimb valutar şi 3 jucători. Toţi jucătorii au iniţial 2 lei şi 3 euro şi se
află la casa de schimb valutar 1 care este albă. Se efectuează 8 mutări astfel:
Pentru a memora datele despre casele de schimb valutar vom defini o structura
denumita casa cu 3 campuri: cod, C si V (conform enuntului).
Pentru a memora datele despre un jucator vom defini o structura denumita jucator
cu urmatoarele campuri:
-sl - suma in lei pe care o are jucatorul respectiv la un moment dat
-se - suma in euro pe care o are jucatorul la un moment dat
-pas - numarul de cartonase pas detinute de jucatorul respectiv.
CAPITOLUL 5. OJI 2019 5.2. VALUTAR - OJI 2019 86
ifstream fin("valutar.in");
ofstream fout("valutar.out");
jucator J[MMAX];
casa C[NMAX];
int main()
{int i, L, E, cine=0, sum=-1, jmax;
char culoare;
fin>>cerinta>>a>>b>>nr>>n>>m>>L>>E>>X;
nr=(a*nr+b)%n+1;
J[cine].unde+=nr; if (J[cine].unde>n) J[cine].unde-=n;
culoare=C[J[cine].unde].cod;
if (culoare==’A’) { continue;}
else
if (culoare==’R’) J[cine].pas++;
else
if (culoare==’G’) //cumpar euro
{
if (J[cine].sl>=J[cine].unde*C[J[cine].unde].c)
{//cumpar euro
J[cine].se+=J[cine].unde;
J[cine].sl-=J[cine].unde*C[J[cine].unde].c;
}
CAPITOLUL 5. OJI 2019 5.2. VALUTAR - OJI 2019 87
else
if (J[cine].pas>0) J[cine].pas--;
else {J[cine].out=1; nrout++;}
}
else //vand euro
if (J[cine].se>=J[cine].unde)
{
J[cine].se-=J[cine].unde;
J[cine].sl+=J[cine].unde*C[J[cine].unde].v;
}
else
if (J[cine].pas>0) J[cine].pas--;
else {J[cine].out=1; nrout++;}
}
if (cerinta==1)
fout<<m-nrout;
else
{
for (i=1; i<=m; i++)
if (!J[i].out)
if (J[i].se>sum) {sum=J[i].se; jmax=i;}
fout<<jmax;
}
fout<<’\n’;
fout.close();
return 0;
}
ifstream in("valutar.in");
ofstream out("valutar.out");
int a,b,p,nr0,n,m,x;
long long l,e;
struct casa
{
char cod;
unsigned long long c,v;
} c[MAXN];
struct jucator
{
bool stare;
int cc,pas;
unsigned long long l,e;
} J[MAXN];
void citire()
{
in>>p;
in>>a>>b>>nr0;
in>>n>>m>>l>>e>>x;
for (int i=1; i<=n; ++i)
in>>c[i].cod>>c[i].c>>c[i].v;
for (int i=1; i<=m; ++i)
{
J[i].cc=1;
J[i].l=l;
J[i].e=e;
J[i].stare=true;
J[i].pas=0;
}
}
CAPITOLUL 5. OJI 2019 5.2. VALUTAR - OJI 2019 88
int main()
{
citire();
int i=1;
int p1=m;
for(int j=1; j<=x; ++j)
{
while(!J[i].stare)
{
++i;
if(i>m)i-=m;
}
nr0=aruncare(nr0);
J[i].cc+=nr0;
if(J[i].cc>n) J[i].cc-=n;
int cc=J[i].cc;
switch(c[cc].cod)
{
case ’R’:
J[i].pas++;
break;
case ’G’:
if(c[cc].c*cc<=J[i].l)
{
J[i].l-=c[cc].c*cc;
J[i].e+=cc;
}
else if(J[i].pas) J[i].pas--;
else
{
J[i].stare=false;
p1--;
}
break;
case ’V’:
if(cc<=J[i].e)
{
J[i].l+=c[cc].v*cc;
J[i].e-=cc;
}
else if(J[i].pas) J[i].pas--;
else
{
J[i].stare=false;
p1--;
}
}
++i;if(i>m)i-=m;
}
if(p==1) out<<p1<<’\n’;
else
{
unsigned long long k=0,maxi=0;
for (int i=1; i<n; ++i)
if(J[i].stare&&J[i].e>maxi){k=i;maxi=J[i].e;}
out<<k<<’\n’;
}
return 0;
}
ifstream cin("valutar.in");
ofstream cout("valutar.out");
struct case_schimb
{
char cul;
int c, v;
};
struct jucator
{
int sumL, sumE, pas, e_joc, poz;
};
jucator v[Max];
case_schimb c[MaxC];
int n, m, a, b, nra, X;
int pr;
void read()
{
int lei, euro;
cin >> pr;
cin >> a >> b >> nra;
cin >> n >> m >> lei >> euro >> X;
for(int i=1; i<=m; i++)
{
v[i].sumL = lei;
v[i].sumE = euro;
v[i].pas = 0;
v[i].e_joc = 1;
v[i].poz = 1;
}
for(int i=1; i<=n; i++)
{
cin >> c[i].cul >> c[i].c >> c[i].v;
}
}
void joc()
{
int nru, j, nrjucator, casa, val;
nrjucator = 1;
for(j=1; j<=X; j++)
{
nru = (a*nra+b)%n+1;
nra = nru;
while(v[nrjucator].e_joc == 0)
{
nrjucator ++;
if(nrjucator > m)
nrjucator = 1;
}
v[nrjucator].poz += nru;
v[nrjucator].poz = v[nrjucator].poz%n;
if(v[nrjucator].poz == 0)
v[nrjucator].poz = n;
casa = v[nrjucator].poz;
if(c[casa].cul ==’R’)
v[nrjucator].pas ++;
else
if(c[casa].cul == ’G’)
{
val = casa * c[casa].c;
if(v[nrjucator].sumL < val)
if(v[nrjucator].pas > 0)
v[nrjucator].pas --;
else
v[nrjucator].e_joc = 0;
else
{
v[nrjucator].sumL -= val;
v[nrjucator].sumE += casa;
}
CAPITOLUL 5. OJI 2019 5.2. VALUTAR - OJI 2019 90
}
else
if(c[casa].cul == ’V’)
{
val = casa * c[casa].v;
if(v[nrjucator].sumE < casa)
if(v[nrjucator].pas > 0)
v[nrjucator].pas --;
else
v[nrjucator].e_joc = 0;
else
{
v[nrjucator].sumE -= casa;
v[nrjucator].sumL += val;
}
}
nrjucator ++;
}
}
void write()
{
int i, nrj = 0, sum_max = 0, viz[100]={0}, k = 0;
for(i=1; i<=m; i++)
if(v[i].e_joc == 1)
{
nrj ++;
if(v[i].sumE > sum_max)
{
sum_max = v[i].sumE;
k=1;
viz[k] = i;
}
else
if(v[i].sumE == sum_max)
viz[++k] = i;
}
if(pr == 1)
cout << nrj << ’\n’;
else
{
for(i=1; i<=k; i++)
cout << viz[i] << ’ ’;
cout << ’\n’;
}
}
int main()
{
read();
joc();
write();
return 0;
}
OJI 2018
În figurile 1, 2, 3, 4 sunt piese de puzzle care respectă regulile descrise, iar ı̂n figura 5 şi ı̂n figura
6 NU sunt piese de puzzle, pentru că nu pot fi obţinute prin lipirea unor coloane de X-uri, una
după cealaltă, de la stânga spre dreapta.
Fiind mic, Mihai nu poate rezolva puzzle-ul, dar poate face o singură operaţie: alege două piese
şi le ı̂mbină ı̂n dreptul laturilor de sus, răsturnând una dintre piese sus-jos (fără să o rotească sau
să o răstoarne stânga-dreapta). Dacă ı̂n urma acestei operaţii el obţine un dreptunghi format din
coloane complete de X-uri, toate coloanele având aceeaşi ı̂nălţime, este mulţumit. De exemplu,
piesa din figura 1 şi cea din figura 2 pot fi ı̂mbinate ı̂n modul descris.
În figura 7 este piesa din figura 2 răsturnată sus-jos. În figura 8 este ilustrat dreptunghiul care
se obţine din piesa din figura 1 şi piesa din figura 2 răsturnată sus-jos.
Observaţi că, dacă am roti piesa din figura 4, am putea să o ı̂mbinăm cu piesa din figura 1,
dar rotaţia nu este permisă.
Vom codifica o piesă printr-un număr natural, fiecare cifră din număr reprezentând (ı̂n ordine
de la stânga la dreapta) câte X-uri se află pe coloana corespunzătoare din piesă.
De exemplu:
- piesa din figura 1 este codificată 4232;
- piesa din figura 2 este codificată 1323;
- piesa din figura 3 este codificată 4444;
- piesa din figura 4 este codificată 3231.
Cerinţe
Determinaţi care este numărul de moduri ı̂n care Mihai poate alege câte două piese dintre cele
N pentru a face o operaţie ı̂n modul descris mai sus.
91
CAPITOLUL 6. OJI 2018 6.1. PUZZLE - OJI 2018 92
Date de intrare
Fişierul de intrare puzzle.in conţine pe prima linie un număr natural N ce reprezintă numărul
de piese din joc. Pe linia a doua se găsesc N numere naturale, separate prin câte un singur spaţiu,
reprezentând codificările celor N piese.
Date de ieşire
Fişierul de ieşire puzzle.out va conţine o singură linie pe care va fi scris numărul cerut.
Exemple
puzzle.in puzzle.out Explicaţii
5 3 Se pot ı̂mbina 3 perechi de piese: piesa 1 cu piesa 5, piesa
222 432 234 123 111 2 cu piesa 3, piesa 2 cu piesa 4. Piesele 3 şi 4 s-ar putea
ı̂mbina corect dacă una dintre ele ar fi răsturnată stânga-
dreapta sau rotită, dar acest lucru nu e permis.
Observam ca doua numere reprezinta codificarile a doua piese ce pot fi cuplate daca
insumand doua cate doua cifrele de pe aceleasi pozitii in cele doua numere se obtin
aceeasi valoare.
O prima solutie, care obtine punctaj partial, neincadrandu-se in timp, fixeaza toat
perechile posibile de numere si aplica testul de mai sus.
O solutie mai buna, liniara este urmatoarea: observam ca doua configuratii sunt
identice daca scazand cu aceeasi valoare fiecare cifra a uneia, se obtine cealalta.
Astfel, fiecarui numar dat ii asociem drept cod valoarea obtinuta scazand din fieca
cifra a sa cifra cu valoare minima.
Astfel, intr-un vector c, pe pozitia fiecarui cod vom numara cate numere cu acel co
Pentru codul 0 adunam la solutie c[0] * (c[0] - 1) / 2, adica toate modurile de a a
piese cu toate laturile netede. Pentru fiecare dintre celelalte coduri i exista un
cod j pentru care piesele cu cele 2 coduri se pot imbina. Astfel, adunam la solutie
c[i] * c[j]. Codul j asociat unui cod i se obtine usor folosind algoritmul de parcu
cifrelor unui numar, aplicat lui i (practic, inlocuind fiecare cifra de valoare x a
valoarea maxim-x, unde maxim reprezinta valoarea celei mai mari cifre din i).
Gradul de dificultate: 3
CAPITOLUL 6. OJI 2018 6.1. PUZZLE - OJI 2018 93
int f[DIMK];
int v[DIMN];
int c[12];
long long sol;
int n, k;
int getCode(int x)
{
int t = 0, minim = 9;
while (x)
{
c[++t] = x%10;
x /= 10;
if (c[t] < minim)
minim = c[t];
}
int r = 0;
for (int i=t;i>=1;i--)
r = r * 10 + (c[i] - minim);
return r;
}
int r = 0;
for (int i = t; i>=1; i--)
{
r = r * 10 + (maxim - c[i]);
}
return r;
}
int numar(int n)
{
int s = 0;
while (n)
{
s++;
n /= 10;
}
return s;
}
int main ()
{
int aux;
fin>>n;
{
fin>>v[i];
if (i == 1)
k = numar(v[i]);
f[aux = getCode(v[i])]++;
//cout<<v[i]<<" "<<aux<<" "<<getReverse(aux, k)<<"\n";
}
sol = 0;
for (int i=1;i<=100000;i++)
sol += f[i] * 1LL * f[ getReverse(i, k) ];
sol /= 2;
fout<<sol<<"\n";
return 0;
}
ifstream f("puzzle.in");
ofstream g("puzzle.out");
int n,v[100000],nrc,x,y,k,i,Max;
long long s,z;
int main()
{ f>>n>>x;
y=x;
while(y){nrc++;y=y/10; k=k*10+1;}
red(x);
if(x==0) z++;
else v[x]++;
for(i=2;i<=n;++i)
{ f>>x;
red(x);
if(x==0) z++;
else {Max=max(Max,x);v[x]++;}
}
s= z*(z-1)/2;
for(i=1;i<Max;i++)
if(v[i]) {x=9*k-i;
red(x);
if(x>i && v[x]) s=s+v[i]*v[x];
}
g<<s<<’\n’;
f.close();
g.close();
return 0;
}
Cerinţe
Date de intrare
Fişierul de intrare tbile.in conţine pe prima linie un număr natural c reprezentând cerinţa
care trebuie să fie rezolvată (1 sau 2), pe a doua linie un număr natural n, reprezentând numărul
de bile ce se inscripţionează, iar pe cea de a treia linie un număr natural m, reprezentând numărul
de bile care ı̂ncap ı̂ntr-un tub. Dacă cerinţa este c 2, fişierul de intrare conţine, ı̂n plus, pe a
patra linie, un număr natural v reprezentând numărul unui nivel.
Date de ieşire
Dacă cerinţa este c 1, atunci, pe prima linie a fişierului tbile.out, vor fi scrise două numere
naturale, separate printr-un spaţiu, reprezentând, ı̂n această ordine, numărul de tuburi de culoare
roşie necesare pentru a ı̂mpacheta bilele din şirul Y , respectiv, numărul total de bile conţinute de
acestea.
Dacă cerinţa este c 2, atunci, pe prima linie a fişierului tbile.out va fi scris un număr natural
reprezentând suma numerelor inscripţionate pe bilele de pe nivelul v.
Exemple
Gradul de dificultate: 4
X[v], X[v+m], X[v+2*m], ... avand valorile <= n (bilele situate pe nivelul v
in tuburi galbene);
v+r1, v+m+r2, v+2*m+r3, ... avand valorile <= n (bilele situate pe nivelul v
in tuburi rosii) unde ri este egal cu numarul de termeni din sirul X <= v+(i-1)*m.
Pentru a obtine punctajul maxim, suma valorilor inscriptionate pe bile din tuburi
rosii avand valorile situate intre doi termeni consecutivi din sirul X poate fi
determinata utilizand sume de tip Gauss.
ifstream in("tbile.in");
ofstream out("tbile.out");
int main()
CAPITOLUL 6. OJI 2018 6.2. TBILE - OJI 2018 97
{
in>>v>>n>>m;
if(v==2)
in>>c;
x[1]=1;x[2]=3;
y=4;p=3;
k=2;nivg=2;
br=c;
while(x[k]+y<=n)
{
k++;
nivg++;
if(nivg>m)nivg=1;
x[k]=x[k-1]+y;
if(nivg==c) s+=x[k];
AdunaRosu(x[k]-1);
y++;
if(y==x[p]){y++;p++;}
}
if(v==1)
{
br=n-k;
if(br%m==0)
out<<br/m;
else
out<<br/m+1;
out<<’ ’<<br<<’\n’;
}
else
{
if(x[k]<n)
{
k++;
AdunaRosu(n);
}
out<<s<<’\n’;
}
return 0;
}
ifstream f("tbile.in");
ofstream g("tbile.out");
ull galben[100000],s,t,p,rest;
int i,iRosu,v,r,n,m,c,j,nr;
int main()
{ f>>v>>n>>m;
galben[1]=1;galben[2]=3;
iRosu=2; r=4; i=2;
while(galben[i]+r<=n)
{ galben[++i]=galben[i-1]+r++;
if(r==galben[iRosu+1]) {iRosu++; r=galben[iRosu]+1;}
}
rest=n-galben[i];
r=n-i;
if(v==1)g<<r/m+(r%m>0)<<’ ’<<r<<’\n’;
else
{ f>>c;
CAPITOLUL 6. OJI 2018 6.2. TBILE - OJI 2018 98
if(c==1) s=3;
else if(c==2) s=2;
nr=1;
for(j=3;j<=i;j++)
{ if(j%m==c || j%m==0 && m==c) s=s+galben[j];
if(nr<c)
if(nr+galben[j]-galben[j-1]-1<c) {nr=nr+galben[j]-galben[j-1]-1; continue;}
else
p=galben[j-1]+(c-nr);
else
{
while(nr+(galben[j]-galben[j-1])-1<=m) {nr+=(galben[j]-galben[j-1]-1);j++;}
if(galben[j-1]+(m-nr)+c>=galben[j]) {nr=galben[j]-galben[j-1]-1-(m-nr);
continue;}
p=galben[j-1]+(m-nr+c);
}
nr=c;
t=(galben[j]-1-p)/m+1;
s+=p*t+(t-1)*t/2*m;
nr=c+galben[j]-(p+(t-1)*m)-1;
if(nr>m) nr-=m;
}
if(rest>0)
{
if(nr<c)
p=galben[i]+(c-nr);
else
p=galben[i]+(m-nr)+c;
g<<s<<’\n’;
}
f.close();
g.close();
return 0;
}
OJI 2017
Cerinţe
Cunoscându-se faptul că organizatorii doresc susţinerea a cât mai multor cursuri, să se deter-
mine:
1) Numărul maxim de cursuri care pot fi programate ı̂n cele K săli de clasă, ţinând cont de
restricţia indicată.
2) În dorinţa de a programa toate cursurile, ı̂n cele K săli, organizatorii decid să modifice
durata cursurilor, păstrând ı̂nsă neschimbată ora de ı̂nceput a lor. Astfel, ei hotărăsc ca toate
cursurile să dureze un interval egal de timp, care ı̂nsă nu va depăşi durata celui mai lung curs
propus iniţial de unul dintre cei N profesori. Determinaţi care poate fi durata maximă pe care o
pot avea cursurile ı̂n aceste condiţii.
Date de intrare
În fişierul de intrare cursuri.in se găseşte pe prima linie un număr natural C. Pentru toate
testele, C poate lua numai valorile 1 sau 2. Pe linia a doua se găseşte o pereche de numere naturale
N K, separate printr-un spaţiu, reprezentând numărul profesorilor şi numărul de săli de clasă. Pe
următoarele N linii se găsesc perechi de numere naturale ai bi , care reprezintă intervalele de timp
ı̂n care cei N profesori ı̂şi susţin cursurile. Numerele ı̂n cadrul unei linii sunt separate printr-un
spaţiu.
Date de ieşire
Dacă valoarea lui C este 1, se va rezolva numai punctul 1) din cerinţe. În acest caz, fişierul de
ieşire cursuri.out va conţine pe prima linie un număr natural reprezentând numărul maxim de
cursuri care pot fi programate ı̂n cele K săli de clasă, ţinând cont de restricţia indicată.
Dacă valoarea lui C este 2, se va rezolva numai punctul 2) din cerinţe. În acest caz, fişierul de
ieşire cursuri.out va conţine pe prima linie un număr natural reprezentând durata maximă pe
care o pot avea cele N cursuri, astfel ı̂ncât toate să poată fi susţinute ı̂n cele K săli disponibile.
99
CAPITOLUL 7. OJI 2017 7.1. CURSURI - OJI 2017 100
Exemple
cursuri.in cursuri.out Explicaţii
1 3 O variantă de programare optimă este următoarea:
42 - ı̂n prima sală se vor susţine cursurile programate ı̂ntre 1, 3
2 16 şi 3, 18
13 - ı̂n a doua clasă se susţine cursul programat ı̂ntre 1, 20.
3 18
1 20
2 4 Durata maximă pe care o pot avea toate cursurile este 4.
42 Cursul al treilea se va mări şi se va desfăşura ı̂ntre 1, 5, celelalte
5 12 se vor micşora. Cursurile vor fi distribuite ı̂n cele două săli astfel:
9 18 Sala 1: al treilea şi primul profesor programaţi ı̂ntre 1, 5 re-
13 spectiv 5, 9;
17 Sala 2: al patrulea şi al doilea profesor programaţi ı̂ntre 1, 5
respectiv 9, 13;
Prima cerinta poate fi rezolvata printr-un algoritm, care presuspune sortarea inter
dupa momentul de sfarsit al cursurilor. Dupa aceasta operatie, se parcurg toate cur
si pentru fiecare se verifica daca poate fi sustinut, adica daca exista vreo sala c
libera la momentul de inceput al cursului. Daca exista mai multe sali disponibile,
va fi programat in sala care minimizeaza durata cand aceasta ramane neocupata, adic
in care cursul anterior programat se termina cel mai tarziu. Complexitate O(N*N +N*
struct Interval
{
int a, b;
};
Interval t[nmax];
int d[nmax];
int n, K, op, M;
void Citire()
{
int i;
ifstream fin(inFile);
fin >> op;
fin >> n >> K;
for (i = 1; i <= n; i++)
{
fin >> t[i].a >> t[i].b;
M = max(M, t[i].b - t[i].a);
}
fin.close();
}
void Optiune1()
{
int i, j, p, ans, D;
sort(t + 1, t + n + 1, Cmp);
ans = 0;
for (i = 1; i <= n; i++)
{
// caut d[p] maxim, p=1..K
// cat mai aproape de capatul stang al intervalului i
p = 0; D = -1;
for (j = 1; j <= K; j++)
if (d[j] <= t[i].a && d[j] > D)
{
p = j;
D = d[j];
}
if (p != 0)
{
d[p] = t[i].b;
ans++;
}
}
ofstream fout(outFile);
fout << ans << "\n";
fout.close();
}
sort(t + 1, t + n + 1, Cmp);
return 1;
}
void Optiune2()
{
int st, dr, L, sol;
st = 1;
dr = M;
sol = 0;
while (st <= dr)
{
L = (st + dr) / 2;
if (Verifica(L))
{
sol = L;
st = L + 1;
}
else
dr = L - 1;
}
ofstream fout(outFile);
fout << sol << "\n";
fout.close();
}
int main()
{
Citire();
if (op == 1)
Optiune1();
else
Optiune2();
return 0;
}
Sala[1]=A[1].second;
for(int i=2; i<=N; i++)
{
Min = inf;
for(int j=1; j<=K; j++)
if (A[i].first>=Sala[j] && Min> A[i].first - Sala[j])
{
Min = A[i].first - Sala[j];
poz = j;
CAPITOLUL 7. OJI 2017 7.1. CURSURI - OJI 2017 103
return nr;
}
sort (A + 1, A + N + 1, cmpf);
ans = tmax;
for(i=K+1; i<=N; ++i)
ans = min(ans, A[i].first - A[i-K].first);
return ans;
}
int main()
{
freopen("cursuri.in", "r", stdin);
freopen("cursuri.out", "w", stdout);
if (T==1)
printf("%d\n", solve_1(A));
else
printf("%d\n", solve_2(A));
return 0;
}
curs A[Nmax];
memset(Sala,0,sizeof(Sala));
sortN2_second(A);
Sala[1]=A[1].second;
for(int i=2; i<=N; i++)
{
Min = inf;
for(int j=1; j<=K; j++)
if (A[i].first>=Sala[j] && Min> A[i].first - Sala[j])
{
Min = A[i].first - Sala[j];
poz = j;
}
return nr;
}
sortN2_first(A);
ans = tmax;
for(i=K+1; i<=N; ++i)
ans = min(ans, A[i].first - A[i-K].first);
return ans;
}
int main()
{
freopen("cursuri.in", "r", stdin);
freopen("cursuri.out", "w", stdout);
if (T==1)
printf("%d\n", solve_1(A));
else
printf("%d\n", solve_2(A));
return 0;
}
ifstream f("cursuri.in");
ofstream g("cursuri.out");
CAPITOLUL 7. OJI 2017 7.1. CURSURI - OJI 2017 105
struct curs
{
int oi,of;
bool p;
}a[1010];
void sort()
{
int i, ok, poz, nn=n;
curs x;
do
{
ok=1;
for(i=1;i<nn; i++)
if(a[i].of>a[i+1].of)
x=a[i], a[i]=a[i+1], a[i+1]=x, poz=i, ok=0;
nn=poz;
} while(!ok);
}
int cerinta1()
{
int cate=0, i, j;
curs sal[1010];
for(i=0;i<=k;i++)
sal[i].oi=sal[i].of=0;
for(i=1;i<=n;i++)
{
int p=0;
for(j=1;j<=k;j++)
if(a[i].oi>=sal[j].of && a[i].oi-sal[j].of<=a[i].oi-sal[p].of)
p=j;
if(p)
sal[p]=a[i], cate++;
}
return cate;
}
bool verif(int x)
{
int i;
for(i=1;i<=n;i++)
a[i].of=a[i].oi+x, a[i].p=false;
sort();
if(cerinta1()==n)
return true;
return false;
}
int cerinta2()
{
int i, gasit=1;
for(i=1;i<=n;i++)
if(a[i].of-a[i].oi>dmax)
dmax=a[i].of-a[i].oi;
while(s<=d)
{
m=(s+d)/2;
if(verif(m))
gasit=m, s=m+1;
else
d=m-1;
}
CAPITOLUL 7. OJI 2017 7.1. CURSURI - OJI 2017 106
return gasit;
}
int main()
{
int i;
f>>cerinta>>n>>k;
for(i=1;i<=n;i++)
f>>a[i].oi>>a[i].of, a[i].p=false;
sort();
if(cerinta==1)
g<<cerinta1();
else
g<<cerinta2();
return 0;
}
struct curs
{
int a,b;
};
int best = 0;
for(int i = 0; i < maxn +100; ++i)
best = max(best, arr[i]), arr[i] = 0;
return best;
}
return poz;
}
for(int i=1;i<len;i++)
{
if(a[i-1]==a[i])
{
dup++;
}
else
{
a[i-dup]=a[i];
}
}
len=len-dup;
}
int main()
{
ifstream f("cursuri.in");
ofstream g("cursuri.out");
int t, n, k;
curs v[1010];
if(t == 1)
{
static int norm[2020], len = 2*n;
sort(norm, norm+len);
while(st<=dr)
{
mij=st+(dr-st)/2;
for(int i = 0; i < n; ++i)
v[i].b = v[i].a + mij;
if(nr_suprapuneri(v, n, 100000 + 10) <= k)
rez=mij, st=mij+1;
else
dr=mij-1;
CAPITOLUL 7. OJI 2017 7.2. JOC - OJI 2017 108
g<<rez<<endl;
}
return 0;
}
Cerinţe
Cunoscând numerele N , K şi cele K şiruri de numere care reprezintă rundele jucate, scrieţi
un program care să rezolve una dintre următoarele două cerinţe:
1. Să se determine câte runde a câştigat fiecare copil.
2. Să se determine care este cel mai mare număr de marcări efectuate până la câştigarea unei
runde.
Date de intrare
Fişierul de intrare joc.in conţine pe prima linie un număr natural C. Pentru toate testele, C
poate lua numai valorile 1 sau 2. Pe a doua linie se află două numere naturale N şi K, separate
prin câte un spaţiu, reprezentând dimensiunea tablei de joc şi respectiv numărul de runde jucate.
Pe următoarele K linii sunt descrise rundele de joc, câte o rundă pe câte o linie a fişierului. În
cadrul liniilor, numerele sunt separate prin câte un spaţiu.
Date de ieşire
Dacă valoarea lui C este 1, se va rezolva numai punctul 1) din cerinţe. În acest caz, fişierul
de ieşire joc.out va conţine pe prima linie două numere naturale t şi s, separate printr-un spaţiu,
unde t reprezintă numărul de runde câştigate de Teodora, iar s numărul rundelor câştigate de
Ştefan.
Dacă valoarea lui C este 2, se va rezolva numai punctul 2) din cerinţe. În acest caz, fişierul
de ieşire joc.out va conţine pe prima linie numărul cel mai mare de marcări efectuate până la
câştigarea unei runde.
CAPITOLUL 7. OJI 2017 7.2. JOC - OJI 2017 109
Exemple
Pentru a simplifica retinerea datelor definim structura ’’marcare’’ ale carei campu
memora numarul de celule marcate de fiecare jucator, corespunzator liniei, coloanei
diagonalei sau semidiagonalei din care face parte.
struct marcare
{
int l[151], c[151];
int dp, dp1, dp2;
int ds, ds1, ds2;
} jucator[2];
int main()
{
ifstream f("joc.in");
ofstream g("joc.out");
f>>c>>n>>k;
m=n*n;
maxim=-1;
for(i=1;i<=k;i++)
{
j=i%2;//jucatorul care incepe runda
gata=0;
for(joc=0;joc<2;joc++)
{
for(p=1;p<=n;p++)
jucator[joc].l[p]=jucator[joc].c[p]=0;
jucator[joc].dp=jucator[joc].dp1=jucator[joc].dp2=0;
jucator[joc].ds=jucator[joc].ds1=jucator[joc].ds2=0;
}
mutari=m+1;
for(p=1; p<=m; p++)
{
joc=(j+p%2)%2;//jucatorul care marcheaza 0=T, 1=S
f>>nr;
if(col==0)
col=n;
else
lin++;
if(lin+col==n+1)
jucator[joc].ds++;
else
if (lin+col==n)
jucator[joc].ds1++;
else
if(lin+col==n+2)
jucator[joc].ds2++;
mutari=p;
}
}
}
if(c==1)
g<<cT<<’ ’<<cS<<’\n’;
else
g<<maxim<<’\n’;
f.close();
g.close();
return 0;
}
bool win;
bool addT(int x)
{
if(win) return false;
if(x%N==0)
linie = x/N, coloana = N;
else
linie = x/N+1, coloana = x%N;
++LT[linie];
if(LT[linie]==N)
return true;
++CT[coloana];
if(CT[coloana]==N)
return true;
dif = linie-coloana+2;
dif = linie+coloana-(N-1);
if(dif>=1 && dif<=3)
{
++diag2T[dif];
if((dif==2 && diag2T[dif]==N) ||
(dif!=2 && diag2T[dif]==N-1))
return true;
}
return false;
}
bool addS(int x)
{
if(win) return false;
if(x%N==0)
linie = x/N, coloana = N;
else
linie = x/N+1, coloana = x%N;
++LS[linie];
if(LS[linie]==N) return true;
++CS[coloana];
if(CS[coloana]==N) return true;
dif = linie-coloana+2;
if(dif>=1 && dif<=3)
{
++diag1S[dif];
if((dif==2 && diag1S[dif]==N) ||
(dif!=2 && diag1S[dif]==N-1))
return true;
}
dif = linie+coloana-(N-1);
if(dif>=1 && dif<=3)
{
++diag2S[dif];
if((dif==2 && diag2S[dif]==N) ||
(dif!=2 && diag2S[dif]==N-1))
return true;
CAPITOLUL 7. OJI 2017 7.2. JOC - OJI 2017 113
return false;
}
void initialize()
{
memset(LT, 0, sizeof(LT));
memset(LS, 0, sizeof(LS));
memset(CT, 0, sizeof(CT));
memset(CS, 0, sizeof(CS));
memset(diag1T, 0, sizeof(diag1T));
memset(diag1S, 0, sizeof(diag1S));
memset(diag2T, 0, sizeof(diag2T));
memset(diag2S, 0, sizeof(diag2S));
}
int main()
{
freopen("joc.in", "r", stdin);
freopen("joc.out", "w", stdout);
scanf("%d\n", &T);
scanf("%d %d\n", &N, &K);
if(T==1)
printf("%d %d\n", winT, winS);
else
printf("%d\n", moves);
return 0;
}
ifstream fin("joc.in");
ofstream fout("joc.out");
struct scor
{
int A, B;
};
CAPITOLUL 7. OJI 2017 7.2. JOC - OJI 2017 114
int n, N; /// N = n * n
scor a[nmax * nmax];
scor L[nmax], C[nmax], DP[3], DS[3];
/**
a[i] =(x,y) : coordonatele din matrice corespunzatoare
valorii i, unde i=1..n*n
L[i]=(x, y) : pe linia i sunt puse x X-uri si y zeroruri
D[i]=(x, y) : pe coloana i sunt puse x X-uri si y zeroruri
DP[i]=(x,y) : pe diagonalele paralele cu diagonala principala
sunt puse x X-uri si y zeroruri
DS[i]=(x,y) : pe diagonalele paralele cu diagonala secundara
sunt puse x X-uri si y zeroruri
*/
void Matrice()
{
int i, j, p;
p = 0;
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
{
p++;
a[p].A = i;
a[p].B = j;
}
}
int main()
{
int nrMoves, whoWins, r, op, K;
int scorA, scorB, maxMoves;
Matrice();
if (op == 1)
fout << scorA << " " << scorB << "\n";
else
fout << maxMoves << "\n";
fout.close();
return 0;
}
ifstream f("joc.in");
ofstream g("joc.out");
int v,n,k;
if(lin==1) return 1;
for(int i=1;i<=n;i++) ///coloana
{
if(a[i][y]!=p){
col=0;
break;
}
}
if(col==1) return 1;
for(int i=0;i<=n-dif-1;i++)
{
if(a[i1+i][j1+i]!=p)
{
d1=0; break;
}
}
}
else
{
d1=0;
}
if(d1==1) return 1;
{
i1=1+dif; j1=n;
}
for(int i=0;i<=n-dif-1;i++)
{
if(a[i1+i][j1-i]!=p)
{
d2=0; break;
}
}
}
else
{
d2 = 0;
}
if(d2==1) return 1;
return 0;
}
void incepe_jocul()
{
int x,lin,col,contor=0,contormax=0,primul=1,poz1=1,poz2=2;
int crt,Teo=0,Stef=0;
f>>v>>n>>k;
///vector<vector<int>> a(n+1,vector<int>(n+1,0));
int a[60][60];
while(f>>x)
{
contor++;
(contor%2==0) ? crt=poz2 : crt=poz1;
lin=(x-1)/n+1;
a[lin][col]=crt;
if(test(a,lin,col,crt)==1)
{
(crt==1) ? Teo++ : Stef++;
contormax=max(contor,contormax);
for(int i=1;i<=n*n-contor;++i)
f>>x;
if(primul==1)
{
primul=2;
poz1=2; poz2=1;
}
else
{
primul=1;
poz1=1; poz2=2;
}
zero(a,n);
contor=0;
}
}
if(v==1)
{
g<<Teo<<" "<<Stef<<"\n";
}
else
{
g<<contormax<<"\n";
}
}
CAPITOLUL 7. OJI 2017 7.2. JOC - OJI 2017 118
int main()
{
incepe_jocul();
return 0;
}
OJI 2016
Date de intrare
Date de ieşire
a Dacă valoarea lui p este 1, atunci se va rezolva numai cerinţa 1. În acest caz, fişierul de ieşire
axyz.out va conţine pe prima linie un şir de cifre reprezentând numărul natural Y determinat
(răspunsul la cerinţa 1).
a Dacă valoarea lui p este 2, atunci se va rezolva numai cerinţa 2. În acest caz, fişierul de
ieşire axyz.out va conţine pe prima linie un număr natural reprezentând numărul Z determinat
(răspunsul la cerinţa 2).
119
CAPITOLUL 8. OJI 2016 8.1. AXYZ - OJI 2016 120
Exemple
axyz.in axyz.out Explicaţii
1 121612 Se rezolvă cerinţa 1.
12 A=12, N=6, X=121621
6 Cel mai mare număr Y strict mai mic ca X este: Y=121612.
121621
2 3 Se rezolvă cerinţa 2. A=12, N=6, X=121621
12 Sunt Z=3 posibilităţi distincte prin care se obţine numărul A
6 din X: 1) 121621; 2) 1216 21; 3) 12 16 21
121621
Descrierea solutiei
- Determinam pozitia poz a celei mai mari cifre dintre cele situate pe pozitiile
k+1,k+2,...,N si cu proprietatea X[k]>X[poz]
- Altfel, daca cifra curenta este a atunci se pot forma cu NB numere A din
cifra a curenta si cele NB cifre b situate la dreapta lui a in X. Adaugam
numarul acestora la celelalte gasite pana in acest moment (Z=Z+NB)
-Complexitate O(N)
int x[30001];
ifstream f("axyz.in");
ofstream g("axyz.out");
int main()
{
int N,A,B,C,NB,Z,i,k,j, poz, t,cer;
f>>cer>>A>>N;
for(i=1; i<=N; i++)
f>>x[i];
///cerinta 1) - problema are solutie pentru toate testele propuse
if(cer==1)
{
k=N-1;
while(k>0 && x[k]<=x[k+1])
k--;
poz=N;
while(poz>k && x[poz]>=x[k])
poz--;
swap(x[k],x[poz]);
for(i=1; i<=k; i++)
g<<x[i];
for(i=N; i>k; i--)
g<<x[i];
g<<’\n’;
}
else ///cerinta 2
if(A<100)
{
B=A%10;
A=A/10;
Z=0;
NB=0;
for(i=N; i>=1; i--)
CAPITOLUL 8. OJI 2016 8.2. GALERIE - OJI 2016 122
if(x[i]==B)NB++;
else if(x[i]==A)Z+=NB;
g<<Z<<’\n’;
}
else
{
int i,C,NC=0,NBC=0,Z=0;
C=A%10;
A/=10;
B=A%10;
A/=10;
g<<Z<<’\n’;
}
return 0;
}
Cerinţe
Cunoscându-se numerele n, m, t şi cele t celule exterioare ı̂n care se află cârtiţele, să se
determine:
1. numărul maxim de celule ı̂n care sapă o cârtiţă până la oprirea tuturor cârtiţelor;
2. numărul maxim de celule din care este formată o galerie interioară.
Date de intrare
Fişierul de intrare galerie.in conţine pe prima linie, una dintre valorile 1 sau 2 reprezentând
cerinţa 1, dacă se cere determinarea numărului maxim de celule ı̂n care sapă o cârtiţă până la
oprirea tuturor cârtiţelor, respectiv cerinţa 2, dacă se cere determinarea numărul maxim de celule
din care este formată o galerie interioară.
Linia a doua conţine, separate prin câte un spaţiu, trei numere naturale: n şi m (reprezentând
dimensiunile terenului) şi t (reprezentând numărul de cârtiţe aflate ı̂n galeriile exterioare).
Linia a treia conţine cele t numere naturale separate prin câte un spaţiu, reprezentând poziţiile
celor t cârtiţe.
Date de ieşire
Fişierul de ieşire galerie.out conţine pe prima linie o valoarea naturală reprezentând numărul
maxim de celule ı̂n care sapă o cârtiţă până la oprirea tuturor cârtiţelor, dacă cerinţa a fost 1,
respectiv un număr natural reprezentând numărul maxim de celule din care este formată o galerie
interioară, dacă cerinţa a fost 2.
Exemple
Cerinta 1 ( 30 puncte)
Problema se restrange la fiecare pas la multimea cartitelor active (cele care sapa)
* se elimina apoi din multimea cartitelor active, cartitele care se opresc, fie pen
CAPITOLUL 8. OJI 2016 8.2. GALERIE - OJI 2016 124
in celula in care au ajuns se mai afla si alte cartite, fie pentru ca au ajuns in
alta galerie (pe marginea terenului sau intr-o galerie interioara);
Cerinta 2 ( 70 de puncte)
Daca o cartita sapa singura intr-o celula, atunci, se aduna o unitate la lungimea
traseului sapat.
Daca o cartita c1 sapa intr-o galerie interioara, de lungime l1, si ajunge in galer
unei alte cartite c2, care se afla intr-o galerie interioara de lungime l2, atunci
cartita c1 se opreste, galeriile se unesc, si lungimea galeriei l2, in care se afl
cartita c2, devine l1+l2.
Daca intr-o celula ajung, in acelasi moment de timp, mai multe cartite, c1, c2, ...
atunci, toate cartitele se opresc si se formeaza o galerie de lungime l1+l2+...+lk.
ifstream f("galerie.in");
ofstream g("galerie.out");
int n,m,t,k,x,i,pas,inou,jnou,a[205][205],
di[]={-1,0,1,0},dj[]={0,1,0,-1},sapa_cineva;
set<int> s;
set<int> sterse;
set<int>::iterator it;
set<int>::iterator it1;
if(interior(i,j))
for(k=0;k<4;k++)
{
i1=i+di[k];
j1=j+dj[k];
if(a[i1][j1]==c1)
{
a[i1][j1]=c2;
uneste_galerii(i1,j1,c1,c2);
}
CAPITOLUL 8. OJI 2016 8.2. GALERIE - OJI 2016 125
}
}
int main()
{ f>>k>>n>>m>>t;
for(i=1;i<=t;i++)
{f>>x;
if(x<=m) {C[i].i=0;C[i].j=x;C[i].di=1;C[i].dj=0;}
else
if(x<=n+m) {C[i].i=x-m;C[i].j=m+1; C[i].di=0;C[i].dj=-1;}
else
if(x<=2*m+n){C[i].i=n+1;C[i].j=2*m+n+1-x;C[i].di=-1;C[i].dj=0;}
else {C[i].i=2*n+2*m+1-x;C[i].j=0;C[i].di=0;C[i].dj=1;}
s.insert(i);
}
for(i=1;i<=n;i++)
a[i][0]=a[i][m+1]=-1;
for(i=1;i<=m;i++)
a[0][i]=a[n+1][i]=-1;
while(!s.empty())
{ sapa_cineva=0;
sterse.clear();
if(x==0)
{
a[inou][jnou]=i;
C[i].l++;
C[i].i=inou;
C[i].j=jnou;
sapa_cineva=1;
}
else
{ if(x!=-1)
{
uneste_galerii(inou,jnou,i,x);
C[x].l+=C[i].l;
if (x<i && a[inou+C[x].di][jnou+C[x].dj]!=x)
sterse.insert(x);
}
sterse.insert(i);
}
}
if(sapa_cineva) pas++;
}
if(k==1)
g<<pas<<’\n’;
else
{
x=C[1].l;
for(i=2;i<=t;i++)
if(C[i].l>x)
x=C[i].l;
g<<x<<’\n’;
}
f.close();
g.close();
return 0;
CAPITOLUL 8. OJI 2016 8.2. GALERIE - OJI 2016 126
ifstream f("galerie.in");
ofstream g("galerie.out");
short n,m,t,k,x,i,j,pas,inou,jnou,a[205][205],s[805],
di[]={-1,0,1,0},dj[]={0,1,0,-1},sapa_cineva,nr_active,nr_sterse;
bool sterg[805];
int main()
{
f>>k>>n>>m>>t;
for(i=1;i<=t;i++)
{
f>>x;
if(x<=m)
{
C[i].i=0;
C[i].j=x;
C[i].di=1;
C[i].dj=0;
}
else
if(x<=n+m)
{
C[i].i=x-m;
C[i].j=m+1;
C[i].di=0;
C[i].dj=-1;
}
else
if(x<=2*m+n)
{
C[i].i=n+1;
C[i].j=2*m+n+1-x;
C[i].di=-1;
C[i].dj=0;
}
else
{
C[i].i=2*n+2*m+1-x;
C[i].j=0;
CAPITOLUL 8. OJI 2016 8.2. GALERIE - OJI 2016 127
C[i].di=0;
C[i].dj=1;
}
s[i]=i;
}
for(i=1;i<=n;i++)
a[i][0]=a[i][m+1]=-1;
for(i=1;i<=m;i++)
a[0][i]=a[n+1][i]=-1;
nr_active=t;
while(nr_active)
{
sapa_cineva=0;
nr_sterse=0;
for(j=1;j<=nr_active;j++)
{
i=s[j];
inou=C[i].i+C[i].di;
jnou=C[i].j+C[i].dj;
x=a[inou][jnou];
if(x==0)
{
a[inou][jnou]=i;
C[i].l++;
C[i].i=inou;
C[i].j=jnou;
sapa_cineva=1;
}
else
{
if(x!=-1)
{
uneste_galerii(inou,jnou,i,x);
C[x].l+=C[i].l;
if (x<i && a[inou+C[x].di][jnou+C[x].dj]!=x)
sterg[x]=true;
}
sterg[i]=true;
}
}
j=0;
for(i=1;i<=nr_active;++i)
if(!sterg[s[i]])
s[++j]=s[i];
nr_active=j;
if(sapa_cineva)
pas++;
}
if(k==1)
g<<pas<<’\n’;
else
{
x=C[1].l;
for(i=2;i<=t;i++)
if(C[i].l>x)
x=C[i].l;
g<<x<<’\n’;
}
f.close();
g.close();
return 0;
}
CAPITOLUL 8. OJI 2016 8.2. GALERIE - OJI 2016 128
OJI 2015
Cerinţe
Dat fiind un număr natural N să se determine cel mai mic număr echilibrat, strict mai mare
decât N .
Date de intrare
Date de ieşire
Fişierul de ieşire ech.out va conţine o singură linie pe care va fi scris cel mai mic număr
echilibrat, strict mai mare decât N .
Exemple
ech.in ech.out Explicaţii
99 110 1+0=1.
123133 123134 1+3+3=2+1+4.
Solutie 80 de puncte
129
CAPITOLUL 9. OJI 2015 9.1. ECH - OJI 2015 130
sp[i]= suma cifrelor din pozitiile pare incepand cu cea mai semnificativa
cifra si terminand cu pozitia i.
Precalculam si cea mai mare suma cu care putem inlocui pozitiile impare
(numarul de cifre de 9) respectiv pare.
In cazul in care numarul are N cifre si sunt toate egale cu 9 si N este par
algoritmul se va opri la pozitia primei cifre zero din fata numarului.
Daca la o pozitie i am gasit cifra mai mica decat 9 determinam cea mai buna
inlocuire (cea mai mica cifra pentru care avem sanse la echilibru).
ifstream fin("ech.in");
ofstream fout("ech.out");
int a[50];
int lg=0;
int nx[50];
int main()
{int r;
citire();
r=rest();
if (r) add(11-r);
else add(11);
while (!ech())
add(11);
afisare();
return 0;
}
void add(int x)
{int i, t=0, s;
nx[0]=x%10; nx[1]=x/10;
for (i=0; i<lg; i++)
{s=a[i]+nx[i]+t;
a[i]=s%10;
t=s/10;}
if (t+nx[i]) a[lg++]=t+nx[i];
}
int rest()
{int i, r=0;
for (i=lg-1; i>=0; i--)
{
r=r*10+a[i];
r=r%11;
}
return r;
}
int ech()
{ int s1=0, s2=0;
for (int i=0; i<lg; i+=2)
s1+=a[i], s2+=a[i+1];
return s1==s2;
}
void citire()
{char c;
int st, dr, aux;
while (fin>>c)
a[lg++]=c-’0’;
//inversez a
for (st=0, dr=lg-1; st<dr; st++, dr--)
{ aux=a[st]; a[st]=a[dr]; a[dr]=aux; }
}
void afisare()
{int i;
for (i=lg-1; i>=0; i--) fout<<a[i];
fout<<’\n’;
fout.close();
}
#include <fstream>
ifstream fin("ech.in");
ofstream fout("ech.out");
int n,v[50],r;
void citire()
{
char ch;
CAPITOLUL 9. OJI 2015 9.1. ECH - OJI 2015 132
int i,aux;
while(fin>>ch)
n++,v[n]=ch-’0’;
for(i=1;i<=n/2;i++)
aux=v[i],v[i]=v[n+1-i],v[n-i+1]=aux;
v[0]=n;
}
void aduna11(int r)
{
int i,t,aux;
t=r;
for(i=1;i<=v[0];i++)
{
aux=v[i]+t;
v[i]=aux%10;
t=aux/10;
}
if(t)v[++v[0]]=t;
}
int ech()
{
int i,sp=0,si=0;
for (i=1;i<=v[0];i++)
if(i%2)si+=v[i];
else sp+=v[i];
if(si==sp)return 1;
else return 0;
}
int rest11()
{
int i,r=0;
for(i=v[0];i>=1;i--)
r=(r*10+v[i])%11;
return r;
}
void afis()
{
int i;
for(i=v[0];i>=1;i--)
fout<<v[i];
fout<<’\n’;
}
int main()
{
citire();
r=rest11();
if(r)
aduna11(11-r);
else
aduna11(11);
while(!ech())
aduna11(11);
afis();
fout.close();
return 0;
}
int n,i,j,s1,s2,nr,p;
char s[Nmax],S[Nmax];
int x[Nmax];
void detp()
{
int i;
for (i=1;i<=n;i++)
if (s[i]>S[i])
{p=i; break;}
}
void solve()
{
int aux1,aux2;
if (s1>s2)
{
i=n; if (i%2==0) i++; s[n+1]=’0’;
while (s1-s2>s[i]-’0’+(9-s[i-1]+’0’))
{
s1-=(s[i]-’0’);
s[i]=’0’;
s2+=(9-s[i-1]+’0’);
s[i-1]=’9’;
i=i-2;
}
if (s2>s1)
{
i=n; if (i%2==1) i++;
swap(s1,s2); s[n+1]=’0’;
while (s1-s2>s[i]-’0’+(9-s[i-1]+’0’))
{
s1-=(s[i]-’0’);
s[i]=’0’;
s2+=(9-s[i-1]+’0’);
s[i-1]=’9’;
i=i-2;
}
{
aux1=s[i]; aux2=i;
s1-=s[i]-’0’; s[i]=’0’;
if (s1-s2==0) s[i]=’1’,s1++;
i--;
while (s[i]+(s1-s2)>’9’ && i>0) i-=2;
s[i]+=(s1-s2);
if (i==0)
{
s[1]=’1’;
for (i=1;i<n;i++) s[i+1]=’0’;
s[++n]=’1’;
}
}
}
}
int main()
{
freopen("ech.in","r",stdin);
freopen("ech.out","w",stdout);
gets(s+1);
n=strlen(s+1);
memcpy(S,s,sizeof(S));
for (i=1;i<=n;i++)
{
if (i%2==1) s1=s1+(s[i]-’0’);
else s2=s2+(s[i]-’0’);
}
solve();
detp();
if (!p)
{
i=n;
while (s[i]==’9’) i--;
if (i==0){
s[1]=’1’;
for (i=1;i<=n;i++) s[i+1]=’0’;
n++; s1=1; s2=0;}
else
{
s[i]++;
if (i%2==1) s1++; else s2++;
}
solve();
}
detp();
for (i=n;i>p;i--)
if (i%2==1) x[++x[0]]=i;
sort(x+1,x+x[0]+1,cmp);
for (i=p+1;i<=n;i++)
if (i%2==0)
{
nr=min(s[i],s[x[x[0]]]);
s[i]=s[i]-nr+’0’;
s[x[x[0]]]=s[x[x[0]]]-nr+’0’;
--x[0];
if (s[x[x[0]]]==’0’) break;
}
for (i=1;i<=n;i++)
printf("%c",s[i]);
return 0;
}
#include <fstream>
ifstream f("ech.in");
ofstream g("ech.out");
int main()
{
char s[50],c;
int si=0, sp=0, i, x=0;
x--;
for(i=0;i<=x;i++)
if(i%2)
sp+=s[i]-’0’;
else
si+=s[i]-’0’;
do
{
int ok=0;
for(i=x;i>=0 && !ok; i=i-1)
if(s[i]<’9’)
{
s[i]++;
ok++;
if(i%2)
sp++;
else
si++;
}
else
{
s[i]=’0’;
if(i%2)
sp-=9;
else
si-=9;
}
if(!ok)
{
si=1;sp=0;
s[0]=’1’;
s[x+1]=’0’;
x++;
}
} while(si!=sp);
for(i=0;i<=x;i++)
g<<s[i];
g<<’\n’;
g.close();
return 0;
}
struct numar
{
int v[50],n;
};
numar next(numar a)
{
int i, s1, s2, s[2], t[2], i2, j, x, k;
a.v[a.n+1]=0;
CAPITOLUL 9. OJI 2015 9.1. ECH - OJI 2015 136
s[0]=0;
s[1]=0;
for(i=1;i<=a.n+1;i++)
{
i2=i%2;//paritatea curenta; 1-i2 paritatea inversa celei curente
s[i2]=s[i2]+a.v[i];
}
t[0]=0;
t[1]=0;
for(i=1;i<=a.n+1;i++)
{
i2=i%2;
a.v[i-1]=0;
if(i>1)t[1-i2]=t[1-i2]+9;
int main()
{
char ch;
int aux,i;
numar a, b;
ifstream fin("ech.in");
CAPITOLUL 9. OJI 2015 9.2. LASERE - OJI 2015 137
ofstream fout("ech.out");
a.n=0;
while(fin>>ch)
{
if(ch>=’0’ && ch<=’9’)
{
a.n++;
a.v[a.n]=ch-48;
}
}
for(i=1;i<=a.n/2;i++)
{
aux=a.v[i];
a.v[i]=a.v[a.n+1-i];
a.v[a.n+1-i]=aux;
}
b=next(a);
for(i=b.n;i>=1;i--)
{
fout<<b.v[i];
}
fout<<’\n’;
fout.close();
fin.close();
return 0;
}
Cerinţe
Cunoscând configuraţia terenului şi amplasarea laserelor, să se rezolve una dintre următoarele
două cerinţe:
1. să se determine numărul de gropi din teren, după executarea tragerilor;
2. să se determine numărul de tranşee existente, după executarea tragerilor.
Date de intrare
Fişierul de intrare lasere.in conţine pe prima linie un număr natural c care reprezintă cerinţa ce
urmează să fie rezolvată (1 sau 2). Pe a doua linie se află două numere naturale n şi m, reprezentând
numărul de linii şi de coloane ale matricei, respectiv numărul de lasere. Pe următoarele n linii
se află câte n numere naturale, reprezentând elementele matricei. Pe următoarele m linii sunt
CAPITOLUL 9. OJI 2015 9.2. LASERE - OJI 2015 138
descrise cele m lasere, câte un laser pe o linie. Pe o linie care descrie un laser se află 3 numere
naturale i j d, cu semnificaţia că se află un laser pe linia i şi coloana j (1 & i, j & n), care trage
ı̂n direcţia d (1 & d & 4). Valorile situate pe aceeaşi linie sunt separate prin spaţiu.
Date de ieşire
Fişierul de ieşire lasere.out va conţine pe prima linie un singur număr natural. Acest număr
reprezintă numărul de gropi (dacă c 1) sau numărul de tranşee (dacă c 2).
Restricţii şi precizări
a 4 & n & 200
a 1 & m & 200
a Numerotarea liniilor şi a coloanelor este de la 1 la n.
a Elementele matricei din fişierul de intrare sunt numere naturale de maxim 4 cifre.
a Poziţiile laserelor sunt distincte.
a Pentru teste valorând 30% din punctaj cerinţa este 1.
Exemple
Autor: prof. Nicu Vad Laurentiu, Liceul Teoretic Mihail Kogalniceanu Vaslui
Varianta 1 -100p
ifstream fin("lasere.in");
ofstream fout("lasere.out");
int a[202][202];
int cerinta,i,j,m,n,x,y,z,d;
int transee(int l)
{
int k=0,p=1,q;
while(p<n)
{
q=1;
while((a[l][p]==a[l][p+q])&&groapa(l,p)&&groapa(l,p+q)) q++;
if(q>1) k++;
p=p+q;
}
return k;
}
int main()
{
fin>>cerinta;
fin>>n>>m;
int max=0;
CAPITOLUL 9. OJI 2015 9.2. LASERE - OJI 2015 140
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{fin>>a[i][j];if(a[i][j]>max) max=a[i][j];}
max++;
for(i=0;i<=n+1;i++){a[0][i]=max;a[n+1][i]=max;a[i][0]=max;a[i][n+1]=max;}
for(i=1;i<=m;i++)
{
fin>>x>>y>>d;
if(d==1) N(x,y);
else if(d==2) E(x,y);
else if(d==3) S(x,y);
else V(x,y);
}
fin.close();
int nrT=0,nrG=0;
if(cerinta==1)
{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(groapa(i,j))nrG++;
fout<<nrG<<’\n’;
}
else
{
for(i=1;i<=n;i++) nrT+=transee(i);
fout<<nrT<<’\n’;
}
fout.close();
return 0;
}
ifstream fin("lasere.in");
ofstream fout("lasere.out");
int T[NMAX][NMAX];
bool G[NMAX][NMAX]; //G[i][j]=true daca in pozitia i j exista o groapa
int n, m;
int gropi, transee;
int c;
int dl[]={0, -1, 0, 1, 0, -1,-1, 1, 1};
int dc[]={0, 0, 1, 0, -1, -1, 1, -1, 1};
int main()
{int i, j, lin, col, d;
fin>>c>>n>>m;
for (i=1; i<=n; i++)
for (j=1; j<=n; j++) fin>>T[i][j];
bordare();
for (i=1; i<=m; i++)
{
fin>>lin>>col>>d;
trage(lin,col,d);
}
CAPITOLUL 9. OJI 2015 9.2. LASERE - OJI 2015 141
gropi=cauta_gropi();
/*for (i=1; i<=n; i++)
{for (j=1; j<=n; j++) fout<<G[i][j]<<’ ’;
fout<<’\n’;}
*/
if (c==1)
fout<<gropi<<’\n’;
else
fout<<cauta_transee()<<’\n’;
fout.close();
return 0;
}
int cauta_gropi()
{int i, j, nr=0;
for (i=1; i<=n; i++)
for (j=1; j<=n; j++)
if (este_groapa(i, j))
{
nr++; G[i][j]=1;
}
return nr;
}
void bordare()
{int i;
for (i=0; i<=n+1; i++)
T[0][i]=T[i][0]=T[n+1][i]=T[i][n+1]=INF;
}
int cauta_transee()
{int i, j, nr=0, lg;
for (i=1; i<=n; i++)
for (j=1; j<=n+1; j++)
if (G[i][j])
if (!G[i][j-1]) //incepe o transee
lg=1;
else
lg++;
else
if (G[i][j-1]) //se termina o transee
if (lg>1) nr++;
return nr;
}
ifstream fin("lasere.in");
ofstream fout("lasere.out");
struct el
{
CAPITOLUL 9. OJI 2015 9.2. LASERE - OJI 2015 142
int v,g;
} a[202][202];
int dx[]={-1,-1,0,1,1,1,0,-1};
int dy[]={0,1,1,1,0,-1,-1,-1};
int n,m,i,j,k,nrg,nrt,c,l;
void bordare()
{
int i;
for(i=0;i<=n+1;i++)
a[i][0].v=a[i][n+1].v=10000;
for(i=0;i<=n+1;i++)
a[0][i].v=a[n+1][i].v=10000;
}
void citire()
{
int i,j,k,x,y,d;
fin>>c;
fin>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
fin>>a[i][j].v;
for(i=1;i<=m;i++)
{
fin>>x>>y>>d;
if(d==1)
for(j=x-1;j>=1;j--)
a[j][y].v--;
if(d==2)
for(j=y+1;j<=n;j++)
a[x][j].v--;
if(d==3)
for(j=x+1;j<=n;j++)
a[j][y].v--;
if(d==4)
for(j=y-1;j>=1;j--)
a[x][j].v--;
}
}
int main()
{
citire();
bordare();
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(groapa(i,j)==1)
{
nrg++;
a[i][j].g=1;
}
if(c==1)fout<<nrg<<’\n’;
else
{
for(i=1;i<=n;i++)
{
l=0;
for(j=1;j<=n;j++)
if(a[i][j].g==1)l++;
else
{
if(l>=2)nrt++;
l=0;
}
if(l>=2)nrt++;
CAPITOLUL 9. OJI 2015 9.2. LASERE - OJI 2015 143
}
fout<<nrt<<’\n’;
}
return 0;
}
#define N 204
#define INF 10000
#define M 10000
ifstream cin("lasere.in");
ofstream cout("lasere.out");
struct laser
{
int x,y,dir;
} X[N];
int main()
{
cin>>cer;
cin>>n>>m;
for(i=1; i<=n; i++)
for(j=1; j<=n; j++) cin>>A[i][j];
for(i=0;i<=n+1;i++) A[0][i]=A[i][0]=A[i][n+1]=A[n+1][i]=INF;
}
p1=0;
for(s=1;s<n;)
if(B[s]==1)
{
p1=s;
while(B[s]) s++;
if(s-p1>=2)tr++;
}
else s++;
for(s=1;s<=n;s++){ B[s]=0;}
}
if(cer==1)cout<<nr<<"\n";
else cout<<tr<<"\n";
/* for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++) cout<<A[i][j]<<" ";
cout<<"\n";
}*/
CAPITOLUL 9. OJI 2015 9.2. LASERE - OJI 2015 144
ifstream f("lasere.in");
ofstream g("lasere.out");
int main()
{
f>>c;
f>>n>>m;
int i, j, x, y, d, nr=0,p;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
f>>a[i][j];
for(i=0;i<=n+1;i++)
a[0][i]=a[n+1][i]=a[i][0]=a[i][n+1]=vmax;
for(p=1;p<=m;p++)
{
f>>x>>y>>d;
trage(x,y,d);
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(groapa(i,j))
gr[i][j]=1, nr++;
int tr=0;
for(i=1;i<=n;i++)
{
j=1;
while(j<=n)
{
while(j<=n and gr[i][j]==0)j++;
x=0;
while(j<=n and gr[i][j]==1)j++, x++;
if(x>1)tr++;
}
CAPITOLUL 9. OJI 2015 9.2. LASERE - OJI 2015 145
if(c==1)
g<<nr<<’\n’;
else
g<<tr<<’\n’;
return 0;
}
ifstream fin("lasere.in");
ofstream fout("lasere.out");
int n,m,nrg,nrt,i,j,k,c,caz,li,co,dir;
int main()
{
fin>>caz>>n>>m;
for(i=0;i<=n+1;i++)
{
a[i][0]=10000;
a[0][i]=10000;
a[n+1][i]=10000;
a[i][n+1]=10000;
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
fin>>a[i][j];
}
}
for(i=1;i<=m;i++)
{
fin>>li>>co>>dir;
switch(dir)
{
case 1 :
{
for(j=li-1;j>=1;j--)
{
a[j][co]--;
}
break;
}
case 3 :
{
for(j=li+1;j<=n;j++)
{
a[j][co]--;
}
break;
}
case 4 :
{
for(j=co-1;j>=1;j--)
{
a[li][j]--;
}
break;
}
case 2 :
CAPITOLUL 9. OJI 2015 9.2. LASERE - OJI 2015 146
{
for(j=co+1;j<=n;j++)
{
a[li][j]--;
}
break;
}
}
}
nrg=0;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
c=0;
for(k=0;k<=7;k++)
{
li=i+dl[k];
co=j+dc[k];
if(a[li][co]<a[i][j])
{
c++;
break;
}
}
if(c==0)
{
nrg++;
b[i][j]=1;
}
else
{
b[i][j]=0;
}
}
}
nrt=0;
for(i=1;i<=n;i++)
{
for(j=0;j<=n-2;j++)
{
if(b[i][j]==0 && b[i][j+1]==1 && b[i][j+2]==1)
{
nrt++;
}
}
}
if(caz==1)
fout<<nrg;
else
fout<<nrt;
fout.close();
fin.close();
return 0;
}
OJI 2014
Cerinţe
Date de intrare
Din fişierul patrat.in se citesc de pe prima linie, două numere naturale N şi M , separate
printr-un spaţiu, reprezentând dimensiunile tabloului bidimensional, iar de pe următoarele N
linii, câte M numere naturale separate prin câte un spaţiu, reprezentând intensitatea luminoasă
a stelelor.
Date de ieşire
În fişierul patrat.out se va scrie pe prima linie un număr natural reprezentând răspunsul la
cerinţa a). Pe cea de-a doua linie se va scrie un număr natural reprezentând răspunsul la cerinţa
b). Pe a treia linie se va scrie un număr natural reprezentând răspunsul la cerinţa c).
a 1 $ N & 200
a 1 $ M & 200
a 1 & intensitatea unei stele & 1000
a pentru rezolvarea corectă a cerinţei a) se acordă 40% din punctajul fiecărui test, pentru
rezolvarea corectă a cerinţei b) se acordă 40% din punctajul fiecărui test iar pentru rezolvarea
corectă a cerinţei c) se acordă 20% din punctajul fiecărui test.
a Respectaţi formatul fişierului de ieşire! Pentru a obţine punctajul acordat unei cerinţe,
trebuie ca răspunsul din fişier să fie corect şi scris exact pe linia precizată ı̂n enunţ.
147
CAPITOLUL 10. OJI 2014 10.1. PĂTRAT - OJI 2014 148
Exemple
patrat.in patrat.out Explicaţii
68 11 În tabloul bidimensional cu 6 linii şi 8 coloane există 11 stele
1 85 71 6 3 strălucitoare. Tabloul conţine 3 constelaţii pătrate iar cea mai
3 4 5 mare are latura pătratului de lungime 5.
12311521
1 71 911
81
63516431
1 95 71 8
21
1565313
6
23 0 În tabloul bidimensional cu 2 linii şi 3 coloane nu există nicio
111 0 stea strălucitoare. Tabloul conţine 0 constelaţii pătrate iar cea
111 0 mai mare are latura pătratului este de dimensiune 0.
Definesc un tip structurat stea cu doua campuri pentru a retine atat intesitatea
luminoasa cat si pentru a memora faptul ca o stea este stralucitoare sau nu.
Definesc o matrice de tipul structurat stea in care se citesc datele de intrare.
Parcurg matricea si pentru fiecare element verific daca valoarea lui este mai
mica decat valorile continute in cele 8 elemente vecine. In cazul in care
conditia este indeplinita, am gasit o stea stralucitoare si o contorizez.
i-1,j-1 i-1,j i-1,j+1
i,j-1 i,j i,j+1
i+1,j-1 i+1,j i+1,j
Daca exista, notam cu k distanta dintre cele doua stele si verific daca la
distante egale cu k de cele doua stele (dar aceasta distanta nu trebuie sa
depaseasca marginea tabloului), se gasesc alte doua stele stralucitoare,
de-a lungul coloanelor pe care se afla stelele A si B, fie acestea C si D.
Retin latura patratului determinat daca aceasta este cea mai mare pana in
acest moment.
int A[MAXN][MAXN];
bool B[MAXN][MAXN], ok;
int main()
{
freopen("patrat.in","r",stdin);
freopen("patrat.out","w",stdout);
printf("%d\n", nrst);
for(i=1; i<=N; i++)
for(j=1; j<=M; j++)
if(B[i][j])
{
L=min(N - i + 1, M - j + 1);
for(d=L; d>1 ; d--)
if(B[i][j + d - 1] &&
B[i + d - 1][j] &&
B[i + d - 1][j + d - 1])
{
nrct++;
Lmax=(Lmax<d?d:Lmax);
}
}
ifstream f("patrat.in");
ofstream g("patrat.out");
int a[203][203],n,m,sf;
struct stea
{
int x,y;
} v[4000];
int parcurg()
{int i,j,nr=0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(vecini(i,j)!=0)
{
nr++;++sf;
v[sf].x=i;v[sf].y=j;
}
return nr;
}
while(poz1+3<=sf)
{
poz2=sf;
while(poz2-3>=poz1)
{
lg=v[poz2].x-v[poz1].x;
if(v[poz2].y-v[poz1].y==lg)
{
k=poz1+1;
ok=0;
while (v[k].x==v[poz1].x)
{if(v[k].y==v[poz1].y+lg) ok=1; k++;}
if(ok)
{
k=poz2-1;ok1=0;
while(v[k].x==v[poz2].x)
{if(v[k].y+lg==v[poz2].y)
ok1=1;k--;
}
if(ok1)
{
nr++;
if(max<lg)
max=lg;
}
}
}
poz2--;
}
poz1++;
}
}
int main()
CAPITOLUL 10. OJI 2014 10.1. PĂTRAT - OJI 2014 151
{ int i,j,nr=0,p=0,max=0;
f>>n>>m;
//for(k=1;k<n/3;k++)
//{
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
f>>a[i][j];
nr=nr+parcurg();
g<<nr<<’\n’;
constelatie(p,max);
g<<p<<’\n’<<max+1<<’\n’;
f.close();
g.close();
return 0;
}
int a[DIM][DIM];
int n, m, i, j, k, maxim, stele, patrate, ok, d, iv, jv, t;
int main()
{
ifstream fin("patrat.in");
ofstream fout("patrat.out");
fin>>n>>m;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
fin>>a[i][j];
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
{
ok = 1;
for (d=0;d<=7;d++)
{
iv = i + di[d];
jv = j + dj[d];
if (a[iv][jv] >= a[i][j])
ok = 0;
}
stele+=ok;
if (ok == 1)
{
a[i][j] = INF;
//cout<<i<<" "<<j<<"\n";
}
}
for (i=1;i<n;i++)
for (j=i+1;j<=n;j++)
{
t = j-i;
for (k=1; k+t<=m; k++)
if (a[i][k] == INF &&
a[i][k+t] == INF &&
a[j][k] == INF &&
a[j][k+t] == INF)
{
patrate++;
if (t > maxim)
CAPITOLUL 10. OJI 2014 10.1. PĂTRAT - OJI 2014 152
maxim = t;
}
}
fout<<stele<<"\n"<<patrate<<"\n"<<maxim+1;
return 0;
}
ifstream f("patrat.in");
ofstream g("patrat.out");
struct stea{
int x;
char s;
};
int m,n,nrs,nrc,v[]={-1,-1,0,1,1,1,0,-1},w[]={0,1,1,1,0,-1,-1,-1};
stea t[202][202];
int main()
{
int k,sw,maxim=0; //maxim-retine latura celei mai mari constelatii
int i,j;
f>>m>>n;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
f>>t[i][j].x;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
sw=1;
for(k=0;k<8;k++) // verific cei 8 vecini
if(t[i][j].x<=t[i+v[k]][j+w[k]].x)
{
sw=0;
k=8;
}
if(sw)
{
nrs++; // numar stelele stralucitoare
t[i][j].s=1; // memorez steaua stralucitoare
}
}
g<<nrs<<’\n’;
for(i=1;i<=m;i++) // parcurg liniile
for(j=1;j<=n;j++) // parcurg coloanele
if(t[i][j].s==1)
{ // daca gasesc o stea stralucitoare
for(k=1;k<=n-j;k++)//caut urmatoarea stea stalucitoare
if(t[i][j+k].s==1) //daca o gasesc
if(i+k<=m && t[i+k][j].s==1 && t[i+k][j+k].s==1)
{
// verific daca exista stele stralucitoare
// in celelalte doua colturi
nrc++;
if(k+1>maxim)
CAPITOLUL 10. OJI 2014 10.1. PĂTRAT - OJI 2014 153
maxim=k+1;//retin maximum
}
}
g<<nrc<<’\n’<<maxim;
f.close();
g.close();
return 0;
}
ifstream f("patrat.in");
ofstream g("patrat.out");
int a[210][210],m,n,ss=0,cp=0,lmax=1;
int dx[]={0,-1,-1,-1,0,1,1,1};
int dy[]={1,1,0,-1,-1,-1,0,1};
void citire()
{
int i,j;
f>>m>>n;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
f>>a[i][j];
void afisare()
{
int i,j;
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
g<<a[i][j]<<’ ’;
g<<endl;
}
}
void stralucire()
{
int i,j,p,k;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
p=0;
for(k=0;k<8;k++)
p=p+(a[i][j] > a[i+dx[k]][j+dy[k]]);
if(p==8)
a[i][j]=valmax,ss++;
}
}
void constelatie()
{
int i,j,k;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
if(a[i][j]==valmax)
{
for(k=1;k<=n-j&&k<=m-i;k++)
if((a[i][j+k]==valmax)&&
(a[i+k][j]==valmax)&&
(a[i+k][j+k]==valmax))
{
CAPITOLUL 10. OJI 2014 10.2. SCHI - OJI 2014 154
cp++;
if(k+1>lmax)
lmax=k+1;
}
}
}
int main()
{
citire();
stralucire();
// afisare();
constelatie();
g<<ss<<’\n’;
g<<cp<<’\n’;
g<<lmax<<’\n’;
return 0;
}
Cerinţe
Scrieţi un program care determină răspunsul pentru fiecare dintre cele K ı̂ntrebări puse de
şeful comisiei de arbitri.
Date de intrare
În fişierul schi.in, pe prima linie este scris un număr natural, N reprezentând numărul de
concurenţi. Pe a doua linie a fişierului sunt scrise cele N numere naturale separate prin câte un
spaţiu, reprezentând punctajele obţinute de fiecare dintre cei N concurenţi, ı̂n ordinea ı̂n care
aceştia au evoluat. Pe a treia linie a fişierului este scris numărul natural K ce reprezintă numărul
de ı̂ntrebări puse de şef. Pe a patra linie a fişierului sunt scrise K numere naturale separate prin
câte un spaţiu, reprezentând valorile X ale punctajelor alese de şeful comisiei de arbitri.
Date de ieşire
În fişierul schi.out se vor scrie K numere, separate prin câte un spaţiu, reprezentând, ı̂n
ordine, răspunsurile la cele K ı̂ntrebări.
Exemple
-Pentru punctaj maxim, trebuie sa determinam atat prima cat si ultima pozitie
din P unde se gaseste valoarea X folosind algoritmul de cautarea binara.
Exista mai multe abordari prin care se pot obtine punctaje partiale:
int v[DIM];
int n, i, T, st, dr, x, q, maxim;
CAPITOLUL 10. OJI 2014 10.2. SCHI - OJI 2014 156
int main()
{
ifstream fin("schi.in");
ofstream fout("schi.out");
fin>>n;
maxim = -1;
for (i=1;i<=n;i++)
{
fin>>x;
if (x > maxim)
maxim = x;
v[i] = maxim;
}
fin>>q;
for (i=1;i<=q;i++)
{
fin>>x;
st = cautMinim(x);
if (st == -1)
fout<<"0 ";
else
{
dr = cautMaxim(x);
fout<<dr-st+1<<" ";
}
}
return 0;
}
int cautMinim(int x)
{
int p = 1, u = n, mid;
while (p<=u)
{
mid = (p+u)/2;
if (x<=v[mid])
{
u = mid-1;
}
else
{
p = mid+1;
}
}
if (v[p] == x)
return p;
else
return -1;
}
int cautMaxim(int x)
{
int p = 1, u = n, mid;
while (p<=u)
{
mid = (p+u)/2;
if (x>=v[mid])
{
p = mid+1;
}
else
{
u = mid-1;
}
CAPITOLUL 10. OJI 2014 10.2. SCHI - OJI 2014 157
if (v[u] == x)
return u;
else
return -1;
}
#include <cstring>
int N, M, K, c, i, j, v, Q, x, p;
int A[MAXN];
punct C[MAXN];
int cb(int x)
{
int st, dr, m, poz;
st=1; dr=v; poz=0;
while (st<=dr && poz==0)
{
m=(st+dr)/2;
if(C[m].p==x)
poz=m;
else
if (C[m].p>x) dr=m-1; else st=m+1;
}
return poz;
}
int main()
{
freopen("schi.in","r",stdin);
freopen("schi.out","w",stdout);
scanf("%d\n",&N);
assert(N>=1 && N<=100000);
C[0].p=-1; v=0;
for(i=1; i<=N; i++)
{
scanf("%d",&A[i]);
assert(A[i]>=0 && A[i]<=1000000000);
if(C[v].p>=A[i])
C[v].t++;
else
{
C[++v].p=A[i]; C[v].t=1;
}
}
scanf("%d\n",&Q);
assert(Q>=1 && Q<=100000 );
printf("\n");
return 0;
}
ifstream f("schi.in");
ofstream g("schi.out");
struct
{
int x,y;
} v[100003];
int p;
int main()
{
int n,i,a,j=1,b,m;
f>>n>>a;
v[1].x=a;
v[1].y=1;
for(i=2;i<=n;i++)
{
f>>a;
if(a<=v[j].x)
v[j].y++;
else
v[++j].x=a;
}
p=j;
f>>m;
for(i=1;i<=m;i++)
{
f>>a;
b=caut(a);
if(b==0)
g<<0<<’ ’;
else
{
if(a==v[1].x)
g<<v[b].y<<’ ’;
else
g<<v[b].y+1<<’ ’;
}
g<<’\n’;
f.close();
g.close();
return 0;
}
CAPITOLUL 10. OJI 2014 10.2. SCHI - OJI 2014 159
int v[DIM];
int n, q, i, x, maxim, nr, j;
int main()
{
ifstream fin("schi.in");
ofstream fout("schi.out");
fin>>n;
maxim = -1;
for (i=1;i<=n;i++)
{
fin>>x;
if (x > maxim)
maxim = x;
v[i] = maxim;
}
fin>>q;
for (i=1;i<=q;i++)
{
fin>>x;
nr = 0;
for (j=1;j<=n;j++)
{
if (v[j] > x)
break;
if (x == v[j])
{
nr++;
}
}
fout<<nr<<" ";
}
return 0;
}
int v[DIM];
int n, i, T, st, dr, x, q, maxim, mid;
int main()
{
ifstream fin("schi.in");
ofstream fout("schi.out");
fin>>n;
maxim = -1;
for (i=1;i<=n;i++)
{
fin>>x;
if (x > maxim)
maxim = x;
v[i] = maxim;
}
CAPITOLUL 10. OJI 2014 10.2. SCHI - OJI 2014 160
fin>>q;
for (i=1;i<=q;i++)
{
fin>>x;
mid = caut(x);
if (mid == -1)
fout<<"0 ";
else
{
st = mid;
while (v[st] == x)
st--;
st++;
dr = mid;
while (v[dr] == x)
dr++;
dr--;
fout<<dr-st+1<<" ";
}
}
return 0;
}
int caut(int x)
{
int p = 1, u = n, mid;
while (p<=u)
{
mid = (p+u)/2;
if (x==v[mid])
{
break;
}
else
{
if (x < v[mid])
u = mid-1;
else
p = mid+1;
}
}
if (p<=u)
return mid;
else
return -1;
}
struct qry
{
int v;
int p;
int r;
};
struct punctaj
{
int v;
int nr;
};
qry w[DIM];
int v[DIM];
punctaj s[DIM];
int n, i, x, k, L, maxim, q, j;
int main()
{
ifstream fin("schi.in");
ofstream fout("schi.out");
fin>>n;
v[0] = -1;
for (i=1;i<=n;i++)
{
fin>>x;
if (x > maxim)
maxim = x;
v[i] = maxim;
if (v[i] == v[i-1])
L++;
else
L=1;
}
s[++k].v = v[n];
s[k].nr = L;
fin>>q;
for (i=1;i<=q;i++)
{
fin>>x;
w[i].v = x;
w[i].p = i;
}
sort(w+1,w+q+1,cmpv);
i = 1;
j = 1;
for (i=1;i<=q;i++)
fout<<w[i].r<<" ";
CAPITOLUL 10. OJI 2014 10.2. SCHI - OJI 2014 162
return 0;
}
OJI 2013
Exemple
compar.in compar.out Explicaţii
¿¿¿¡¡ 6 6¿4¿2¿1¡3¡5
642135 Există şi alte soluţii posibile, aceasta este doar una dintre ele.
163
CAPITOLUL 11. OJI 2013 11.1. COMPAR - OJI 2013 164
Parcurgem secventa de semne si daca semnul curent este < atunci scriu
valoarea curenta, apoi o incrementez.
Daca insa semnul curent este > identific intreaga subsecventa care urmeaza
formata numai din semnul >; sa consideram ca lg este lungimea secventei;
vom plasa valorile de la crt pana la crt+lg in ordine descrescatoare in
secventa reconstituita.
Obtinem intotdeauna cea mai mica solutie din punct de vedere lexicografic.
Se parcurge sirul.
char s[100000];
int main()
{
ifstream fin("compar.in");
ofstream fout("compar.out");
fin>>s;
int N;
N=strlen(s)+1;
fout<<N<<"\n";
for(int i=0;i<N;i++)
if(s[i]==’<’)
fout<<minn<<" ",minn++;
else
CAPITOLUL 11. OJI 2013 11.2. UNIFIC - OJI 2013 165
fout<<maxx<<" ",maxx--;
fout.close();
return 0;
}
ifstream f("compar.in");
ofstream g("compar.out");
int i,N,Max,Min,j,k;
char s[lmax];
int main()
{
f.getline(s,lmax);
N=strlen(s);
g<<N+1<<"\n";
Max=N+1;
Min=1;
i=0;
while(i<N)
{
if (s[i]==’<’)
{
g<<Min<<" ";
++Min; ++i;
}
else
{
j=i;
while (s[j]==’>’ && j<N) ++j;
for (k=i;k<j;++k)
{
g<<Max<<" ";
--Max;
}
i=j;
}
}
if (s[N-1]==’<’)
g<<Min<<"\n";
else
g<<Max<<"\n";
return 0;
}
Dacă două elemente vecine Ai , Ai1 (1 & i $ N ) au cel puţin o cifră comună, ele se pot unifica.
Procedeul de unificare constă ı̂n eliminarea din numerele Ai şi Ai1 a tuturor cifrelor comune
şi adăugarea prin alipire a numărului obţinut din Ai1 la numărul obţinut din Ai , formându-se
astfel un nou număr. Numărul Ai va fi ı̂nlocuit cu noul număr, iar numărul Ai1 va fi eliminat din
şir. (De exemplu, numerele Ai 23814 şi Ai1 40273 au cifrele 2, 3, 4 comune, după unificare
obţinem Ai 817, iar Ai1 este eliminat; observaţi că dacă după eliminarea cifrelor comune,
numerele ı̂ncep cu zerouri nesemnificative, acestea vor fi eliminate, apoi se realizează alipirea).
Dacă ı̂n urma eliminării cifrelor comune, unul dintre numere nu mai are cifre, atunci numărul
rezultat va avea cifrele rămase ı̂n celălalt. Dacă ı̂n urma eliminării cifrelor comune atât Ai cât şi
Ai1 nu mai au cifre, atunci ambele numere vor fi eliminate din şir, fără a fi ı̂nlocuite cu o altă
valoare.
Ordinea ı̂n care se fac unificările ı̂n şir este importantă: la fiecare pas se alege prima pereche de
elemente vecine Ai Ai1 care poate fi unificată, considerând şirul parcurs de la stânga la dreapta.
(De exemplu, considerând Ai 123, Ai1 234, Ai2 235, se unifică Ai cu Ai1 % Ai 14,
iar unificarea cu următorul număr nu mai este posibilă).
Cerinţe
Date de intrare
Fişierul de intrare unific.in conţine pe prima linie o valoare naturală N , iar pe următoarele
N linii, ı̂n ordine, cele N numere naturale din şirul A, câte un număr pe o linie.
Date de ieşire
Fişierul de ieşire unific.out va conţine pe prima linie un număr natural c reprezentând cifra
care apare cel mai frecvent ı̂n scrierea celor N numere naturale. Pe cea de a doua linie un număr
natural N r reprezentând numărul de numere naturale rămase ı̂n şir după efectuarea unui număr
maxim de unificări. Pe cea de a treia linie se vor scrie cele N r numere naturale rămase, ı̂n ordinea
din şir, separate prin câte un spaţiu.
Dacă ı̂n urma procedeului de unificare, toate numerele vor fi eliminate, fişierul de ieşire va
conţine o singură linie, pe care se va scrie cifra care apare cel mai frecvent ı̂n scrierea celor N
numere naturale.
Exemple
Solutia propusa analizeaza secvential numerele inca din citirea din fisier.
a)
Pentru realizarea primei cerinta se construieste vectorul caracteristic al
cifrelor care apar in scrierea celor N numere naturale din sir.
b)
Trebuie avut in vedere ca prin unificarea lui A[i] cu A[i+1], numarul nou
obtinut in A[i] poate genera la randul lui posibile unificari cu numerele
anterior determinate A[i-1],A[i-2], ...
Citeste a[1]
i = 1,
Cat timp Not Eof() Executa
Citeste xa - valoarea curenta
Daca comun(a[i], xa)
Atunci
a[i] = unifica (a[i],xa);
ifstream fin("unific.in");
ofstream fout("unific.out");
int n;
long long int a[NMAX], rez, vmax;
int nrc[10];
int cmax;
int c[10];//cifrele comune perechii curente
int main()
{int i, ok, nr, maxim, cmax,ii;
for (i=vmax=1; i<=18; i++) vmax=vmax*10;
fin>>n;
assert(1<=n && n<=100000);
fin>>a[0]; nr=1;
numara_cifre(a[0]);
assert(a[0]<=vmax);
int v[20];
int concat(long long int x, long long int y, long long int &rez)
//returneaza 0 daca dupa unificare rezultattul nu mai are cifre;
{
int lgrez=0, lg, i;
rez=0;
do {if (!c[x%10]) v[lgrez++]=x%10; x/=10;} while (x);
CAPITOLUL 11. OJI 2013 11.2. UNIFIC - OJI 2013 169
int N, k, i, c;
long long a[100001], xa, x;
int ap[10];
if (x == 0)
uz[0] = 1;
else
while (x > 0)
{
uz[x % 10] = 1;
x /= 10;
}
if (y == 0 && uz[0] == 1)
return 1;
while(y > 0)
{
c = y % 10; y /= 10;
if (uz[c]) return 1;
}
return 0;
}
//unific (y alipit la x)
inline long long unific (long long y, long long x)
{
short c, i = 0, uz[10], uc;
long long z, p;
CAPITOLUL 11. OJI 2013 11.2. UNIFIC - OJI 2013 170
z = y;
if (z == 0)
uz[0] = 1;
else
while (z > 0)
{
uz[z % 10] = 1;
z /= 10;
}
z = x;
if (z == 0 && uz[0])
uz[0] = 2;
else
{
p = 1; x = 0;
while (z > 0)
{
c = z % 10;
if (uz[c] == 0)
{
x = x + c * p;
p *= 10;
}
else uz[c] = 2;
z /= 10;
}
}
if (y > 0)
{
z = y; p = 1; y = 0;
while (z > 0)
{
c = z % 10;
if (uz[c] == 1)
{
y = y + c * p;
p *= 10; ++i; uc = c;
}
z /= 10;
}
}
if (x * y > 0)
{
if (uc == 0) p /= 10;
return x * p + y;
}
else
{
if (x > 0)
{
if (i > 0) x *= 10;
return x;
}
else
{
if (i == 0) y = -1;
return y;
}
}
}
int main()
{
FILE * f = fopen("unific.in", "r");
FILE * g = fopen("unific.out", "w");
i = 1;
fscanf(f, "%lld", &a[k]); aparitii(a[k]);
while (i < N)
{
//citim valoarea curenta
fscanf(f, "%lld", &a[++k]); aparitii(a[k]);
++i;
c = 0;
for (i = 1; i<=9; ++i)
if (ap[i] > ap[c]) c = i;
return 0;
}
OJI 2012
Cerinţe
Scrieţi un program care să determine suma maximă a puterilor armelor pe care le va avea la
brâu Vasile după efectuarea ı̂nlocuirilor.
Date de intrare
Date de ieşire
Fişierul de ieşire arme.out va conţine o singură linie pe care va fi scrisă suma maximă a
puterilor armelor de la brâul lui Vasile, după efectuarea ı̂nlocuirilor.
Exemple
arme.in arme.out
32 16
317
45
172
CAPITOLUL 12. OJI 2012 12.1. ARME - OJI 2012 173
//Pintea Adrian
#include <iostream>
#include <fstream>
ifstream fin("arme.in");
ofstream fout("arme.out");
int n,m,i,j,p[2001],aux,rezultat;
int main()
{
fin>>n>>m;
for(i=0;i<n;i++)
fin>>p[i];
for(i=n;i<n+m;i++)
fin>>p[i];
rezultat=0;
for(i=0;i<n;i++)
{
for(j=i+1;j<n+m;j++)
{
if (p[i]<p[j])
{
aux=p[i];
p[i]=p[j];
p[j]=aux;
}
}
rezultat+=p[i];
}
fout<<rezultat<<"\n";
fout.close();
return 0;
}
char T[10][10];
char s[100];
void citire();
void afisare();
void sortare(arma[], short int);
long int suma();
int main()
{
citire();
sortare(b,N);
sortare(c,M);
smax=suma();
afisare();
return 0;
}
void citire()
CAPITOLUL 12. OJI 2012 12.1. ARME - OJI 2012 175
{
int i;
ifstream fin(InFile);
fin>>N>>M;
for (i=1; i<=N; i++)
{fin>>b[i].p; b[i].nr=i;}
for (i=1; i<=M; i++)
{fin>>c[i].p; c[i].nr=i;}
}
void afisare()
{
int i;
ofstream fout(OutFile);
fout<<smax<<’\n’;
/*
fout<<cate<<’\n’;
for (i=0; i<cate; i++)
fout<<mut[i].nr<<’ ’<<mut[i].p<<’\n’;
*/
fout.close();
}
int a[1001],b[1001],m,n,i,j,s;
int main()
{
freopen("arme.in","r",stdin);
freopen("arme.out","w",stdout);
cin>>n>>m;
for(i=1;i<=n;i++)
{
cin>>a[i];
s=s+a[i];
}
for(i=1;i<=m;i++)
cin>>b[i];
qsort(a+1,n,sizeof(a[0]),cmp1);//a crescator
qsort(b+1,m,sizeof(b[0]),cmp2);//b descrescator
//afis(a,n);afis(b,m);
int k=n;
if(m<n)
k=m;
i=1;
while(i<=k && a[i]<b[i])
{
s=s+(b[i]-a[i]);
i++;
}
cout<<s;
return 0;
}
Date de intrare
Fişierul de intrare triunghi.in conţine pe prima linie numărul natural n reprezentând numărul
de linii din triunghi. Pe următoarele n linii sunt descrise informaţiile despre triunghi. Mai exact,
pe linia i (1 & i & n) dintre cele n se află două numere naturale separate prin spaţiu pi vi indicând
poziţia şi respectiv valoarea numărului cunoscut de pe linia i a triunghiului.
Date de ieşire
Fişierul de ieşire triunghi.out va conţine o singură linie, pe care se găsesc n numere naturale
separate prin câte un spaţiu, reprezentând ı̂n ordinea de la stânga la dreapta numerele scrise pe
linia 1 a triunghiului.
Exemple
Apoi, cunoscand linia n-1 si unul dintre numerele de pe linia n-2 le putem afla
pe celelalte doua, tot prin scaderi etc.
Trebuie sa fim doar atenti cum facem scaderile: daca cunoastem numerele de pe
linia i: vi, 1, vi, 2,..., vi, n+1-i si de pe linia i+1 cunoastem valoarea
V=v[i+1,p], de pe pozitia p, calculam numerele de pe pozitiile p+1, p+2, ..
succesiv: vi+1, p+1=v[i,p]-v[i+1,p], vi+1, p+2=v[i,p+1]-vi+1, p+1 etc., iar
numerele de pe pozitiile anterioare p-1, p-2, ...1
la fel: vi+1,p-1=vi,p-1-vi,p, etc.
ifstream fin("triunghi.in");
ofstream fout("triunghi.out");
int citire()
{
fin >> n;
for (i=n;i>0;i--) { fin>>p[i]>>x; a[i][p[i]]=x;}
fin.close();
return 0;
}
int afisare()
{
for (j = 1; j <= n; j++)
fout << a[n][j] << ’ ’;
return 0;
}
int main()
{
citire();
CAPITOLUL 12. OJI 2012 12.2. TRIUNGHI - OJI 2012 179
construire();
afisare();
fout.close();
return 0;
}
ifstream fin("triunghi.in");
ofstream fout("triunghi.out");
int N, p[DIM];
unsigned long long L1[DIM], L2[DIM], v[DIM];
void citire()
{
int i;
fin >> N;
for (i = N; i >0; i--) //le citesc invers ca sa lucrez
fin >> p[i] >> v[i]; //"mai usor" la reconstruire
fin.close();
}
void refa()
{
int i, j;
for (i = 2; i <= N; i++) //refa linia i (de sus in jos)
{
L2[p[i]] = v[i]; //pun in L2 valoarea cunoscuta
if (p[i] > p[i - 1]) //detectez sensul recalcularii
{
for (j = p[i] - 1; j > 0 ; j--) //intai spre stanga
L2[j] = L1[j] - L2[j + 1];
for (j = p[i] + 1; j <= i; j++) //apoi spre freapta
L2[j] = L1[j - 1] - L2[j - 1];
}
else
{
for (j = p[i] + 1; j <= i; j++) //intai spre dreapta
L2[j] = L1[j - 1] - L2[j - 1];
for (j = p[i] - 1; j > 0; j--) //apoi spre stanga
L2[j] = L1[j] - L2[j + 1];
}
for (j = 1; j <= i; j++) //copiez L2 in L1
L1[j] = L2[j]; //adica L2 devine L1
for (j = 1; j <= i; j++) //"curat" L2
L2[j] = 0; //nu era neaparat necesar
}
}
void afisare()
{
int i;
for (i = 1; i < N; i++) //afisez primele N-1 valori
fout << L1[i] << ’ ’; //urmate de un spatiu
fout << L1[N] << ’\n’; //apoi ultima valoare urmata de ENTER
}
int main()
{
citire();
L1[1] = v[p[1]];
refa();
afisare();
fout.close();
return 0;
}
CAPITOLUL 12. OJI 2012 12.2. TRIUNGHI - OJI 2012 180
ifstream f("triunghi.in");
ofstream g("triunghi.out");
int main()
{
f>>n;
for (i=n;i>0;--i)
{
f>>p[i]>>v[i];
}
a[1][1]=v[1];
for (i=2;i<=n;++i)
{
//refac linia i
j=p[i];
a[i][j]=v[i];
//refac stanga
k=j-1;
while (k)
{
a[i][k]=a[i-1][k]-a[i][k+1];
--k;
}
//refac dreapta
k=j+1;
while (k<=i)
{
a[i][k]=a[i-1][k-1]-a[i][k-1];
++k;
}
}
// for (i=1;i<=n;++i)
// {
for (j=1;j<=n;++j)
g<<a[n][j]<<’ ’;
// g<<’\n’;
// }
return 0;
}
ifstream f("triunghi.in");
ofstream g("triunghi.out");
int main()
{
f>>n;
for (i=n; i>0; --i)
{
f>>p[i]>>v[i];
}
a[1][1]=v[1];
for (i=2; i<=n; ++i)
{
//refac linia i
j=p[i];
a[i][j]=(long long)v[i];
CAPITOLUL 12. OJI 2012 12.2. TRIUNGHI - OJI 2012 181
//refac stanga
k=j-1;
while (k)
{
a[i][k]=a[i-1][k]-a[i][k+1];
--k;
}
//refac dreapta
k=j+1;
while (k<=i)
{
a[i][k]=a[i-1][k-1]-a[i][k-1];
++k;
}
}
return 0;
}
ifstream f("triunghi.in");
ofstream g("triunghi.out");
int main()
{
f>>n;
for (i=n; i>0; --i)
{
f>>p[i]>>v[i];
}
L[0][1]=v[1];
for (i=2; i<=n; ++i)
{
//refac linia i
j=p[i];
L[1][j]=(long long)v[i];
//refac stanga
k=j-1;
while (k)
{
L[1][k]=L[0][k]-L[1][k+1];
--k;
}
//refac dreapta
k=j+1;
while (k<=i)
{
L[1][k]=L[0][k-1]-L[1][k-1];
++k;
}
//copiez linia
for (j=1; j<=i; ++j)
L[0][j]=L[1][j];
}
return 0;
}
void citire()
{cin>>n;
for(i=n;i>=1;i--)
{cin>>p>>v;
x[i]=p;
// y[i]=v;
a[i][p]=v;
}
}
void sol()
{for(i=1;i<=n;i++)
{ p=x[i];//a[i][p]are valoare
for(j=p+1;j<=i;j++) // completez la dreapta
a[i][j]=a[i-1][j-1]-a[i][j-1];
for(j=p-1;j>=1;j--)
a[i][j]=a[i-1][j]-a[i][j+1];
}
}
void afis()
{
unsigned int i;
for(i=1;i<=n;i++)
cout<<a[n][i]<<" ";
}
int main()
{freopen("triunghi.in","r",stdin);
freopen("triunghi.out","w",stdout);
citire();
sol();
afis();
return 0;
}
void citire()
{cin>>n;
for(i=n;i>=1;i--)
{cin>>p>>v;
x[i]=p;
y[i]=v;
}
}
void sol()
{ s1[x[1]]=y[1];
for(i=2;i<=n;i++)
{ p=x[i];
v=y[i];
CAPITOLUL 12. OJI 2012 12.2. TRIUNGHI - OJI 2012 183
s2[p]=v;
for(j=p+1;j<=i;j++)
s2[j]=s1[j-1]-s2[j-1];
for(j=p-1;j>=1;j--)
s2[j]=s1[j]-s2[j+1];
for(j=1;j<=i;j++)
s1[j]=s2[j];
}
}
void afis()
{
int i;
for(i=1;i<=n;i++)
cout<<s1[i]<<" ";
cout<<endl;
}
int main()
{
freopen("triunghi.in","r",stdin);
freopen("triunghi.out","w",stdout);
citire();
sol();
afis();
return 0;
}
OJI 2011
Cerinţe
Date de intrare
Fişierul grupe.in conţine pe prima linie valorile lui m şi n separate printr-un spaţiu, iar pe
celelalte m linii câte n elemente separate două câte două printr-un spaţiu, reprezentând elementele
tabloului.
Date de ieşire
- 0 $ m, n $ 101;
- elementele tabloului bidimensional iniţial sunt mai mici sau egale decât 100000 şi mai mari
decât 1;
- o grupă poate fi compusă dintr-un singur element.
Se acordă punctaje parţiale:
- 50% pentru afişarea valorilor corecte pe prima linie din fişierul grupe.out (cerinţa a));
- 50% pentru afişarea valorilor corecte pe a doua linie din fişierul grupe.out (cerinţa b)).
184
CAPITOLUL 13. OJI 2011 13.1. GRUPE - OJI 2011 185
Exemple
grupe.in grupe.out Explicaţii
23 4 2 10 Numărul divizorilor pentru fiecare element al tabloului: 5 divizori
16 2 4 225 (pentru valoarea 16), 2 divizori (pentru valoarea 2), 3 divizori (pentru
10 6 5 valoarea 4), 4 divizori (pentru valoarea 10), 4 divizori (pentru valoarea
6) şi 2 divizori (pentru valoarea 5).
Se pot forma grupele: cu 2 divizori (elementele 2, 5), cu 4 divizori
(elementele 10,6), cu 3 divizori (elementul 4) şi cu 5 divizori (elementul
16). După ordonarea descrescătoare a grupelor, grupele cu cele mai
multe elemente sunt cele care conţin 2 elemente: (10, 6), respectiv
(2, 5). Pentru că elementele 10 şi 6 au 4 divizori, ele vor face parte
din grupa A, iar 2 şi 5, având doar 2 divizori fiecare, vor face parte
din grupa B. Deci grupa A are 4 divizori, 2 elemente şi cel mai mare
element din grupă este 10, iar grupa B are 2 divizori, 2 elemente şi cel
mai mare element din grupă este 5.
23 4 3 15 Numărul divizorilor pentru fiecare element al tabloului: 2 divizori
2 15 4 225 (pentru valoarea 2), 4 divizori (pentru valoarea 15), 3 divizori (pentru
10 6 5 valoarea 4), 4 divizori (pentru valoarea 10), 4 divizori (pentru valoarea
6) şi 2 divizori (pentru valoarea 5). După ordonarea descrescătoare a
grupelor, grupa cu cele mai multe elemente este cea formată din ele-
mentele 10, 6, 15, fiecare element având exact 4 divizori. Aceasta va fi
grupa A. Grupa B va fi cea formată din două elemente, celelaltă grupă
având un singur element. Deci grupa A are 4 divizori, 3 elemente şi
cel mai mare element din grupă este 15, iar grupa B are 2 divizori, 2
elemente şi cel mai mare element din grupă este 5.
Se poate opta pentru utilizarea a doua matrice de dimensiuni mai mici, in a doua
pastrandu-se numarul de divizori pozitivi pentru fiecare element, dar o astfel
de solutie nu va functiona pentru toate testele.
Sursele care nu verifica eficient numarul de divizori nu vor primi punctaj maxim.
ifstream f("grupe.in");
ofstream g("grupe.out");
for(i=2;i<=sqrt(x);i++)
if (x%i==0)
nr+=2;
if ((int)sqrt(x)==sqrt(x))
nr--;
return nr;
}
int main()
{
long int nr,i,max1,max2,poz1,poz2,n,m;
long int a;
f>>n>>m;
for(i=1;i<=n*m;i++)
{
f>>a;
nr=nr_div(a);
x[nr]++;
if (a>maxx[nr]) maxx[nr]=a;
}
f.close();
max1 = x[2];
poz1 = 2;
max2=0;
for(i=3;i<=200;i++)
if (x[i]>=max1)
{
max2 = max1;
poz2 = poz1;
max1 = x[i];
poz1 = i;
}
else
if (x[i]>=max2)
{
max2 = x[i];
poz2 = i;
}
if (max2==0)
g<<"0 0 0";
else
g<<poz2<<" "<<x[poz2]<<" "<<maxx[poz2];
g.close();
return 0;
}
obţinându-se un nou număr k3 , ş.a.m.d. până se ajunge la aşezarea doar a ultimului jeton, caz ı̂n
care se obţine numărul kn .
Cerinţe
Scrieţi un program care citeşte numărul n de jetoane, cele n litere asociate jetoanelor, precum
şi codurile asociate literelor, ı̂n ordinea apariţiei lor şi afişează:
a) numărul de perechi de litere consecutive din cuvântul iniţial care au proprietatea că o literă
este vocală şi cealaltă este consoană (ordinea lor nu contează);
b) numărul k1 , format din aşezarea iniţială a jetoanelor;
c) suma k1 k2 ... kn .
Date de intrare
Fişierul de intrare litere.in va conţine pe prima linie valoarea lui n, reprezentând numărul de
jetoane, pe a doua linie un cuvânt format din n litere mari (de la ’A’ la ’Z’); literele sunt scrise una
după alta, fără să fie separate cu spaţii, astfel ı̂ncât prima literă este cea aflată pe primul jeton, a
doua literă pe al doilea jeton ş.a.m.d. Pe a treia linie din fişier se află un număr m ce reprezintă
numărul de litere distincte, iar pe a patra linie m valori reprezentând codurile literelor distincte ce
apar ı̂n cuvânt. Codurile sunt date ı̂n ordinea apariţiei literelor ı̂n cuvânt şi sunt numere naturale
nenule formate dintr-o singură cifră, separate printr-un spaţiu, pentru fiecare literă codul fiind dat
o singură dată, chiar dacă litera se repetă.
Date de ieşire
Fişierul de ieşire litere.out va conţine pe prima linie numărul de perechi de litere consecutive
din cuvânt care au proprietatea că o literă este vocală şi cealaltă consoană (ordinea lor nu con-
tează), pe a doua linie numărul k1 , (format din aşezarea iniţială a jetoanelor), iar pe a treia linie
suma k1 k2 ... kn .
- 0 $ n & 10000
- 0 $ m $ 27
Se acordă punctaje parţiale:
- 20% pentru afişarea valorii corecte pe prima linie din fişierul rezultat (cerinţa a));
- 40% pentru afişarea valorii corecte pe a doua linie din fişierul rezultat (cerinţa b));
- 40% pentru afişarea valorii corecte pe a treia linie din fişierul rezultat (cerinţa c)).
Exemple
//calcularea sumelor
inc=100;
for(i=0;i<n;i++) {
sum[inc+i]=(i+1)*cost[text[i]];
}
//deplasarea cifrelor daca este cazul
for(i=n-1;(i>0)||(sum[inc+i]>9);i--) {
sum[inc+i-1]+=sum[inc+i]/10;
sum[inc+i]%=10;
}
//scrierea rezultatelor in formatul cerut
char S[30002];
char c;
char *voc = "AEIOU";
long int a, N, C, k, j, i, T, aux;
char P[130], cod[130];
long int L[30];
int main()
{
FILE *f = fopen("litere.in","r");
FILE *g = fopen("litere.out","w");
fscanf(f,"%d",&N);
fscanf(f,"%s",S+1);
a = 0;
k = 0;
for (i=1;i<N;i++)
{
if ((strchr(voc, S[i]) && !strchr(voc, S[i+1])) ||
(!strchr(voc, S[i]) && strchr(voc, S[i+1])))
{
a++;
}
if (!P[S[i]])
P[S[i]] = ++k;
}
if (!P[S[N]])
P[S[N]] = ++k;
fprintf(g,"%d\n",a);
fscanf(f,"%d",&C);
for (i=1;i<=C;i++)
{
fscanf (f,"%d",&L[i]);
}
for (i=1;i<=N;i++)
S[i] = L[P[S[i]]];
for (i=1;i<=N;i++)
{
fprintf(g,"%c",S[i] + ’0’);
}
for (i=1,j=N;i<=j;i++,j--)
{
c = S[i];
S[i] = S[j];
S[j] = c;
}
CAPITOLUL 13. OJI 2011 13.2. LITERE - OJI 2011 189
while (T)
{
S[++N] = T%10;
T/=10;
}
fprintf(g,"\n");
for (i=N;i>=1;i--)
{
fprintf(g,"%c",S[i] + ’0’);
}
fclose(f);
fclose(g);
return 0;
}
OJI 2010
Cerinţe
Scrieţi un program care să citească şirul de cuvinte şi să afişeze:
a) numărul de ordine al primului cuvânt şters sau valoarea 0 ı̂n cazul ı̂n care nu se şterge niciun
cuvânt
b) numerele de ordine ale cuvintelor rămase după finalizarea operaţiilor de modificare.
Date de intrare
Fişierul cuvant.in conţine o singură linie pe care se află şirul de cuvinte separate două câte
două printr-un spaţiu.
Date de ieşire
190
CAPITOLUL 14. OJI 2010 14.1. CUVINTE - OJI 2010 191
Exemple
cuvinte.in cuvinte.out
alfa faal alfa fala lafa afal calfa calfa! 2
13478
Explicaţii:
Cuvintele obţinute prin transformarea cuvântului alfa sunt: lfaa, faal, aalf. Prima pereche
de cuvinte vecine care ı̂ndeplinesc cerinţele sunt cuvintele cu numerele de ordine 1 şi 2. Va fi şters
cuvântul cu numărul de ordine 2. şirul rezultat este format din următoarele 7 cuvinte: alfa alfa
fala lafa afal calfa calfa. Prima pereche care ı̂ndeplineşte cerinţele din noul şir este perechea
formată din cuvintele fala şi lafa, având numerele de ordine 4 şi 5, pentru că lista de cuvinte
obţinute prin transformarea cuvântului fala sunt: alaf, lafa, afal. Se va şterge cuvântul cu
numărul de ordine 5. şirul rezultat după ştergere este: alfa alfa fala afal calfa calfa. Prima
pereche care ı̂ndeplineşte cerinţele problemei ı̂n noul şir este fala şi afal. Se şterge afal cu numărul
de ordine 6. şirul rezultat după ştergere este: alfa alfa fala calfa calfa. ı̂n acest şir nu se mai
găseşte nicio pereche care să ı̂ndeplinească cerinţele. Au rămas deci cuvintele: alfa, alfa, fala,
calfa, calfa care au numerele de ordine 1, 3, 4, 7, 8.
Pentru primul cuvant se determina toate cuvintele obtinute prin transformarea lui.
char x[25][255],y[25][255];
int poz[25];
if (strcmp(x[j],y[i])==0)
return 1;
}
return 0;
}
int main()
{
char s[255],*p;
unsigned int n,i=0,t,j,prima=0;
ifstream f("cuvant.in");
ofstream g("cuvant.out");
f.get(s,255);
p=strtok(s," !");
while(p)
{
strcpy(x[i++],p);
poz[i-1]=i;
p=strtok(NULL," !");
}
n=i;
i=0;
j=1;
while(i<n-1)
{
transforma(x[i]);
if (verifica(j,strlen(x[i])-1))
{
for(t=j;t<n-1;t++)
{
strcpy(x[t],x[t+1]);
poz[t]=poz[t+1];
}
if (prima==0)
prima=j+1;
n--;
}
else
{
i++;
j=i+1;
}
}
if (poz)
g<<prima<<"\n";
else
g<<"0"<<"\n";
for(j=0;j<n;j++)
g<<poz[j]<<" ";
f.close();
g.close();
return 0;
}
Zarul folosit la diverse jocuri este un cub care are desenat pe fiecare
faţă a sa 1, 2, 3, 4, 5 sau 6 puncte. Pe un zar nu există două feţe cu
acelaşi număr de puncte şi suma punctelor de pe oricare două feţe opuse
este egală cu 7.
Pe o masă de joc este desenat un traseu ı̂n formă de pătrat, cu latura
de dimensiune n. Fiecare latură a traseului este ı̂mpărţită ı̂n n pătrăţele Figura 14.1: triunghi
identice, care au latura egală cu cea a zarului. Zarul este aşezat iniţial ı̂n
colţul din stânga sus al traseului şi apoi rostogolit de pe o faţă pe alta,
din pătrăţel ı̂n pătrăţel, de-a lungul traseului parcurs ı̂n sensul acelor de ceasornic.
În orice moment ne-am uita la zar, putem vedea numărul punctelor desenate pe trei din feţele
sale (aşa cum se vede ı̂n desenul de mai sus).
Notăm cu f 1 faţa cubului orientată spre noi, f 2 faţa superioară a cubului, respectiv cu f 3
faţa laterală din dreapta. Pentru exemplul din figură: n 4, faţa dinspre noi (f 1) conţine trei
puncte, faţa superioară (f 2) conţine două puncte, faţa laterală din dreapta (f 3) conţine un punct,
iar sensul de deplasare este cel precizat prin săgeţi.
Cerinţe
Cunoscând dimensiunea n a traseului şi numărul punctelor de pe cele trei feţe ale zarului ı̂n
poziţia iniţială, determinaţi după k rostogoliri numărul punctelor ce se pot observa pe fiecare din
cele trei feţe ale zarului.
Date de intrare
Date de ieşire
Fişierul zar.out va conţine o singură linie cu trei numere naturale separate prin câte un spaţiu,
care reprezintă numărul punctelor ce se pot observa pe feţele f 1, f 2 şi f 3 (ı̂n această ordine) după
ce au fost efectuate krostogoliri pe traseul dat.
Exemple
zar.in zar.out
4 11 153
321
Explicaţii:
Fiecare latură a traseului este formată din 4 căsuţe şi se vor efectua 11 rostogoliri. După prima
rostogolire spre dreapta, valorile celor trei feţe (f 1, f 2, respectiv f 3) ale zarului vor fi 3, 6 şi 2.
După a doua rostogolire obţinem numerele 3, 5, 6, iar după a treia rostogolire valorile feţelor vor
fi 3, 1 şi 5. ı̂n acest moment zarul a parcurs o latură a traseului. Următoarele trei rostogoliri se
vor efectua ı̂n jos, de-a lungul traseului iar feţele vor avea succesiv valorile 1, 4, 5 apoi 4, 6, 5 şi 6,
3, 5. Urmează rostogolirile spre stânga, pe feţele zarului vom observa valorile 6, 5, 4 apoi 6, 4, 2
şi respectiv 6, 2, 3. Ultimele două rostogoliri se vor efectua ı̂n sus de-a lungul laturii din stânga a
traseului. După penultima rostogolire obţinem 5, 6, 3, iar după ultima rostogolire valorile feţelor
vor fi 1, 5 şi 3.
Pozitia fetelor zarului este periodica. Din acest motiv, din patru in patru
rostogoliri pe aceeasi latura a traseului, pe fetele zarului se vor observa
aceleasi valori.
Pentru rostogoliri spre stanga sau spre dreapta de-a lungul traseului, vom
tine cont de modificarea valorilor celor patru fete implicate in rostogilirea
pe aceasta directie:
f2 f3 7-f2 7-f3
Analog vom proceda pentru fetele implicate in rostogoliri in sus sau in jos
de-a lungul celorlaltor doua laturi ale traseului. Cele patru valori ale
fetelor implicate in acest tip de rostogolire sunt:
f2 7-f1 7-f2 f1
Prin permutari ale acestor valori, vom obtine pozitia finala a zarului dupa
k rostogoliri pe traseul dat.
ifstream f("zar.in");
ofstream g("zar.out");
int main()
{
f>>n>>k;
f>>f1>>f2>>f3;
st_dr[1]=7-f2;
st_dr[2]=f3;
st_dr[3]=f2;
st_dr[4]=7-f3;
CAPITOLUL 14. OJI 2010 14.2. ZAR - OJI 2010 195
sus_jos[1]=7-f2;
sus_jos[2]=f1;
sus_jos[3]=f2;
sus_jos[4]=7-f1;
while(k>0)
{
if (k<n)//dreapta
{
rostogolire_dreapta(st_dr,k);
k=0;
}
else
{
rostogolire_dreapta(st_dr,n-1);
k=k-(n-1);
}
sus_jos[1]=st_dr[1];
sus_jos[3]=st_dr[3];
if (k<n)//jos
{
rostogolire_dreapta(sus_jos,k);
k=0;
}
else
{
rostogolire_dreapta(sus_jos,n-1);
k=k-(n-1);
}
st_dr[1]=sus_jos[1];
st_dr[3]=sus_jos[3];
if (k<n)//stanga
{
rostogolire_stanga(st_dr,k);
k=0;
}
else
{
rostogolire_stanga(st_dr,n-1);
k=k-(n-1);
}
sus_jos[1]=st_dr[1];
sus_jos[3]=st_dr[3];
if (k<n)//sus
{
rostogolire_stanga(sus_jos,k);
k=0;
}
else
{
rostogolire_stanga(sus_jos,n-1);
k=k-(n-1);
}
st_dr[1]=sus_jos[1];
st_dr[3]=sus_jos[3];
}
return 0;
}
196
Capitolul 15
ONI 2023
15.1 dominew
Problema 1 - Dominew 100 de puncte
Pentru că se plictiseşte şi este foarte inteligent, Radu l-a rugat pe prietenul lui, savantul
Feder, să creeze o activitate care să-i pună mintea la ı̂ncercare. Savantul Feder a adus N piese
dreptunghiulare pe care sunt scrise numere naturale şi le-a aşezat pe masă ı̂n ordinea crescătoare
a valorilor scrise pe ele, pe poziţii consecutive, una lângă cealaltă. Apoi ı̂i dă lui Radu, una câte
una, alte M piese dreptunghiulare, pe care sunt scrise numere naturale, ı̂ntr-o ordine oarecare.
Când Radu primeşte o piesă el trebuie să o aşeze ı̂n şirul de pe masă pe cea mai mică poziţie
posibilă, astfel ı̂ncât piesele din şir să rămână ı̂n ordine crescătoare. Evident, şirul de pe masă
se modifică pe măsură ce Radu aşază piesele ı̂n şir.
Cerinţă
Cunoscând şirul pieselor de pe masă, ı̂n ordinea ı̂n care sunt aşezate, precum şi cele M piese
pe care le primeşte succesiv Radu, scrieţi un program care să afişeze pentru fiecare dintre cele M
piese poziţia pe care aceasta este aşezată ı̂n şir.
Date de intrare
Fişierul dominew.in conţine pe prima linie numărul natural N . Pe a doua linie se află N
numere naturale, ı̂n ordine crescătoare, reprezentând valorile pieselor din şirul aflat iniţial pe
masă. Pe a treia linie se află numărul natural M . Pe cea de-a patra linie sunt M numere naturale,
reprezentând valorile pieselor pe care le primeşte Radu, ı̂n ordinea ı̂n care acesta le primeşte.
Numerele scrise pe aceeaşi linie sunt separate prin câte un spaţiu.
Date de ieşire
Fişierul de ieşire dominew.out va conţine o singură linie pe care vor fi scrise M valori separate
prin câte un spaţiu, cea de a i-a valoare fiind poziţia pe care este aşezată ı̂n şirul de pe masă cea
de a i-a piesă primită de Radu (1 & i & M ).
# Punctaj Restricţii
1 8 M 1
2 14 1 $ N, M & 100
3 8 100 $ N & 50 000, 100 $ M & 250
4 24 N & 100 000, 250 $ M & 1 000
5 46 N & 1 000 000, 1 000 $ M & 8 000
197
CAPITOLUL 15. ONI 2023 15.1. DOMINEW 198
Exemple:
Propusă de: Prof. Flavius Boian, Colegiul Naţional ”Spiru Haret”, Târgu Jiu
La citire se reţin elementele ı̂n 2 vectori distincţi (primul va avea N elemente, iar cel de-al
doilea M elemente).
În primul rând, se poate observa că numărul maxim de actualizări este mult mai mic decât
numărul de valori iniţiale (M & 8 000), mult mai mic decât valoarea maximă a lui N , ceea ce ne
duce cu gândul la a procesa separat cei doi vectori pentru a obţine răspunsul ı̂ntr-un timp optim.
Pe măsură ce se citesc elementele din cel de-al doilea vector se identifică poziţia pe care ar
trebui inserate acestea ı̂n vectorul sortat până la acel moment. Vom nota valoarea pe care o
verificăm la un pas cu x.
Pentru fiecare element din şirul de M valori, va trebui mai ı̂ntâi să căutăm binar ı̂n vectorul cu
valorile iniţiale poziţia ı̂n care se află cea mai mare valoare mai mică decât x. Să notăm această
poziţie cu a.
Apoi, vom afla şi câte valori din vectorul de lungime M situate ı̂naintea valorii curente sunt
mai mici decât x. Datorită valorii mici a lui M , putem face acest lucru verificând fiecare poziţie
anterioară poziţiei curente. Să notăm acest răspuns cu b.
Astfel, răspunsul corespunzător pentru o valoare citită va fi a b 1.
2
Soluţia are complexitatea totală O M M log N .
Soluţie alternativă. Se vor citi mai ı̂ntâi valorile şi se vor sorta valorile din vectorul de
lungime M . Apoi, vom aplica un algoritm de interclasare pentru a răspunde ı̂n manieră offline la
toate ı̂ntrebările, memorând mai ı̂ntâi poziţia unde se găseau acele actualizări ı̂n vectorul al doilea,
având grijă să prioritizăm valoarea din vectorul al doilea ı̂n caz de egalitate, pentru a respecta
restricţia din enunţ.
2
Această soluţie are complexitatea totală O M M N .
CAPITOLUL 15. ONI 2023 15.2. PIX 199
#include <iostream>
#include <fstream>
//ifstream f("dominew.in");
ofstream g("dominew.out");
int n,m,i,j,x,st,dr,mij,poz,t,a[1000001],b[8001];
int main()
{
f>>n;
f>>m;
for(i=1; i<=m; i++)
{
f>>b[i];
st=1;
dr=n;
poz=0;
while(st<=dr)
{
mij=(st+dr)/2;
if(a[mij]<b[i])
{
poz=mij;
st=mij+1;
}
else
dr=mij-1;
}
return 0;
}
15.2 pix
Problema 2 - Pix 100 de puncte
Robotul Vasile s-a angajat la un depozit de pixuri. Aici pixurile sunt ambalate ı̂n cutii.
Există N tipuri de cutii; ı̂ntr-o cutie de tipul i (1 & i & N ) sunt ambalate exact nri pixuri
(nr1 & nr2 & ... & nrN ). În depozit există un număr atât de mare de cutii de fiecare tip ı̂ncât Vasile
poate utiliza oricâte cutii doreşte, de orice tip. Sarcina robotului Vasile este să livreze pixurile
comandate de diferite firme de birotică. El nu ştie câte pixuri va avea de livrat la următoarea
comandă, dar ştie că vor fi cel mult Vmax pixuri. Ca urmare, pentru a fi eficient, robotul Vasile
vrea să ı̂şi pregătească ı̂n camera de livrare un număr minim de cutii de pixuri astfel ı̂ncât să
poată livra orice număr de pixuri cuprins ı̂ntre 1 şi Vmax folosind cutiile pregătite, evident, fără
a deschide cutiile.
CAPITOLUL 15. ONI 2023 15.2. PIX 200
Cerinţe
Scrieţi un program care citeşte valorile N , nr1 , nr2 , ..., nrN şi V max şi determină numărul
minim de cutii pe care robotul Vasile trebuie să le pregătească ı̂n camera de livrare astfel ı̂ncât să
poată livra orice număr de pixuri cuprins ı̂ntre 1 şi Vmax , fără a deschide nicio cutie.
Date de intrare
Fişierul de intrare pix.in conţine pe prima linie numărul natural N reprezentând numărul de
tipuri de cutii.
Pe a doua linie se află N numere naturale ı̂n ordine crescătoare, separate prin câte un spaţiu,
nr1 , nr2 , ..., nrN reprezentând numărul pixuri ambalate ı̂n fiecare tip de cutie.
Pe a treia linie se află numărul natural Vmax cu semnificaţia din enunt,.
Date de ieşire
Fişierul de ieşire pix.out va conţine o singură linie pe care va fi scris un număr natural
reprezentând numărul minim de cutii pe care robotul Vasile trebuie să le pregătească ı̂n camera
de livrare astfel ı̂ncât să poată livra orice număr de pixuri cuprins ı̂ntre 1 şi Vm ax.
# Punctaj Restricţii
1 20 1 & N $ 15
2 10 15 & N $ 600
3 40 Vmax & 100 000
Exemple:
Propusă de: Prof. Emanuela Cerchez, Colegiul Naţional ”Emil Racovit, ă”,Ias, i
Reţinem ı̂ntr-un vector nr capacităţile distincte & V max.
Deoarece se garantează că există soluţie, obligatoriu nr1 1.
Vom lua o cutie de tipul 1.
Analizăm apoi nr2. Dacă nr2 % nr1 atunci comenzile pentru capacitatea x din mulţimea
r1, 2, ..., nr 2 1x nu pot fi obţinute decât din mai multe cutii cu capacitatea nr 1 1.
Pentru ca formula să funcţioneze şi pentru i n vom iniţializa componenta n 1 a vectorului
nr cu Vmax 1, astfel că la pasul n vom asigura toate comenzile pentru capacităţile x & Vmax .
nr[n+1] = Vmax+1;
rez = nr[2]-1; sum=n[2]-1; // in rez contorizam cutiile
for(i=2; i<=n; i++)
{
if(nr[i+1]-1 <= sum) continue;
cate = (nr[i+1]-1-sum)/nr[i];
if(cate * nr[i] + sum < nr[i+1]-1) cate++;
rez += cate;
sum += cate * nr[i];
}
ifstream fin("pix.in");
ofstream fout("pix.out");
int n, lg;
long long int nr[NMAX];
long long int a[NMAX];
long long int vmax, rez, sum, ultima, cate;
CAPITOLUL 15. ONI 2023 15.3. SECVMIN 202
int main()
{
int i;
fin>>n;
fin>>vmax;
//sort(a+1,a+n+1);
n=lg;
nr[n+1]=vmax+1;
rez=nr[2]-1;
sum=nr[2]-1;
fout<<rez<<’\n’;
fout.close();
return 0;
}
15.3 secvmin
Problema 3 - Secvmin 100 de puncte
Fie un şir de n numere naturale v1 , v2 , ..., vn , unde vi reprezintă al i-lea număr din şir. O
subsecvenţă x, y a şirului v (cu 1 & x & y & n) conţine toate elementele vx , vx1 , ..., vy1 , vy .
Cerinţă
Fiind date două numere naturale n şi k şi un şir v de n numere naturale, scrieţi un program
care să răspundă la următoarea ı̂ntrebare: câte subsecvent,e conţin simultan cele mai mici k valori
distincte din şir?
Date de intrare
Fişierul de intrare secvmin.in conţine pe prima linie numerele n şi k, iar pe cea de a doua linie
se vor afla numerele naturale v1 , v2 , ..., vn , cu semnificaţia din enunţ. Numerele scrise pe aceeaşi
linie sunt separate prin câte un spaţiu.
Date de ieşire
Fişierul de ieşire secvmin.out va conţine o singură linie pe care va fi scris răspunsul la cerinţa
problemei.
CAPITOLUL 15. ONI 2023 15.3. SECVMIN 203
1&k &5
1 & vi & 1 000 000 000, pentru 1 & i & n
Se garantează că şirul va conţine cel puţin k valori distincte.
# Punctaj Restricţii
1 23 k 1
2 32 k 2
3 45 3&k&5
Exemple:
Propusă de: Stud. Theodor-Gabriel Tulba-Lecu şi Ioan-Cristian Pop, Universitatea Politehnica
Bucureşti
Să considerăm cele mai mici valori distincte din şir y1 , y2 , ..., yk . Pentru fiecare poziţie i din şir
vom calcula şi vom actualiza valorile last1 , last2 , ..., lastk cu semnificaţia lastj este cea mai mare
poziţie mai mică sau egală decât i ı̂n care a apărut valoarea yj .
Se observă că o secvenţă care are capătul dreapta ı̂n poziţia i va conţine toate cele k valori
minime dacă şi numai dacă capătul stânga al secvenţei este mai mic sau egal decât toate valorile
lastj . Pentru a obţine soluţia, la fiecare i actualizăm şirul last şi adunăm la soluţie valoarea
minimă a acestui şir.
Pentru a forma şi actualiza şirul last este necesar ca ı̂n prealabil să avem calculate cele k valori
minime, dar aceasta se poate realiza ı̂ncă de la citire prin inserarea ı̂n şirul y a celor mai mici k
valori atunci când ele apar.
Şirul last se iniţializează cu 0 şi se actualizează de fiecare dată când la o poziţie i apare una
dintre cele k valori minime. Soluţia are complexitatea O N K
CAPITOLUL 15. ONI 2023 15.3. SECVMIN 204
ifstream f("secvmin.in");
ofstream g("secvmin.out");
int main()
{
f>>n>>k;
if(val<y[k])
{
int p=1;
while(val>y[p]) p++;
if(val<y[p])
{
int q=k;
while(q>p)
{
y[q]=y[q-1];
q--;
}
y[p]=val;
}
}
x[i]=val;
}// for i
sol+=cnt;
}// for i
g<<sol;
return 0;
}
ONI 2022
16.1 microbuz
Problema 1 - Microbuz 100 de puncte
O companie de transport cu microbuze din judeţul Iaşi a adoptat o strategie proprie pentru
rutele din judeţ :
niciun traseu nu poate avea mai mult de 165 kilometri
distanţa ı̂ntre două staţii consecutive este de un kilometru
un pasager poate pleca din orice staţie şi poate să ı̂şi cumpere bilete pentru parcurgerea a
1, 2, . . . , 10 kilometri
fiecare dintre cele zece distanţe posibile au bilete cu preţuri distincte
De exemplu:
1 km 2 km 3 km 4 km 5 km 6 km 7 km 8 km 9 km 10 km
11 lei 14 lei 18 lei 23 lei 29 lei 36 lei 44 lei 45 lei 53 lei 64 lei
Gigel, care călătoreşte cu microbuzul exact N kilometri, poate să aleagă una sau mai multe
distanţe dintre cele zece stabilite şi să cumpere biletele corespunzătoare. Compania impune ca un
pasager să poată cumpăra maxim 3 bilete de acelaşi tip.
Gigel observă că pentru aceeaşi sumă poate achiziţiona seturi diferite de bilete cu preţuri
distincte. Pentru exemplu de mai sus, cu 98 de lei el poate cumpăra câte un bilet cu preţurile 11,
14, 29, 44 lei sau câte un bilet cu preţurile 45, 53 lei (11 + 14 + 29 + 44 = 45 + 53).
Cerinţe
Date de intrare
Fişierul de intrare microbuz.in are trei linii. Pe prima linie se află un număr natural C ce
reprezintă cerinţa (1, 2 sau 3). Linia a doua conţine zece valori naturale ordonate strict crescător,
separate prin câte un spaţiu, reprezentând preţurile pentru parcurgerea a 1, 2, . . . , 10 kilometri.
Linia a treia conţine valoarea N reprezentând distanţa pe care doreşte să o parcurgă Gigel.
Date de ieşire
205
CAPITOLUL 16. ONI 2022 16.1. MICROBUZ 206
3. dacă C = 3, pe prima linie se va afişa preţul comun al celor două seturi de bilete, iar pe
următoarele două linii câte un set de bilete dat prin numărul de km pentru biletele din set
ı̂n ordine strict crescătoare, separate prin câte un spaţiu.
Restricţii şi precizări
C " r1, 2, 3x
1 & N & 165
cele 10 preţuri sunt numere naturale din intervalul [10, 99 ]
răspunsul la cerinţa 3 nu depinde de valoarea lui N
# Punctaj Restricţii
1 28 C 1
2 38 C 2
3 34 C 3
Exemple:
Cerinţele 1 şi 2. Se vor genera toate combinaţiile posibile de bilete ı̂n mod succesiv.
Pentru ı̂nceput, vom reţine ı̂n tabloul max cnti min 3, ni , pentru i de la 1 la 10, numărul
maxim de bilete de tip i pe care le putem cumpăra fără a depăşi n kilometri.
În continuare, vom genera fiecare combinaţie cu ajutorul tabloului cnti = numărul de bilete
de tip i din combinaţie, ı̂n mod succesiv utilizând un algoritm de tip succesor. Pentru fiecare
combinaţie vom calcula distanţa parcursă:
distanta 1 cnt1 2 cnt2 ... 10 cnt10
CAPITOLUL 16. ONI 2022 16.1. MICROBUZ 207
Soluţie prof. Claudiu-Cristian Gorea-Zamfir. - Şcoala Gimnazială Alexandru cel Bun, Iaşi
Cerinţele 1 şi 2.
- Se generează toate numerele de 10 cifre, ı̂n baza 4 şi se renţin pentru un număr cifrele sale
ı̂ntr-un tablou cif . Acest tablou va reţine numărul de bilete cumpărate pentru fiecare tip
de bilet i de la 1 la 10;
- Se calculează preţul astfel:
- Dacă dist n şi pret $ pretmin atunci reţinem configuraţia actuală a tabloului cif şi
actualizăm pretmin pret;
Cerinţa 3.
Fie:
Construirea tabloului cost. Să presupunem că la pasul curent considerăm achiziţionarea unui bilet
ce asigură parcurgerea unei distanţe de d km, cu preţul egal cu biletd ;
Obţinem astfel următoarea relaţie de recurenţă:
De exemplu, să considerăm, ı̂n contextul acestei scrieri, numărul binar 0000010111:
astfel ı̂ncât ı̂nsumate să dea S. Pentru aceasta, folosim un algoritm identic cu cel folosit ı̂n
cadrul cerinţei 2.
Pentru reconstrucţia soluţiei ne vom folosi de biletele cumpărate ı̂n configuraţiile Ddist1 .conf ,
Ddist2 .conf respectiv Ddist3 .conf .
K
Complexitatea aceste soluţii este O 2 , unde K este numărul de tipuri de bilete posibile pe
care le putem cumpăra. Pentru această problemă K 10.
Cerinţa 3. Se calculează tabloul bidimensional:
~
dacă există o submulţime x a submulţimii conf
1.
Aconf,sum cost
astfel ı̂ncât suma costurilor biletelor din submulţimea x să fie sum cost
0, altf el
Ce rămâne de făcut este să iterăm prin toate submulţimile conf posibile ale celor K bilete.
Fie comp conf submulţimea complementară submulţimii conf .
Fie s suma costurilor biletelor din submulţimea conf .
Dacă Acomp conf,s 1 ı̂nseamnă că am găsit două submulţimi disjuncte de bilete care ı̂nsumează
acelaşi cost. Nu uităm ı̂nsă că Acomp conf,s 1 indică faptul că există o submulţime a lui
comp conf pentru care suma costurilor biletelor din ea să fie s şi nu ı̂nseamnă neapărat că suma
costurilor biletelor din comp conf este egală cu s.
K
Complexitatea soluţiei este O 2 Smax , unde Smax reprezintă suma totală a costurilor
biletelor.
16.2 raza
Problema 2 - Raza 100 de puncte
Pe planeta Quadratia, locuitorii folosesc forme pătrate ı̂n tot ceea ce construiesc. Ei au trimis
pe solul planetei N maşini speciale de apărare, numite rovere, care se deplasează pe traiectorii ce
descriu pătrate.
CAPITOLUL 16. ONI 2022 16.2. RAZA 210
Harta planetei poate fi privită ca un tablou bidimensional cu număr infinit de linii şi coloane,
numerotarea acestora ı̂ncepând cu 1. Fiecare element al acestui tablou se identifică prin numărul
liniei, respectiv numărul coloanei pe care se găses, te.
Fiecare rover este descris prin 3 numere naturale nenule L, C şi R, reprezentând poziţia (linia
L şi coloana C) elementului din colţul din stânga-sus al pătratului ce descrie traiectoria, respectiv
lungimea R a laturii acestuia. Toate roverele pornesc iniţial din elementul din colţul stânga-sus al
pătratului ce descrie traiectoria, pe care o parcurg ı̂n sensul acelor de ceasornic, traversând câte
un element pe secundă. Ele sunt programate să parcurgă această traiectorie fără a se opri. Este
posibil ca mai multe rovere să se afle, la un moment dat la aceeaşi poziţie de pe hartă.
Rectilinienii sunt singurii duşmani ai quadratienilor, ei deosebindu-se de aceştia prin folosirea
consecventă a liniilor drepte ı̂n tot ceea ce construiesc. Rectilinienii au construit o armă laser de
mare putere, pe care vor să o folosească la distrugerea roverelor quadratiene. Arma a fost adusă
ı̂n poziţia 1, 1 de pe harta planetei, adică elementul de pe prima linie şi prima coloană. Arma
poate emite o singură rază distructivă, timp de o secundă, dezafectând ı̂n acest timp toate roverele
aflate ı̂n secunda respectivă pe diagonala principală a tabloului care descrie harta planetei. Arma
nu poate fi detectată ı̂n primele S secunde. Traiectoria roverelor poate trece prin poziţia ı̂n care
a fost amplasată arma, fără a o putea detecta ı̂n primele S secunde.
În imaginea alăturată avem două rovere, acestea fiind iden-
tificate prin tripletele de numere 4, 2, 6, respectiv 6, 9, 4.
Traiectoria primului rover ı̂ncepe din poziţia 4, 2 şi are
latura 6. Numerele de pe traiectorie reprezintă secunda la
care se parcurge respectivul element al tabloului. Roverul
va ajunge din nou ı̂n poziţia iniţială la secundele 21, 41,
61, . . . . Primul rover intersectează, la prima sa trecere,
diagonala principală ı̂n două puncte: 4, 4 la secunda 3 şi
7, 7 la secunda 9. Al doilea rover intersectează diagonala
principală ı̂ntr-un singur punct 9, 9 la secundele 10, 22, 34, . . . .
Cerinţe
Date de intrare
Datele de intrare se citesc din fişierul raza.in, care are următoarea structură:
pe prima linie se află numărul natural T " r1, 2x, semnificând numărul cerinţei de rezolvat.
pe a doua linie se află numerele naturale nenule N şi S, separate printr-un spaţiu,
reprezentând numărul roverelor, respectiv numărul de secunde ı̂n care arma nu este de-
tectată.
pe următoarele N linii se află câte 3 numere naturale nenule, L C R, separate prin câte
un spaţiu, reprezentând coordonatele poziţiei iniţiale, respectiv lungimea laturii traiectoriei
fiecărui rover.
Date de ieşire
Datele de ieşire se vor afişa ı̂n fis, ierul raza.ouţ care are următoarea structură ı̂n funcţ ie de
cerinţă:
dacă T 1, pe prima linie se va afişa numărul roverelor a căror traiectorie se intersectează
cu diagonala principală;
dacă T 2, pe prima linie se vor afişa două numere naturale, separate printr-un spaţiu,
reprezentând numărul maxim de rovere dezactivate şi secunda minimă ı̂n care se poate
realiza acest lucru.
CAPITOLUL 16. ONI 2022 16.2. RAZA 211
# Punctaj Restricţii
1 28 T 1
2 72 T 2
Exemple:
Fie x, y linia respectiv coloana colţului din stânga-sus al traiectoriei roverului curent iar r
lungimea laturii traiectoriei. Condiţia de intersecţie a traiectoriei cu diagonala este:
unui secunda ı̂n care roverul i intersectează prima dată diagonala ı̂n cadrul primei par-
curgeri a traiectoriei;
doii secunda ı̂n care roverul i intersectează a doua oară diagonala ı̂n cadrul primei par-
curgeri a traiectoriei sau 0, dacă roverul NU intersectează diagonala ı̂n două poziţii;
prdi 4 r 4, perioada roverului i (numărul de secunde necesare parcurgerii ı̂ntregii
traiectorii);
Numărul de secunde S este relativ mic, deci putem calcula, pentru fiecare secundă ı̂ntre 1 şi S,
câte rovere se găsesc pe diagonala principală ı̂n acel moment. Acest calcul presupune marcarea,
pentru fiecare rover, a tuturor momentelor de timp ı̂n care roverul atinge diagonala principală,
folosind cei trei vectori construiţi anterior. Reţinem la fiecare pas numărul maxim curent şi
momentul de timp corespunzător.
Soluţie prof. Gorea-Zamfir Claudiu-Cristian. - Şcoala Gimnazială Alexandru cel Bun, Iaşi
La citirea roverelor, identificăm 5 situaţii bazate pe valorile de plecare, raza atinge traiectoria
astfel:
2 colţuri (l c) - momentele de timp sunt r0, 2r, 4r, 6r, ...x;
1 colţ, dreapta-sus (c r l) - momentele de timp sunt r1r, 5r, 9r, ...x;
1 colţ, stânga-jos (l r c) - momentele de timp sunt r3r, 7r, 11r, ...x;
2 laturi nord şi est (c $ l şi l $ c r) - momentele de timp sunt r1 l c, 1 l c 4r, 1
l c 8r, ...x şi r2r 1 l c, 6r 1 l c, 10r 1 l c, ...x;
2 laturi sud şi vest (l $ c şi c $ l r) - momentele de timp sunt r1 c l 2r, 1 c l
6r, 1 c l 10r, ...x şi r1 c l 4r, 1 c l 8r, 1 c l 12r, ...x.
În fiecare situaţie contorizăm faptul ca raza intersectează traiectoria acestui rover. Numărul
de rovere intersectate, fiind răspunsul cerinţei 1.
Pentru cerinţa 2, ı̂n fiecare dintre cele 5 situaţii, pe baza relaţiilor de tip progresie aritmetică
obţinute din periodicitatea ı̂ntâlnirii roverului cu raza, vom folosi un vector de frecvenţă pentru a
marca la fiecare moment care rovere ar fi afectate. La final determinăm maximul din acest vector
şi momentul ı̂n care raza va emite.
16.3 text
Problema 3 - Text 100 de puncte
Alexandra citeşte un text format din litere mici şi mari ale alfabetului englez şi spaţii. Fiind
interesată de criptografie, ea elimină toate spaţiile şi apoi ı̂ncadrează literele, ı̂n ordinea ı̂n care
acestea apar ı̂n text ı̂ntr-un tablou bidimensional, ı̂n care numărul de linii este mai mic sau egal
decât numărul de coloane.
Întrucât pot exista mai multe moduri de ı̂ncadrare a textului, Alexandra ı̂l alege pe cel pentru
care diferenţa absolută dintre numărul liniilor şi al coloanelor tabloului este minimă. Completarea
cu literele textului a tabloului bidimensional se face ı̂n ordinea crescătoare a liniilor şi ı̂n cadrul
fiecărei linii, ı̂n ordinea crescătoare a coloanelor.
Cerinţe
1. Notând cu N numărul de linii şi cu M numărul de coloane ale tabloul bidimensional obţinuţ
afişaţi elementele acestuia pe primele N linii ale fişierului de ieşire, fiecare linie conţinând
exact M litere fără spaţii ı̂ntre ele. Afişarea se va face ı̂n ordinea crescătoare a indicilor
liniilor şi pe fiecare linie ı̂n ordinea crescătoare a indicilor coloanelor.
CAPITOLUL 16. ONI 2022 16.3. TEXT 213
# Punctaj Restricţii
1 16 C 1 şi numărul de caractere din şirul iniţ ial & 10 000
2 36 C 2 şi numărul de caractere din şirul iniţ ial & 1 000
3 16 C 3 şi numărul de caractere din şirul iniţ ial & 1 000
4 16 C 3 şi numărul de caractere din şirul iniţ ial & 50 000
5 16 C 3, fără restricţii suplimentare
2. Determinaţi cel mai lung palindrom de pe o linie sau de pe o coloană a tabloului obţinut. În
cazul ı̂n care există mai multe palindroame de aceeaşi lungime, se va afişa cel care este cel
mai mare din punct de vedere lexicografic conform codului ASCII.
3. Determinaţi care este numărul maxim de elemente dintr-un subtablou dreptunghiular, ce
conţine doar vocale.
Date de intrare
Datele de intrare se citesc din fişierul text.in, care are următoarea structură:
pe prima linie se află numărul natural C care poate avea doar valorile 1, 2 sau 3, semnificând
numărul cerinţei de rezolvat;
pe a doua linie se află textul pe care ı̂l va prelucra Alexandra.
Date de ieşire
Datele de ieşire se vor afişa ı̂n fişierul text.out care are următoarea structură:
dacă C 1, N linii, fiecare conţinând câte M litere, repezentând elementele tabloului obţinut;
dacă C 2, o singură linie conţinând cel mai lung palindrom determinat;
dacă C 3, o singură linie conţinând un număr natural reprezentând numărul de elemente
din subtabloul determinat.
2 & numărul total de caractere din textul iniţ ial al Alexandrei & 200 000
vocalele sunt: A, E, I, O, U, a, e, i, o, u
se garantează că N, numărul de linii ale tabloului obţinut este % 1
Exemple:
ONI 2021
17.1 Cat2Pal
Problema 1 - Cat2Pal 100 de puncte
Prin concatenarea a două numere naturale A şi B se pot obţine numerele naturale AB şi BA.
De exemplu, dacă A 8 şi B 8, atunci prin concatenare se poate obţine numărul 88, iar dacă
A 7 şi B 17, atunci prin concatenare se pot obţine numerele 717 şi respectiv 177.
Cerinţe
1. Pentru un număr natural nenul A dat, să se calculeze P1 , numărul numerelor naturale
distincte X, unde 1 & X & 10 A, astfel ı̂ncât X concatenat cu A sau A concatenat cu X
este palindrom.
2. Date fiind numărul natural N şi un şir de N numere naturale v 1, v 2, ..., v N , să se
calculeze P2 , numărul de numere palindrom distincte care se pot obţine prin concatenarea
numerelor din perechile v i, v j , unde 1 & i & N şi 1 & j & N .
Date de intrare
Fişierul de intrare cat2pal.in conţine pe prima linie numărul natural C, reprezentând cerinţa
care urmează sa fie rezolvată (1 sau 2).
Dacă C 1, atunci pe linia a doua se află numărul natural A.
Dacă C 2, atunci pe linia a doua se află numărul natural N şi pe linia a treia se află N
numere naturale separate prin spaţiu, reprezentând ş irul v.
Date de ieşire
Fişierul de ieşire cat2pal.out va conţine o singură linie pe care se va scrie un singur număr
natural, reprezentând rezultatul pentru cerinţa C din fişierul de intrare.
216
CAPITOLUL 17. ONI 2021 17.1. CAT2PAL 217
Exemple:
Astfel se pot depune aceste numere ı̂ntr-un vector şi apoi se verifică şi se numără valorile
distincte care corespund cerinţelor.
2
Complexitate temporală: O log A
Pentru a doua cerinţa se vor parcurge pentru fiecare valoare (asemănător cu rezolvarea de la
prima cerinţă) prefixele şi sufixele valorii oglindite şi pentru fiecare dintre acestea se va ı̂ncerca
obţinerea unui palindrom.
Pentru fiecare palindrom obţinut se va construi un sufix identificator, pentru palindrom cu k
cifre sufixul va avea k k2 cifre, care va fi marcat ı̂ntr-un vector de poziţie. La final vor fi numărate
poziţiile marcate.
2
Complexitate temporală: O N log M axV al
17.2 virus
Problema 2 - virus 100 de puncte
Un laborator specializat studiază mutaţiile unui virus pandemic pentru a găsi cel mai bun
vaccin pentru combaterea acestuia.
Codul unui virus este un şir format din litere (mari şi mici) ale alfabetului englez. Numim
mutaţie a virusului pandemic un şir de caractere care are aceeaşi lungime cu codul virusului şi
care conţine o singură poziţie pentru care litera din şir este diferită de litera situată pe poziţia
respectivă ı̂n codul virusului pandemic.
De exemplu, pentru virusul pandemic având codul abac, şirul Bbac reprezintă o mutaţie,
deoarece are aceeaşi lungime şi diferă doar prin litera de pe prima poziţie.
Laboratorul primeşte o listă conţinând codurilor mai multor viruşi descoperiţi ı̂n urma
testărilor.
Cerinţe
Scrieţi un program care, cunoscând codul virusului pandemic şi lista codurilor viruşilor
descoperiţi ı̂n urma testărilor, rezolvă următoarele cerinţe:
1. Determină numărul de mutaţii ale virusului pandemic existente ı̂n listă, mutaţii nu neapărat
distincte;
2. Determină mutaţia cu număr maxim de apariţii ı̂n listă; dacă există mai multe mutaţii cu
acelaşi număr maxim de apariţii, se va determina prima mutaţie, ı̂n ordine lexicografică.
Date de intrare
Fişierul de intrare virus.in conţine pe prima linie un număr natural C reprezentând cerinţa
care trebuie să fie rezolvată (1 sau 2). Pe cea de a doua linie se află codul virusului pandemic. Pe
a treia linie se află un număr natural N , reprezentând numărul de viruşi existenţi ı̂n lista primită
de laborator. Pe următoarele N linii se află codurile viruşilor din listă, câte un cod pe o linie.
Date de ieşire
Dacă C 1, pe prima linie va fi scris un număr natural care reprezintă câte elemente din
listă sunt mutaţii ale virusului pandemic.
Dacă C 2, pe prima linie va fi scris un şir de caractere care reprezintă mutaţia cu număr
maxim de apariţii. Dacă există mai multe mutaţii cu număr maxim de apariţii, va fi afişată
prima (cea mai mică), n̂ ordine lexicografică.
Dacă a şi b sunt două şiruri de lungime lg, spunem că şirul a a0 a1 a2 ...alg1 este mai
mic din punct de vedere lexicograficc decât şirul b b0 b1 b2 ...blg1 , dacă există o poziţie
k " r0, 1, 2, ..., lg 1x astfel ı̂ncât ai bi pentru orice 0 & i $ k şi ak $ bk .
În codul ASCII codurile literelor mari sunt mai mici decât codurile literelor mici.
Pentru alte teste valorând 16 de puncte: C 2, N le500 şi lungimea maxima a codului unui
virus este 40.
Pentru alte teste valorând 53 de puncte: C 2 şi nu există restricţii suplimentare.
Exemple:
CAPITOLUL 17. ONI 2021 17.2. VIRUS 219
2 XbcD mutaţiile XbcD şi aXcD apar fiecare de câte 2 ori, prima ı̂n
abcD ordine lexicografică fiind XbcD.
8 XbcD este mai mic lexicografic decât aXcD, deoarece ı̂n codul
abcdD ASCII:
XbcD ’A’ ¡ ’B’ ¡ ... ¡ ’Z’ ¡ ’a’ ¡ ’b’ ¡ ... ¡ ’z’
Xc
XbcD
aXcD
aXcD
aXc
ab
17.3 zid
Problema 3 - zid 100 de puncte
Un zid ornamental de formă dreptunghiulară este alcătuit din N rânduri de cărămizi, fiecare
rând având câte M cărămizi identice, aşezate una lângă alta. Fiecare cărămidă este colorată
ı̂ntr-una dintre culorile r0, 1, 2, ..., Cmax .
Un pătrat de latură L ı̂n acest zid este constituit din cărămizile situate pe L rânduri consecutive
şi L coloane consecutive.
Spunem că un pătrat este colorat uniform dacă el conţine acelaşi număr de cărămizi din fiecare
culoare care apare ı̂n pătratul respectiv.
Cerinţe
Scrieţi un program care, ând configuraţia zidului, determină ı̂n acest zid un pătrat de latură
maximă, colorat uniform.
Date de intrare
Fişierul de intrare zid.in conţine pe prima linie numerele naturale N M Cmax , reprezentând
numărul de rânduri de cărămizi, numărul de cărămizi de pe fiecare rând, respectiv culoarea
maximă.
Pe următoarele N linii este descrisă configuraţia zidului, de sus ı̂n jos; pe fiecare linie dintre
cele N se află câte M numere naturale, reprezentând culorile cărămizilor de pe rândul respectiv,
ı̂n ordine, de la stânga la dreapta. Valorile scrise pe aceeaşi linie sunt separate prin câte un spaţiu.
Date de ieşire
Fişierul de ieşire zid.out va conţine o singură linie pe care vor fi scrise 3 numere naturale
N r R C, separate prin câte un singur spaţiu, reprezentând numărul de cărămizi existente ı̂ntr-un
pătrat colorat uniform de latură maximă, respectiv rândul şi cărămida de pe rând situată ı̂n colţul
din stânga-sus al pătratului colorat uniform de latură maximă.
Exemple:
CAPITOLUL 17. ONI 2021 17.3. ZID 221
Pentru a memora frecvenţa de apariţie a fiecărei litere ı̂ntr-un pătrat cu colţul stânga-sus ı̂n
poziţia i, j şi colţul din dreapta-jos ı̂n poziţia i L 1; j L 1 vom utiliza un vector uz,
unde uz k reprezintă frecvenţa de apariţie a culorii k. Calcularea vectorului uz se poate face ı̂n
O C , ı̂n următorul mod:
223
Capitolul 19
ONI 2019
19.1 domino
Problema 1 - domino 100 de puncte
Într-un joc de domino, fiecare piesă este ı̂mpărţită ı̂n două zone, ı̂n fiecare zonă fiind ı̂nscris
un număr natural. Dacă jocul are dimensiunea d, ı̂n joc vor exista toate piesele distincte care se
pot forma cu numere cuprinse ı̂ntre 0 şi d. Două piese sunt considerate identice dacă au ı̂nscrise
aceleaşi numere, indiferent de ordinea lor. Astfel, piesele 3, 7şi 7, 3 sunt identice. De exemplu,
jocul de dimensiune d 2 va avea 6 piese distincte:
Suma tuturor numerelor de pe aceste piese este 12. Problema are două cerinţe:
1. Dat fiind un şir format din N numere naturale nenule reprezentând dimensiunile unor jocuri
de domino, să se determine pentru fiecare joc suma tuturor numerelor ı̂nscrise pe piesele din jocul
respectiv.
2. Dat fiind un şir format din N numere naturale nenule reprezentând sumele tuturor numerelor
de pe piesele unor jocuri de domino, se construieşte mai ı̂ntâi un şir de cifre, notat cu A, scriind
ı̂n ordine toate numerele din şirul dat, fără spaţii ı̂ntre ele. Se cere să se construiască un şir strict
crescător de numere naturale, notat cu B, parcurgând alternativ cifrele din şirul A de la stânga
la dreapta şi de la dreapta la stânga după cum urmează:
- primul număr din B este format din prima cifră din şirul A;
- al doilea număr din B se construieşte concatenând (alipind) cifrele din A, ı̂ncepând de la
dreapta către stânga, până când obţinem un număr strict mai mare decât primul număr din B;
- al treilea număr din B se construieşte concatenând cifrele din A de la stânga către dreapta
(ı̂ncepând cu prima cifră care nu a fost deja utilizată), până când obţinem un număr strict mai
mare decât precedentul din B;
- al patrulea număr din B se construieşte concatenând din nou cifrele din A de la dreapta la
stânga (ı̂ncepând cu cea mai din dreapta cifră care nu a fost deja utilizată), până când obţinem
un număr strict mai mare decât al treilea din B;
- se continuă astfel alternativ, până când nu se mai poate forma un număr strict mai mare
decât ultimul număr adăugat ı̂n B.
Cerinţe
Date de intrare
Fişierul de intrare domino.in conţine pe prima linie un număr natural C reprezentând cerinţa
care trebuie rezolvată (1 sau 2). Pe a doua linie se află numărul natural N . Pe a treia linie se află
N numere naturale nenule separate prin câte un spaţiu d1 d2 ... dN .
Date de ieşire
224
CAPITOLUL 19. ONI 2019 19.1. DOMINO 225
Fişierul de ieşire domino.out va conţine o singură linie. Dacă C 1, pe prima linie se vor afişa
N numere naturale separate prin câte un spaţiu; al i-lea număr afişat reprezintă suma numerelor
din jocul de domino având dimensiunea di (1 & i & N ). Dacă C 2, pe prima linie se vor afişa ı̂n
ordine, separate prin câte un spaţiu, valorile din şirul B determinat conform regulilor din enunţ.
Restricţii şi precizări
a 1 & N & 104
a Dacă C 1, 1 & di & 1000, iar dacă C 2, 1 & di & 109, pentru 1 & i & N .
a Numerele din şirul B vor fi afişate fără zerouri nesemnificative (de exemplu, dacă ı̂n urma
aplicării regulilor din enunţ ı̂n şirul B se obţine numărul 0204 se afişează 204).
a Pentru teste ı̂n valoare de 30 de puncte cerinţa este 1.
Exemple
domino.in domino.out Explicaţii
1 12 30 2040 60 252 Cerinţa este 1, deci trebuie să determinăm sumele numerelor
5 din jocurile de dimensiune 2, 3, 15, 4 şi 7.
2 3 15 4 7
Cerinta 1:
Cerinta 2:
Testele au fost alese astfel incat se putea obtine punctaj si in situatia folosirii
tip long long.
Exista teste in care valorile pe baza carora se obtin sirurile sunt formate din cif
#define M 10005
ifstream cin("domino.in");
ofstream cout("domino.out");
int main()
{
int pr;
cin >> pr;
if (pr == 1)
{
int i, x, a, b, c;
cin >> n;
for(i=1; i<=n; i++)
CAPITOLUL 19. ONI 2019 19.1. DOMINO 227
{
cin >> x;
a = x;
b = x+1;
c = x+2;
if(a%2 == 0)
a /= 2;
else
b /= 2;
v[i] = a * b * c;
}
cin >> n;
for(i=1; i<=n; i++)
cin >> v[i];
i = 1; j = n;
exista = true;
unde = 2; //urmeaza dreapta - stanga
cif = v[1]/p[1];
nr[0] = (char)(cif+’0’);
nr[1] = ’\0’;
v[1] = v[1] % p[1];
p[1] = p[1] / 10;
if(p[1] == 0)
i = 2;
cout << nr << ’ ’; // nr format din prima cifra
while(i<=j && exista)
{
if(unde == 2)
{
s = 0;
while(v[j] > 0 && j >= i)
{
cif = v[j]%10;
v[j] /= 10;
p[j] /= 10;
if(cif == 0 && s == 0)
continue;
aux[s++] = (char)(cif+’0’);
aux[s] =’\0’;
if(v[j]==0 && j >= i && p[i] != 0)
j--;
if(strlen(aux) > strlen(nr) ||
(strcmp(aux, nr)>0 && strlen(aux) == strlen(nr)))
{
unde = 1;
break;
}
}
else
{
s = 0;
while(p[i] > 0 && i <= j)
{
cif = v[i] / p[i];
v[i] = v[i] % p[i];
p[i] = p[i] / 10;
if(cif == 0 && s == 0)
{
if(p[i] == 0 && i <= j && p[j] != 0)
i++;
continue;
}
aux[s++] = (char)(cif+’0’);
aux[s] = ’\0’;
return 0;
}
ifstream fin("domino.in");
ofstream fout("domino.out");
int compar (char a[], int lga, char b[], int lgb);
int main()
{int i, nr, poz, st, dr, lg, j;
long long int x;
CAPITOLUL 19. ONI 2019 19.1. DOMINO 229
fin>>cerinta>>n;
assert(cerinta==1 || cerinta==2);
assert(0<n && n<=10000);
if (cerinta==1)
{
i=0;
while (fin>>x)
{
i++;
assert(0<x && x<=1000);
fout<<x*(x+1)*(x+2)/2<<’ ’;
}
assert(i==n);
fout<<’\n’; fout.close(); return 0;
}
poz=0;
i=0;
while (fin>>nr)
{
i++;
assert(0<nr && nr<=1000000000);
for (x=1; x<=1000; x++) if (x*(x+1)*(x+2)/2==nr) break;
assert (x<=1000);
lg=0;
while (nr)
{v[lg++]=nr%10; nr/=10; }
for (j=lg-1; j>=0; j--) s[poz++]=v[j]+’0’;
}
assert(i==n);
fout<<s[0]<<’ ’;
last[0]=s[0]; last[1]=0; st=1; dr=poz-1; lglast=1;
while (1)
{
while (s[dr]==’0’ && st<=dr) dr--;
if (st<=dr) {crt[0]=s[dr--]; crt[1]=0; lgcrt=1;}
else break;
while (compar(last,lglast,crt,lgcrt)>=0 && st<=dr)
{crt[lgcrt++]=s[dr--]; crt[lgcrt]=0; }
if (compar(last,lglast,crt,lgcrt)<0)
{
fout<<crt<<’ ’;
strcpy(last,crt); lglast=lgcrt;
}
else break;
while (s[st]==’0’ && st<=dr) st++;
if (st<=dr) {crt[0]=s[st++]; crt[1]=0; lgcrt=1;}
else break;
return 0;
}
int compar (char a[], int lga, char b[], int lgb)
{int i;
if (lga<lgb) return -1;
if (lga>lgb) return 1;
for (i=0; i<lga && a[i]==b[i]; i++);
if (i==lga) return 0;
if (a[i]<b[i]) return -1;
return 1;
}
CAPITOLUL 19. ONI 2019 19.1. DOMINO 230
#include <fstream>
#include <cstring>
ifstream in("domino.in");
ofstream out("domino.out");
int n,C,v[MAXN];
nat S[MAXS];
char s[MAXB],c[12],a[MAXB],b[MAXB];
void citire()
{
in>>C>>n;
if(C==1)
{ for (int i=1; i<=n; ++i)
in>>v[i];
for (int i=1; i<=1000; ++i) S[i]=S[i-1]+nat(i)*(i+1)/2*3;
}
else
for (int i=1; i<=n; ++i)
{in>>c;
strcat(s,c);
}
}
void P1()
{
for (int i=1; i<=n; ++i)
out<<S[v[i]]<<’ ’;
}
void P2()
{
int i=1,j=strlen(s)-1,p=2,nc=1;
a[0]=s[0];a[1]=’\0’;
out<<a<<’ ’;
while(i<=j){
if(p%2){
while(s[i]==’0’)i++;
if(i+nc<=j+1)
{ strncpy(b,s+i,nc);b[nc]=’\0’;
if(strcmp(a,b)>=0)
{ nc++;strncpy(b,s+i,nc);b[nc]=’\0’;}
}else return;
i+=nc;
}else {
//out<<i<<’*’<<j<<’\n’;
while(j>=i&&s[j]==’0’)j--;
if(i+nc<=j+1)
{ for(int k=0;k<nc;++k)
b[k]=s[j--];
b[nc]=’\0’;//out<<’*’<<b<<’\n’;
if(strcmp(a,b)>=0)
{ if(i>j) return;
b[nc++]=s[j--];b[nc]=’\0’;
}
}
}
if(strcmp(a,b))out<<b<<’ ’;
strcpy(a,b);
p++;
}
}
int main()
CAPITOLUL 19. ONI 2019 19.2. TUBURI 231
{
citire();
if(C==1) P1();
else P2();
return 0;
}
19.2 tuburi
Problema 2 - tuburi 100 de
puncte
Pe un perete au fost montate n m piese pe n
rânduri (numerotate de sus ı̂n jos, de la 1 la n) şi m
coloane (numerotate de la stânga la dreapta, de la 1 la
m). Piesele sunt tuburi sau coturi având unul dintre
tipurile 1, 2, ..., 6, conform imaginii alăturate.
Ionel poate introduce o bilă ı̂ntr-o piesă situată pe
rândul 1, doar dacă piesa este de tip 2, 4 sau 6. Bila
poate coborı̂ un nivel sau se poate deplasa pe orizontală Figura 19.3: joc1
ı̂ntr-o piesă alăturată, dacă ı̂mbinarea pieselor permite aceasta, dar nu poate urca, din cauza
gravitaţiei. Bila nu poate trece de două ori prin aceeaşi piesă şi se blochează atunci când nu se
mai poate deplasa ı̂ntr-o altă piesă.
Cerinţe
Se citesc două numere naturale n, m şi apoi n m numere din mulţimea r1, 2, 3, 4, 5, 6x
reprezentând dispunerea pieselor pe perete. Scrieţi un program care să rezolve următoarele cerinţe:
1. determină numărul maxim de piese prin care poate trece până la blocare o bilă introdusă
ı̂n una dintre piesele de pe rândul 1, având tipul 2, 4 sau 6;
2. pentru un rând k dat, determină numerele c şi t, unde c este coloana minimă pentru care,
ı̂nlocuind piesa existentă pe rândul k şi coloana c cu o piesă de tipul t, se obţine un număr cât
mai mare posibil de piese prin care poate trece, până la blocare, o bilă introdusă ı̂n una dintre
piesele de pe rândul 1 având tipul 2, 4 sau 6; dacă există mai multe soluţii de a ı̂nlocui piesa de
pe rândul k şi coloana c, se alege varianta cu t minim.
Date de intrare
Fişierul de intrare tuburi.in conţine pe prima linie un număr natural C reprezentând cerinţa
care trebuie să fie rezolvată (1 sau 2), pe a doua linie numerele naturale n, m, reprezentând
dimensiunile peretelui. Pe fiecare dintre următoarele n linii se află câte m numere aparţinând
mulţimii r1, 2, 3, 4, 5, 6x reprezentând ı̂n ordine tipurile pieselor de pe perete. Dacă cerinţa este
C 2, fişierul de intrare conţine ı̂n plus, pe a n 3-a linie, un număr natural k reprezentând
numărul unui rând de piese. Valorile scrise pe aceeaşi linie sunt separate prin câte un spaţiu.
Date de ieşire
Exemple
Cerinta 1: se determina pentru fiecare coloana j din multimea de indici {1, 2, ...,
numarul de piese prin care poate trece bila introdusa in piesa de pe randul 1, colo
daca aceasta este de tipul 2, 4 sau 6 si apoi maximul dintre valorile obtinute. In
rezolvarii cerintei doi, pe parcursul determinarii traseelor posibile, pentru fieca
pozitie (i,j) se retine intr-o matrice suplimentara coloana in care a fost introdus
pe randul 1, pentru a ajunge in acea pozitie, respectiv, valoarea 0 daca niciun tra
trece prin acea piesa.
Cerinta 2:
Pentru k=1 se plaseaza in fiecare coloana j, pe rand cate o piesa de orice tip si s
determina lungimea maxima a unui traseu posibil al bilei pana la blocare.
ifstream in("tuburi.in");
ofstream out("tuburi.out");
int n,m,lm,p,r,k=0;
int a[Nmax][Nmax],C[Nmax][Nmax];
void citire()
{
in>>p>>n>>m;
for (int i=1; i<=n; ++i)
for (int j=1; j<=m; ++j)
if(in>>a[i][j])++k;
for (int j=1; j<=m; ++j)
if (a[1][j]%2==0)
C[1][j]=j;
}
int main()
{
int j, l;
citire();
for (j=1; j<=m; j++)
if (a[1][j]%2==0)
{
l=lungime(1,j,0);
if (l>lm) lm=l;
}
if(p==1) out<<lm<<’\n’;
else
{
int t,tc,c,aux,caz;
in>>r;
CAPITOLUL 19. ONI 2019 19.2. TUBURI 234
ifstream in("tuburi.in");
ofstream out("tuburi.out");
int n,m,lm,p,r,k=0;
int a[Nmax][Nmax],C[Nmax][Nmax];
void citire()
{
in>>p>>n>>m;
for (int i=1; i<=n; ++i)
for (int j=1; j<=m; ++j)
if(in>>a[i][j])++k;
for (int j=1; j<=m; ++j)
if (a[1][j]%2==0)
C[1][j]=j;
}
else
{
if (a[i][j-1]==1 || a[i][j-1]==5)
{jj=j;j--;l++;g=1;}
}break;
case 6:
if (a[i][j-1]==5 || a[i][j-1]==1)
{jj=j;j--;l++;g=1;}
}
if(k==0) C[i][j]=col;
}
while (g);
return l;
}
int main()
{
int j, l, lmv;
citire();
for (j=1; j<=m; j++)
if (a[1][j]%2==0)
{
l=lungime(1,j,0);
if (l>lm) lm=l;
}
lmv=lm;
if(p==1) out<<lm<<’\n’;
else
{
int t,tc,c,aux,caz;
in>>r;
lm=0;
for (j=1; j<=m; j++)
{ aux=a[r][j];
for (tc=1; tc<=6; ++tc)
{ a[r][j]=tc;
if(tc%2==0)
if(r>1) l=lungime(1,C[r-1][j],r);
else l=lungime(1,j,r);
else if(tc==1) l=lungime(1,C[r][j+1],r);
else if(tc==3) l=lungime(1,C[r][j-1],r);
else
{ l=lungime(1,C[r][j-1],r);
if (l>lm)
{lm=l;c=j;t=tc;}
l=lungime(1,C[r][j+1],r);
}
if (l>lm)
{lm=l;c=j;t=tc;}
}
a[r][j]=aux;
}
out<<c<<’ ’<<t<<’\n’;
} return 0;
}
19.3 venus
Problema 3 - venus 100 de puncte
Casa de Modă Venus a decis să se modernizeze şi, ı̂ncepând cu 1 ianuarie 2020 ora 00 00,
l-a angajat pe robotul Vasile. Vasile poate executa orice comandă ı̂n exact T ore, indiferent de
complexitatea acesteia (mai exact, dacă Vasile ı̂ncepe să lucreze la comandă ı̂n momentul x, la
momentul x T ore comanda va fi gata de predare). Foarte ı̂ncrezătoare ı̂n calităţile robotului
Vasile, Casa de Modă Venus a lansat o campanie publicitară cu sloganul ”Dacă am ı̂ntârziat,
primeşti produsul comandat gratis!”. Campania şi-a atins scopul, ca urmare Casa de Modă a
primit deja N comenzi pentru ı̂ntreg anul 2020. Pentru fiecare comandă sunt specificate valoarea
acesteia, precum şi data şi ora până la care produsul comandat trebuie să fie gata de predare.
CAPITOLUL 19. ONI 2019 19.3. VENUS 236
Dacă Vasile predă produsul exact la data şi ora specificată ı̂n comandă (sau ı̂nainte) el ı̂ncasează
valoarea comenzii. Dacă nu, el tot trebuie să execute comanda respectivă, dar nu va primi suma
reprezentând valoarea ei.
Deşi lucrează fără nicio pauză, Vasile estimează că este posibil să nu poată preda la timp
toate comenzile, dar ı̂şi planifică lucrul, astfel ı̂ncât pierderea să fie minimă (adică suma valorilor
comenzilor care nu vor fi predate la timp să fie cât mai mică). Numim planificare optimală
succesiunea ı̂n care Vasile trebuie să execute cele N comenzi, astfel ı̂ncât pierderea să fie minimă.
Cerinţe
Scrieţi un program care, cunoscând informaţiile referitoare la cele N comenzi, determină
pierderea minimă, precum şi o planificare optimală.
Date de intrare
Fişierul de intrare venus.in conţine pe prima linie numărul natural N , reprezentând numărul
de comenzi şi numărul natural T , reprezentând numărul de ore necesare lui Vasile pentru a executa
o comandă. Pe următoarele N linii se află informaţiile despre comenzi, câte o comandă pe o linie,
sub forma:
V zi luna ora
unde V este valoarea comenzii, zi este ziua ı̂n care trebuie predată comanda (un număr natural
cuprins ı̂ntre 1 şi numărul de zile ale lunii), luna este denumirea lunii, iar ora este un număr natural
cuprins ı̂ntre 0 şi 23. Valorile scrise pe aceeaşi linie sunt separate prin câte un spaţiu.
Comenzile se consideră numerotate de la 1 la N ı̂n ordinea din fişierul de intrare.
Date de ieşire
Fişierul de ieşire venus.out va conţine pe prima linie numărul natural pmin, reprezentând
pierderea minimă. Pe a doua linie vor fi scrise N numere naturale distincte cuprinse ı̂ntre 1 şi N ,
separate prin câte un spaţiu, reprezentând o planificare optimală.
Restricţii şi precizări
a 1 & N & 1000
a 1 & T & 500
a 1 & V & 10000
a Numele lunilor vor fi scrise cu litere mici. Anul 2020 este an bisect, adică luna februarie are
29 de zile.
a Dacă există mai multe planificări optimale, se va accepta orice soluţie corectă.
a Se acordă 50% din punctajul pentru fiecare test pentru determinarea valorii pmin. Punctajul
integral pentru fiecare test se acordă pentru rezolvarea ambelor cerinţe (pmin şi o planificare
optimală).
Exemple
Solutie alternativa,
ifstream fin("venus.in");
ofstream fout("venus.out");
int zl[12]={31,29,31,30,31,30,31,31,30,31,30,31};
int sz[12];
struct Comanda
{short int v, p, nr, tc; };
///v = valoare
///p=timpul pana la care trebuie predata comanda
///nr de ordine al comenzii
///tc=-1 daca comanda nu poate fi onorata la timp sau timpul curent de predare altfel
int n, lg, t;
Comanda C[NMAX];
int pmin;
int L[NMAX];
int main()
{int i, zi, ora, k, j, sch;
char luna[50];
Comanda aux;
fin>>n>>t;
if (i<=n)
{L[1]=i; lg=1; C[i].tc=t;
for (i++; i<=n; i++)
{///verific daca pot onora la timp comanda C[i]
///parcurg comenzile existente si verific care pot fi amanate
for (j=lg;
j>=1 && C[L[j]].tc+t<=C[L[j]].p && C[L[j]].p>=C[i].p;
j--);
{
for (k=lg; k>j; k--) {C[L[k]].tc+=t; L[k+1]=L[k];}
lg++;
L[j+1]=i;
C[i].tc=C[L[j]].tc+t;
}
else C[i].tc=-1;
}
}
pmin=0;
for (i=1; i<=n; i++)
if (C[i].tc==-1) pmin+=C[i].v;
fout<<pmin<<’\n’;
fout<<’\n’;
fout.close();
return 0;
}
ifstream cin("venus.in");
ofstream cout("venus.out");
struct comanda
{
int nr, v, h,nt;
} v[1001];
int main()
{
int zi,l,j,i,dmax=0;
char luna[15];
cin>>n>>t;
else v[i].nt=v[i].h/t;
tot+=v[i].v;
}
sort(v+1,v+n+1,comp);
mg=0;
tlm=366*24;
p[0]=1;
for(i=1;i<=n;++i)
if(!p[v[i].nt])
{
p[v[i].nt]=v[i].nr;
b[i]=true;
mg+=v[i].v;
}
else
{
j=v[i].nt;
while(j>0&&p[j])
j--;
if(j)
{
p[j]=v[i].nr;
b[i]=true;
mg+=v[i].v;
}
}
cout<<tot-mg<<’\n’;
for (i=1; i<=tlm; ++i)
if (p[i])
cout << p[i]<<’ ’;
return 0;
}
ONI 2018
20.1 evip
Problema 1 - evip 100 de puncte
Un număr natural n se numeşte număr VIP dacă este format din cel puţin două cifre, conţine
cel puţin o cifră impară şi cel puţin o cifră pară, iar toate cifrele impare sunt scrise ı̂naintea tuturor
celor pare. (VIP=Valori Impare Pare). De exemplu, 352, 7546 sunt numere VIP, iar 35, 468, 5483,
387 nu sunt numere VIP. Se numeşte SECVENŢĂ VIP ı̂ntr-un şir de cifre, o succesiune de cifre
(aflate pe poziţii consecutive ı̂n şir) care formează, ı̂n ordine, un număr VIP.
Cerinţe
Date de intrare
Fişierul evip.in conţine pe prima linie un număr natural c reprezentând cerinţa care trebuie
să fie rezolvată (1, 2 sau 3). Pe cea de a doua linie se află un şir de cifre nenule, neseparate prin
spaţiu, reprezentând, ı̂n ordine, elementele şirului.
Date de ieşire
Dacă cerinţa este c 1, atunci, pe prima linie a fişierului evip.out va fi scris un număr natural
reprezentând numărul de SECVENŢE VIP din şir.
Dacă cerinţa este c 2, atunci, pe prima linie a fişierului evip.out va fi scris un număr natural
reprezentând lungimea minimă a unui şir de cifre care conţine acelaşi număr de SECVENŢE VIP
ca şirul dat şi are toate cifrele impare situate ı̂naintea celor pare.
Dacă cerinţa este c 3, atunci, pe prima linie a fişierului evip.out va fi scris un număr natural
reprezentând suma tuturor numerelor ce se pot forma, astfel ı̂ncât fiecare număr să conţină toate
cifrele distincte ale celui mai mare număr VIP din şirul dat, fiecare cifră fiind folosită exact o dată,
şi nicio altă cifră diferită de acestea.
a Numărul de cifre de pe linia a doua a fişierului de intrare este cel puţin 2 şi cel mult 10 000.
a şirul conţine cel puţin o SECVENŢĂ VIP.
a Pentru teste valorând 30% din punctaj cerinţa este 1. Pentru teste valorând 30% din punctaj
cerinţa este 2. Pentru teste valorând 40% din punctaj cerinţa este 3.
241
CAPITOLUL 20. ONI 2018 20.1. EVIP 242
Exemple
evip.in evip.out Explicaţii
1 6 Sunt 6 SECVENŢE VIP ı̂n şirul dat:
413643623 136 (4 136 43623), 1364 (4 1364 3623), 36 (41364 36 23),
364 (41 364 3623), 36(41364 36 23), 362 (41364 362 3).
2 5 Şirul dat conţine 6 SECVENŢE VIP. Cel mai mic număr de cifre
413643623 dintr-un şir care conţine 6 SECVENŢE VIP şi are toate cifrele impare
situate ı̂naintea celor pare, este 5. Un exemplu de astfel de şir este
13246
3 1776 Cel mai mare număr VIP din şir este 1344. Cifrele distincte ale
413443623 acestui număr sunt {1,3,4}. Suma tuturor numerelor ce se pot scrie,
folosind, o singură dată, toate cifrele {1,3,4}, şi nicio altă cifră diferită
de acestea, este 1776. 134+143+314+341+413+431=1776
Timp maxim de executare/test: 0.1 secunde
Memorie: total 8 MB din care pentru stivă 8 MB
Dimensiune maximă a sursei: 10 KB
Cerinţa 1)
Se identifică secvenţele maximale, de cifre impare (impark ).
Fiecare astfel de secvenţă conţine impark park numere VIP.
Fie m numărul acestor secvenţe. Se calculează şi se afişează <
m
k 1 impark park .
Cerinţa 2)
Fie v numărul numerelor VIP aflate ı̂n şirul dat.
Lungimea celui mai scurt şir ce are toate cifrele impare ı̂naintea celor pare şi conţine axact
Ó
v numere VIP este dk dv , unde dk reprezintă cel mai mare divizor al lui v, 1 & dk & v,
k
v dk dv
k
Demonstraţie: ...
Cerinţa 3)
Se identifică cel mai mare număr VIP din şir şi se determină mulţimea cifrelor distincte utilizate
ı̂n scrierea acestuia rx1 , x2 , ..., xk x. ı̂n fiecare număr, trebuie să apară fiecare dintre cele k cifre
distincte.
Fiecare dintre cifrele acestei mulţimi se poate afla pe oricare dintre cele k poziţii.
Mai ı̂ntâi se calculează câte numere se pot forma cu cele k cifre. Dacă fixăm prima cifră pe
una dintre cele k poziţii, atunci cea de-a doua cifră poate ocupa oricare dintre cele k 1 poziţii
rămase ş.a.m.d. Penultimei cifre ı̂i rămân două poziţii, iar ultima cifră se aşează pe ultimul loc
rămas.
Notam acest număr cu nr k k 1 k 2 ... 2 1
Aşezând numerele unele sub altele, se observă că suma cifrelor de pe fiecare ordin este aceeaşi.
Notăm această sumă cu s. Mai mult, toate cele k cifre apar de acelaşi număr de ori pe oricare
ordin (al unităţilor, al zecilor, al sutelor, etc). Fiind nr numere ı̂n total
fiecare cifră va apărea
de nrk
ori ı̂n s.
Aşadar
=x s =x s
k k
=x
k
nr k k 1 ... 2 1
s k k k 1 ... 2 1 k
k i 1
k i 1 i 1
20.2 nxy
Problema 2 - nxy 100 de puncte
Se consideră N , un număr natural nenul. Dorim să-l scriem pe N ca suma a două numere
naturale nenule x şi y, astfel ı̂ncât suma cifrelor numerelor x şi y să fie maximă.
Cerinţe
Date de intrare
Fişierul de intrare nxy.in conţine pe prima linie numărul natural c, reprezentând cerinţa (1,
2 sau 3). Pe cea de a doua linie se află numărul natural N .
Date de ieşire
Fişierul de ieşire nxy.out va conţine o singură linie. Dacă c 1, pe prima linie va fi scris
un număr natural s, reprezentând suma maximă a cifrelor a două numere naturale nenule x şi y
pentru care x y N . Dacă c 2 sau c 3, pe prima linie vor fi scrise două numere naturale
nenule separate printr-un singur spaţiu, reprezentând soluţia pentru cerinţa respectivă (xmax
ymax pentru c 2, respectiv xmin ymin pentru c 3).
a 1 $ N & 1018
a Pentru teste valorând 20% din punctaj cerinţa este 1. Pentru teste valorând 40% din punctaj
cerinţa este 2. Pentru teste valorând 40% punctaj cerinţa este 3.
Exemple
nxy.in nxy.out Explicaţii
1 16 Suma maximă care se poate obţine adunând cifrele a două numere x
25 şi y pentru care x+y=25 este 16.
2 19 6 Suma maximă care se poate obţine adunând cifrele a două numere x şi
25 y pentru care x y 25 este 16. Perechea de numere xmax ' ymax
pentru care xmax ymax este maximă (13) şi pentru care suma
cifrelor este maximă este xmax 19 şi ymax 6.
3 16 9 Suma maximă care se poate obţine adunând cifrele a două numere x
25 şi y pentru care x y 25 este 16. Perechea de numere xmin ' ymin
pentru care xmin ymin este minimă (7) şi pentru care suma cifrelor
este maximă este xmin 16 şi ymin 9.
20.3 viitor
Problema 3 - viitor 100 de puncte
Staţiunea Xoni de pe insula Ixos are N magazine de ı̂ngheţată, aşezate unul lângă altul, pe
aceeaşi parte a străzii pietonale. Acestea sunt numerotate cu valori naturale de la 1 la N , ı̂n
ordinea aşezării pe stradă.
Magazinele sunt deţinute de K acţionari (numerotaţi de la 1 la K), fiecare dintre aceştia fiind
proprietarul unor magazine numerotate consecutiv. Un magazin poate avea mai mulţi acţionari.
Odată cu venirea verii, ı̂ncepe şi perioada concediilor, toţi acţionarii luându-şi concediul
ı̂mpreună, timp de M zile. ı̂nainte de a pleca ı̂n concediu, ei au discutat cu Transportel pentru a se
ocupa de aprovizionarea cu ı̂ngheţată a magazinelor lor. Acesta a decis, singur, să facă ı̂n fiecare
dintre cele M zile aprovizionarea unor magazine, numerotate şi acestea cu numere consecutive.
Cerinţe
Determinaţi, pentru fiecare acţionar numărul de magazine deţinute de către acesta care nu au
fost aprovizionate cu ı̂ngheţată ı̂n nicio zi din concediu.
Date de intrare
Prima linie a fişierului viitor.in conţine trei numere naturale N , M şi K separate prin câte
un spaţiu, cu semnificaţia de mai sus.
Fiecare dintre următoarele M linii conţine câte două numere naturale x şi y, separate printr-un
spaţiu. Numerele x y aflate pe cea de a i-a linie dintre cele M semnifică faptul că ı̂n ziua i sunt
aprovizionate cu ı̂ngheţată toate magazinele cu numerele de ordine x, x 1, ..., y.
Fiecare dintre următoarele K linii conţine câte două numere naturale a şi b, separate printr-un
spaţiu. Numerele a b situate pe a i-a linie dintre cele K semnifică faptul că proprietarul i este
acţionar la magazinele cu numerele a, a 1, a 2, ..., b.
Date de ieşire
Fişierul viitor.out va conţine K linii. Pe cea de a i-a linie se află numărul de magazine
deţinute de către acţionarul i, care nu au fost aprovizionate cu ı̂ngheţată ı̂n nicio zi din concediu.
Exemple
viitor.in viitor.out Explicaţii
10 3 2 1 Magazinul 7 nu a fost aprovizionat ı̂n nicio zi, fiind singu-
14 2 rul dintre cele deţinute de primul acţionar care nu primeşte
9 10 ı̂ngheţată ı̂n nicio zi.
36 Dintre magazinele deţinute de acţionarul 2, cele cu numerele 7
17 şi 8 nu primesc ı̂ngheţată ı̂n nicio zi.
4 10
Formal, problema spune că se dă un prim set de intevale pe axa Ox (fiecare dintre ele acoperă
valori naturale consecutive) şi se cer apoi informatii despre intervale dintr-un alt set: câte numere
naturale de pe axa Ox, incluse ı̂n intervalul dat, nu se află ı̂n niciun interval din primul set.
O soluţie poate fi următoarea: odată cu citirea unui interval din primul set, se marchează
ı̂ntr-un vector valorile naturale care se află ı̂n acel interval. Când avem intervale din al doilea
set, putem fie parcurge element cu element pentru a determina câte valori sunt nemarcate, fie
putem afla direct dacă ı̂n prealabil folosim un vector de sume parţiale pentru intervalul ı̂n care
am marcat. Această soluţie obţine punctaj parţial pentru că nu se ı̂ncadrează nici ı̂n timp nici ı̂n
memorie pentru datele maxime de la intrare.
O alta optimizare poate fi utilizarea tehnicii numită ”şmenul lui Mars” pentru evitarea par-
curgerii tuturor numerelor dintr-un interval dat din primul set.
O altă soluţie care permite obţinerea punctajului maxim este următoarea: Dupa ce intervalele
din primul set se sortează după extremitatea stângă, se poate determina unui alt şir de intervale,
disjuncte, reunind pe cele care se intersectează. Pentru aceasta se foloseşte un algoritm simplu:
avem setat un interval curent, iar intervalul la care am ajuns (ı̂n ordinea dată la intrare) produce
următoarele cazuri:
- intersectează intervalul curent şi nu ı̂l extinde la dreapta (doar acolo se poate extinde) - ı̂n
acest caz trecem la următorul interval;
- intersectează intervalul curent şi ı̂l extinde la dreapta - actualizăm extremitatea dreaptă a
intervalului curent şi trecem la următorul interval;
- nu intersectează intervalul curent (automat ı̂ncepe după extremitatea dreaptă a acestuia),
caz ı̂n care trecem ı̂n soluţie (reuniune) intervalul curent şi reiniţializăm intervalul curent cu acela
la care am ajuns cu parcurgerea.
Având intervalele disjuncte din reuniune, la fiecare interval din al doilea set putem localiza
intervalele din reuniune ı̂n jurul cărora se află extremităţile celui de la interogarea curentă prin
căutări binare. Folosindu-ne şi de un vector de sume parţiale, putem răspunde apoi direct la fiecare
interogare.
ONI 2017
21.1 carte
Problema 1 - carte 100 de puncte
În timpul activităţilor din ”Săptămâna Altfel” elevii clasei a VII-a doresc să ajute la organizarea
cărţilor din biblioteca şcolii. Fiecare carte este etichetată cu un cod care este exprimat printr-
un un şir de caractere distincte. Acestea pot fi cifrele 0, 1, ..., 9 şi primele zece litere mici ale
alfabetului englez a, b, ..., j.
Codul identifică ı̂n mod unic fiecare carte, adică nu vor exista două cărţi cu acelaşi cod, dar
şi genul literar din care acestea face parte. Cărţile din acelaşi gen literar au codul de identificare
format din aceleaşi caractere, distincte, dispuse ı̂n altă ordine.
Numim coduri pereche două coduri de identificare care au acelaşi număr de caractere şi care
diferă printr-un caracter. De exemplu, codurile 42a8 şi 2c8a sunt coduri pereche. Pe de altă parte,
codurile 42a8 şi 248a, respectiv 42ab şi 248c, nu sunt coduri pereche.
Cerinţe
Fiind dat şirul celor N coduri de identificare, scrieţi un program care să rezolve următoarele
cerinţe:
1) determină numărul de cărţi din cel mai numeros gen literar şi numărul de genuri literare
care au acest număr maxim de cărţi.
2) determină numărul de coduri, din şirul celor N , care sunt coduri pereche cu ultimul cod din
şir.
Date de intrare
Fişierul de intrare carte.in conţine pe prima linie un număr natural C. Pentru toate testele,
C poate lua numai valorile 1 sau 2. Pe a doua linie se află numărul N de cărţi din biblioteca şcolii,
iar pe următoarele N linii, câte un şir de caractere pe fiecare linie, ce reprezintă codul pentru
identificarea unei cărţi.
Date de ieşire
Dacă valoarea lui C este 1, se va rezolva numai cerinţa 1. ı̂n acest caz, fişierul de ieşire
carte.out conţine pe prima linie numărul maxim de cărţi de acelaşi gen literar, M AX, iar pe a
doua linie numărul de genuri literare care au exact M AX cărţi.
Dacă valoarea lui C este 2, se va rezolva numai cerinţa 2. ı̂n acest caz, fişierul de ieşire
carte.out conţine pe prima linie numărul de coduri pereche cu ultimul cod din şirul celor N .
Exemple
247
CAPITOLUL 21. ONI 2017 21.1. CARTE 248
Pentru fiecare cod de identificare se construieşte un număr natural ı̂n care pentru fiecare
caracter din codul de identificare se ia poziţia p din şirul ”0123456789abcdefghij” şi se adaugă
p
la număr valoarea 2 , astfel codurile de identificare care sunt formate din aceleaşi caractere vor
avea asociat acelaşi număr şi ı̂n continuare se foloseşte un vector de frecvenţe [0, 1, ..., 1 100 000],
1.100.000 % 2 .
20
2 12 3
De exemplu, pentru codul ”2b3” se formează numărul 2 2 2 4 4096 8 4108 (ı̂n
baza 2 este 1000000001100), deci codurile ”2b3” şi ”23b” au asociat acelaşi număr.
Cerinta 1
Se parcurge vectorul de frecvente, se găseşte valoarea maximă şi la final printr-o parcurgere
liniara a acestui vector se numără pe câte poziţii apare valoarea maximă.
Cerinta 2
Pentru ultimul cod de identificare se construieşte numărul asociat conform precizărilor descrise
anterior şi comparând acest număr cu celelalte numere asociate celorlalte coduri se verifică dacă
sunt coduri pereche cu ultimul cod (au aceeaşi lungime şi diferă prin exact un caracter).
int main()
{
freopen("carte.in", "r", stdin);
freopen("carte.out","w", stdout);
scanf("%d\n%d\n",&C,&N);
mx = 0;
j = 0;
while(j < n)
{
assert(isdigit(s[j]) || isalpha(s[j]) && s[j]<=’j’);
if(isdigit(s[j]))
x=s[j]-’0’;
else
x=s[j]-’a’ + 10;
mx |= 1<<x;
++j;
}
A[mx]++;
if(A[mx]==1)
ngen++;
if(C==1)
printf("%d\n%d\n", Max, nMax);
else
{
for(mx = 0; mx <= Vmax; mx++)
if(A[mx])
{
ed = mu ˆ mx;
nc=0;
do
{
ed &= ed-1;
nc++;
} while (ed);
nr=0;
cmx = mx;
do
{
cmx&= cmx-1;
nr++;
} while (cmx);
printf("%d\n", nrC);
}
return 0;
}
21.2 ghinde
Problema 2 - ghinde 100 de puncte
Scrat şi Scratte sunt două veveriţe devoratoare de ghinde. Ele trăiesc ı̂ntr-un stejar ı̂nalt şi
culeg ghinde din cele N ramuri ale acestuia. Veveriţele vor organiza un concurs: cine culege cele
mai multe ghinde ı̂n K ture. ı̂ntr-o tură, fiecare veveriţă se va deplasa de la vizuină până la o
ramură a stejarului, de unde va culege cât mai multe ghinde, dar nu mai mult de M ghinde, după
care va reveni ı̂n vizuină. Veveriţele vor efectua alternativ fiecare câte K ture, prima care ı̂ncepe
fiind Scratte.
Supărat că la concurs nu va ı̂ncepe primul, Scrat decide să se antreneze separat şi să vadă câte
ghinde ar culege ı̂n K ture, dacă ar fi singur.
Cerinţe
Date de intrare
Pe prima linie a fişierului ghinde.in se află un număr natural C. Pentru toate testele, C poate
lua numai valorile 1 sau 2.
Pe a doua linie se găsesc numerele N , M şi K reprezentând numărul de ramuri ale stejarului,
numărul maxim de ghinde culese la o tură, respectiv numărul de ture.
Pe următoarele N linii se găsesc numărul de ghinde de pe fiecare ramură ı̂n parte.
Date de ieşire
Dacă valoarea lui C este 1, se va rezolva numai punctul 1) din cerinţe. ı̂n acest caz, fişierul de
ieşire ghinde.out va conţine numărul total de ghinde cules ı̂n timpul antrenamentului de Scrat.
Dacă valoarea lui C este 2, se va rezolva numai punctul 2) din cerinţe. ı̂n acest caz, fişierul
de ieşire ghinde.out va conţine pe aceeaşi linie două numere naturale, separate printr-un spaţiu,
reprezentând ı̂n ordine, numărul de ghinde culese de Scratte respectiv Scrat, pe durata concursului.
Exemple
CAPITOLUL 21. ONI 2017 21.2. GHINDE 251
ifstream f("ghinde.in");
ofstream g("ghinde.out");
int main()
{
f>>C>>N>>M>>K;
if(C == 1)
{
if(nr>=K)
{
g<<1LL*K*M<<’\n’ ;
CAPITOLUL 21. ONI 2017 21.3. SUBMAT 252
return 0;
}
K -= nr;
rez =1LL * nr * M;
rez1 = (nr+1)/2*M;
rez2 = nr/2*M;
K = 2*K - nr;
return 0;
}
21.3 submat
Problema 3 - submat 100 de puncte
Se consideră o matrice A având N linii şi N coloane. Elementele acesteia aparţin mulţimii
r0, 1, 2x. Pe fiecare linie şi pe fiecare coloană valorile elementelor sunt dispuse crescător.
Fie două elemente din matrice situate pe linia i1 şi coloana j1 respectiv i2 şi j2 , unde i1 & i2
şi j1 & j2 . O submatrice a lui A, având colţurile stânga-sus şi dreapta-jos ı̂n i1 , j1 şi i2 , j2 ,
este formată din toate elementele situate pe linii cuprinse ı̂ntre i1 şi i2 , inclusiv, şi coloane ı̂ntre
j1 şi j2 , inclusiv. Numim submatrice constantă o submatrice a matricei A, având toate elementele
egale.
Cerinţe
Realizaţi un program care determină numărul maxim K de elemente pe care ı̂l are o submatrice
constantă a lui A şi numărul submatricilor constante formate din K elemente.
Date de intrare
În fişierul submat.in pe prima linie se găseşte numărul natural N . Pe următoarele N linii
câte o pereche de numere naturale, despărţite printr-un spaţiu:
- Primul număr de pe linia i 1 din fişier reprezintă numărul de ordine al primei coloane de
pe linia i din matricea A, unde elementul este egal cu 1. Dacă pe linia i nu apare niciun element
egal cu 1, acest număr are valoarea 0.
CAPITOLUL 21. ONI 2017 21.3. SUBMAT 253
- Al doilea număr de pe linia i 1 din fişier reprezintă numărul de ordine al primei coloane de
pe linia i din matricea A, unde elementul este egal cu 2. Dacă pe linia i nu apare niciun element
egal cu 2, acest număr are valoarea 0.
Date de ieşire
Fişierul de ieşire submat.out va conţine pe prima linie o pereche de numere naturale separate
printr-un spaţiu, reprezentând, ı̂n ordine, numărul maxim de elemente pe care ı̂l are o submatrice
constantă a lui A, respectiv numărul submatricilor constante formate din acest număr maxim de
elemente determinat.
Exemple
submat.in submat.out Explicaţii
8 12 6 Matricea corespunzătoare fişiereului de intrare este:
40 00011111
48 00011112
48 00011112
37 00111122
36 00111222
35 00112222
23 01222222
02 02222222
Numărul maxim de elemente al unei submatrici constante este
12.
Sunt 6 submatricile constante formate din 12 elemente, respec-
tiv cele având colţurile ı̂n: (1,1) şi (6,2); (1,4) şi (4,6); (1,4) şi
(3,7); (5,6) şi (8,8); (7,3) şi (8,8); (6,5) şi (8,8).
Stelian Ciurea
Pentru ı̂nceput determinăm submatricea cu număr maxim de elemente egale cu 2, apoi subma-
tricea cu număr maxim de elemente egale cu 0. Datorită particularităţii matricei (valori crescătoare
pe fiecare linie şi pe fiecare coloană), aceste determinări se pot face ı̂n O n, parcurgând cele două
şiruri de intrare.
Pentru a determina submatricea cu număr maxim de elemente egale cu 1, fixăm o linie - fie
ea linia i, apoi pentru toate liniile j, unde j ia valori de la i la n, calculăm numărul de elemente
egale cu 1 din submatricea aflată ı̂ntre liniile i si j şi coloanele determinate de prima valoare cu
un elemente egal cu 1 de pe linia i şi ultima coloană cu un element egal cu 1 de pe coloana j care
este coloana anterioara primei coloane care conţine un 2. Aceste două coloane se deduc din datele
de intrare referitoare la linia i, respectiv la linia j.
2
Pentru ı̂ncadrarea ı̂n timp pentru această etapă a algoritmului, care are complexitatea O n ,
sunt necesare anumite optimizări care ţin cont de dimensiunea submatricei de arie maximă deter-
minată până ı̂n acel moment şi de particularităţile matricei.
CAPITOLUL 21. ONI 2017 21.3. SUBMAT 254
ifstream f("submat.in");
//FILE * f = fopen("submat.in","rt");
ofstream g("submat.out");
//FILE * g = fopen("submat.out","wt");
int primacoloana1[nmax];
int primacoloana2[nmax];
int n,nrelemax=1,i,ctmax,nrelemcrt,j,poz;
int inaltime,latime;
int xi1, xi2, xj1, xj2;
int main()
{
f >> n;
//fscanf(f,"%ld",&n);
for (i=1;i<=n;i++)
f >> primacoloana1[i] >> primacoloana2[i];
//fscanf(f,"%ld%ld",&primacoloana1[i],&primacoloana2[i]);
for (i=1;i<=n;i++)
{
if (primacoloana2[i]==0)
continue;
latime = n - primacoloana2[i] + 1;
inaltime = n - i + 1;
nrelemcrt = inaltime * latime;
if (nrelemcrt == nrelemax)
{
ctmax++;
}
}
//cout << nrelemax << ’ ’ << ctmax << endl;
inaltime = i;
nrelemcrt = inaltime * latime;
//cout << i << ’ ’ << nrelemcrt << endl;
ctmax=0;
}
if (nrelemcrt == nrelemax)
{
ctmax++;
}
}
//cout << nrelemax << ’ ’ << ctmax << endl;
primacoloana1[i]=0;
for (i=1;i<=n;i++)
{
if (primacoloana1[i]==primacoloana1[i-1])
continue;
if (primacoloana1[i]==0)
continue;
xi1 = primacoloana1[i];
if (primacoloana2[i]!=0)
xi2 = primacoloana2[i] - 1;
else
xi2 = n;
for (j=max(i,i+hmin-1);j<=n;j++)
{
if (primacoloana1[j]==0)
break;
inaltime = j - i + 1;
xj1 = primacoloana1[j];
if (primacoloana2[j]!=0)
{
if (primacoloana2[j]<primacoloana1[i])
break;
xj2 = primacoloana2[j] - 1;
}
else
xj2 = n;
//cout << i << ’ ’ << j << ’ ’<< xi1 << ’ ’<< xi2 << ’ ’
// << xj1 << ’ ’ << xj2 <<endl;
ONI 2016
22.1 birouri
Problema 1 - birouri 100 de puncte
Arhi şi-a propus să extindă clădirea de birouri pe care a proiectat-
o iniţial pe un singur nivel numerotat cu 1, ı̂mpărţit ı̂n n n zone
pătratice de latură 1, fiecare corespunzând unui birou, prin constru-
irea mai multor niveluri. În colţurile tuturor birourilor se construiesc
grinzi de rezistenţă. Pentru a asigura rezistenţa ı̂ntregii clădiri, Arhi
va proiecta niveluri noi, numerotate cu 2, 3, ... atât timp cât conţin
cel puţin un birou şi sunt respectate următoarele patru reguli:
R1: fiecare nivel nou va fi proiectat sub forma unui dreptunghi sau Figura 22.1: birouri
pătrat de arie maximă pentru nivelele cu număr impar, respectiv, sub forma unui pătrat de arie
maximă pentru nivelele cu număr par;
R2: fiecare dintre colţurile zidurilor unui nivel nou trebuie plasat pe câte o grindă de rezistenţă
dintre două sau mai multe birouri de pe nivelul precedent;
R3: oricare două dintre colţurile zidurilor unui nivel nou vor fi plasate pe ziduri diferite (un
zid nu se poate suprapune ı̂n totalitate pe alt zid) şi cel puţin două vârfuri opuse ale unui nivel
nou se vor afla pe ziduri opuse ale nivelului precedent;
R4: orice porţiune de zid de pe nivelul k (k % 1), construită deasupra unui birou de pe nivelul
k 1, se va suprapune exact peste una dintre laturile biroului, sau ı̂l va străbate ı̂n diagonală.
Birourile de pe nivelul k (k % 1), vor fi construite exact deasupra celor de pe nivelul precedent,
astfel, nivelurile 2, 4 etc. vor avea lângă ziduri spaţii triunghiulare care nu vor aparţine niciunui
birou.
Numerele inscripţionate pe birouri ı̂n imaginea de mai sus, indică nivelul corespunzător
birourilor vizibile de deasupra clădirii.
Cerinţe
Date de intrare
Fişierul de intrare birouri.in conţine pe prima linie una dintre valorile 1 sau 2, reprezentând
cerinţa 1, dacă se cere determinarea numărului maxim de niveluri pe care le poate avea clădirea,
respectiv cerinţa 2, dacă se cere determinarea numărului total de birouri al clădirii cu număr
maxim de niveluri.
Linia a doua conţine un număr natural n (reprezentând lungimea fiecărui zid al primului nivel
al clădirii).
Date de ieşire
256
CAPITOLUL 22. ONI 2016 22.1. BIROURI 257
Fişierul de ieşire birouri.out conţine pe prima linie un număr natural reprezentând numărul
maxim de niveluri pe care le poate avea clădirea, dacă cerinţa a fost 1, respectiv un număr natural
reprezentând numărul total de birouri ale clădirii cu număr maxim de niveluri, dacă cerinţa a fost
2.
Exemple
birouri.in birouri.out Explicaţii
1 5 Exemplul corespunde imaginii de mai sus. Clădirea cu nivelul
10 de la bază de latură 10 va avea 5 niveluri.
Nivelul 6 nu se mai construieşte, deoarece nu ar conţine niciun
birou.
2 172 Clădirea cu 5 niveluri şi latura de la bază de lungime 10 are:
10 - pe primul nivel 100 birouri;
- pe nivelul doi 40 birouri;
- pe nivelul trei 24 birouri;
- pe nivelul patru 4 birouri;
- pe nivelul cinci 4 birouri.
100 + 40 + 24 + 4 + 4 = 172
#define in "birouri.in"
#define ou "birouri.out"
int main()
CAPITOLUL 22. ONI 2016 22.1. BIROURI 258
{
short c;
int i, ok;
ifstream f(in);
f>>c>>n;
f.close();
NrNiv = NrBirouri = 0;
lat = n;
lun = n;
ok = 1;
drept = 1;
do
{
NrNiv++;
if(drept)
{
if(lun == lat)
{
if(lat % 2 == 1)
ok = 0;
NrBirouri += lat*lat;
lat /= 2; lun = lat;
}
else
{
NrBirouri += lat*lun;
if(lun < lat) tmp = lun, lun = lat, lat = tmp;
if(lat % 2 == 1 || lun % 2 == 1)
ok = 0;
lat /=2; lun = lat;
}
}
else
{
NrBirouri += 2*(lat-1)*lat;
if(lat % 2 == 1)
lat = lat - 1, lun = lun + 1;
}
drept = !drept;
if(lat == 1 || lun == 1)
ok = 0;
} while(ok);
ofstream g(ou);
if(c == 1)
g<<NrNiv<<endl;
else
g<<NrBirouri<<endl;
g.close();
return 0;
}
ifstream f("birouri.in");
ofstream g("birouri.out");
int n,v,h,m;
long long p;
int main()
{
f>>v>>n;
m=n;
if(n&1)
{
h=1;
CAPITOLUL 22. ONI 2016 22.1. BIROURI 259
p=n*n;
}
else
while((n&1)+(m&1)<2)
{
p+=n*m;
h++;
n=min(n,m);
m=n=n/2;
if(n>=2)
{
p+=2*(n-1)*n;
h++;
if(n&1)
{ m=n+1;
n--;
}
}
}
if(v==1)
g<<h<<’\n’;
else
g<<p<<’\n’;
f.close();
g.close();
return 0;
}
ifstream in("birouri.in");
ofstream out("birouri.out");
int main()
{
in>>c>>n;m=n;
do
{
niv++;
if(niv%2)
b+=n*m;
else
{
k=n>m?m:n;
p=k*k/2-k;b+=p;
if(!p)niv--;
if (k%4==0)
n=m=k/=2;
else
{
n=n/2-1;
m=n+2;
}
}
} while(n&&n%2==0);
if(c==1)
out << niv << endl;
else
out << b << endl;
return 0;
}
CAPITOLUL 22. ONI 2016 22.2. CRISTALE 260
22.2 cristale
Problema 2 - cristale 100 de puncte
Pietrele preţioase au fascinat omenirea ı̂ncă din timpuri străvechi iar cele mai
renumite dintre ele, cristalele, au devenit atât simbolul durităţii cât şi al eternităţii.
În urma unui studiu ştiinţific, pe un eşantion de formă dreptunghiulară se pot ob-
serva diferite tipuri de molecule, dispuse ı̂ntr-o geometrie perfectă, pe M rânduri
a câte N molecule fiecare, aliniate una lângă alta. O formaţiune cristalizabilă este
alcătuită din 3 molecule de acelaşi tip, ı̂nvecinate două câte două, având una dintre cele patru
forme din imaginea alăturată (fig.1).
Fiecare formaţiune este ı̂nconjurată de jur-ı̂mprejur, ca ı̂n fig.2, de un ı̂nveliş
special format şi el din molecule identice, de alt tip decât cele din formaţiunea
cristalizabilă pe care o ı̂nconjoară şi o izolează de restul formaţiunilor moleculare. În
acest fel, fiecare moleculă din formaţiunea cristalizabilă se ı̂nvecinează la N ord, Sud,
Est şi V est cu o moleculă din aceeaşi formaţiune cristalizabilă sau cu o moleculă
din ı̂nvelişul special.
Fiecare formaţiune cristalizabilă se bombardează cu raze X şi ı̂n acest fel are loc
cristalizarea, proces prin care ı̂nvelişul special se extinde peste formaţiunea cristal-
izabilă pe care o ı̂nconjoară, formând o singură structură din care se va dezvolta
cristalul.
Cerinţe
Date de intrare
Fişierul de intrare cristale.in conţine pe prima linie un număr natural c reprezentând cerinţa
care trebuie să fie rezolvată (1 sau 2). Pe cea de-a doua linie se află două numere naturale M şi
N , separate printr-un spaţiu, având semnificaţia din enunţ. Pe următoarele M linii se află câte N
numere naturale, separate prin câte un spaţiu, reprezentând moleculele din eşantionul analizat.
Date de ieşire
Dacă valoarea lui c este 1, atunci se va rezolva numai cerinţa 1, caz ı̂n care pe prima linie a
fişierului cristale.out va fi scris un număr natural reprezentând numărul formaţiunilor cristaliz-
abile identificate pe eşantionul analizat.
Dacă valoarea lui c este 2, atunci se va rezolva numai cerinţa 2. ı̂n acest caz, fişierul de ieşire
cristale.out va conţine pe fiecare dintre primele M linii, câte N numere naturale separate prin
câte un spaţiu, reprezentând moleculele eşantionului rezultat după cristalizare.
a 4 & M, N & 800 şi tipul fiecărei molecule este exprimat printr-un număr natural din intervalul
1, 16;
a pe marginea eşantionului nu pot fi identificate formaţiuni cristalizabile;
a există cel puţin o formaţiune cristalizabilă pe eşantionul analizat;
a eşantionul nu conţine formaţiuni cristalizabile lipite (cu celule vecine pe una din cele patru
direcţii);
a pentru rezolvarea corectă a cerinţei 1 se acordă 30% din punctaj, iar pentru rezolvarea corectă
a cerinţei 2 se acordă 70% din punctaj.
CAPITOLUL 22. ONI 2016 22.2. CRISTALE 261
Exemple
cristale.in cristale.out Explicaţii
2 Se va rezolva cerinţa 1 a problemei.
Eşantionul are 6 rânduri cu câte 8 molecule pe fiecare
rând. Pe acest eşantion observăm o formaţiune cristal-
izabilă cu celule de tip 9, izolată de ı̂nvelişul special for-
mat din celule identice, toate de tip 6 şi o formaţiune
cristalizabilă cu celule de tip 7, izolată de ı̂nvelişul spe-
cial format din celule identice, toate de tip 4.
Formaţiunea de 3 molecule de tip 8 nu este o formaţiune
cristalizabilă ı̂ntrucât se află pe marginea eşantionului.
Se va rezolva cerinţa 2 a problemei.
După cristalizare, peste fiecare din cele două formaţiuni
cristalizabile identificate se extinde ı̂nvelişul din jurul
lor.
int main()
{
ifstream f(in);
CAPITOLUL 22. ONI 2016 22.2. CRISTALE 262
ofstream g(ou);
int cate;
f>>c>>m>>n;
for(i=1; i<=4; ++i)
for(j=1; j<=n; ++j)
f>>A[i][j];
cate = m-4;
/*
if(c == 2)
{
for(j=1; j<=n; ++j)
g<<A[1][j]<<’ ’;
g<<’\n’;
}
*/
while(cate>=0)
{
for(i=2; i<=3; ++i)
for(j=2; j<=n-2; ++j)
{
if( A[i][j] == A[i][j+1] &&
A[i][j] == A[i+1][j+1] &&
A[i][j] != A[i-1][j] ) //1
{
tmp = A[i-1][j];
if(A[i-1][j+1] == tmp && A[i][j-1] == tmp &&
A[i][j+2] == tmp && A[i+1][j] == tmp &&
A[i+1][j+2] == tmp && A[i+2][j+1] == tmp )
{
NrC++;
if(c <= 2) A[i][j] = A[i][j+1] = A[i+1][j+1] = tmp;
}
}
else
if( A[i][j] == A[i][j+1] && A[i][j] == A[i+1][j] &&
A[i][j] != A[i-1][j] ) //2
{
tmp = A[i-1][j];
if(A[i-1][j+1] == tmp && A[i][j-1] == tmp &&
A[i][j+2] == tmp && A[i+1][j-1] == tmp &&
A[i+1][j+1] == tmp && A[i+2][j] == tmp )
{
NrC++;
if(c <= 2) A[i][j] = A[i][j+1] = A[i+1][j] = tmp;
}
}
else
if( A[i][j] == A[i+1][j] && A[i][j] == A[i+1][j+1] &&
A[i][j] != A[i-1][j] ) //3
{
tmp = A[i-1][j];
if(A[i][j-1] == tmp && A[i][j+1] == tmp &&
A[i+1][j-1] == tmp && A[i+1][j+2] == tmp &&
A[i+2][j] == tmp && A[i+2][j+1] == tmp )
{
NrC++;
if(c <= 2) A[i][j] = A[i+1][j] = A[i+1][j+1] = tmp;
}
}
else
if( A[i][j+1] == A[i+1][j+1] && A[i][j+1] == A[i+1][j] &&
A[i][j+1] != A[i-1][j+1] ) //4
{
tmp = A[i-1][j+1];
if(A[i][j] == tmp && A[i][j+2] == tmp &&
A[i+1][j-1] == tmp && A[i+1][j+2] == tmp &&
A[i+2][j] == tmp && A[i+2][j+1] == tmp )
{
NrC++;
if(c <= 2) A[i][j+1] = A[i+1][j+1] = A[i+1][j] = tmp;
}
}
}
CAPITOLUL 22. ONI 2016 22.2. CRISTALE 263
if(c == 2)
{
for(j=1; j<=n; ++j)
g<<A[1][j]<<’ ’;
g<<’\n’;
}
if(c == 1)
g<<NrC<<’\n’;
else
{
for(i=1; i<=3; i++)
{
for(j=1; j<=n; ++j)
g<<A[i][j]<<’ ’;
g<<’\n’;
}
}
f.close();
g.close();
return 0;
}
#define ML 801
#define MC 801
ifstream f("cristale.in");
ofstream g("cristale.out");
return 0;
}
cf=p[li][co-1];
if((cp==p[li][co+1])&&
(cp==p[li+1][co])&&
(cp!=cf)&&
(cf==p[li-1][co])&&
(cf==p[li-1][co+1])&&
(cf==p[li][co+2])&&
(cf==p[li+1][co+1])&&
(cf==p[li+2][co])&&
(cf==p[li+1][co-1]))
{
p[li][co]=p[li][co+1]=p[li+1][co]=cf;
return 1;
}
return 0;
}
return 0;
}
return 0;
}
void afis4_linii()
{
int i,j;
for(i=2;i<=2;i++)
{
g<<’\n’;//fprintf(g,"\n");
for(j=1;j<=n-1;j++)
g<<p[i][j]<<’ ’;//fprintf(g,"%d ",p[i][j]);
g<<p[i][n];//fprintf(g,"%d",p[i][n]);
}
}
void copiere_linii_peste_cele_vechi()
CAPITOLUL 22. ONI 2016 22.2. CRISTALE 265
{
int j;
for(j=1;j<=n;j++)
{
p[1][j]=p[2][j];
p[2][j]=p[3][j];
p[3][j]=p[4][j];
}
}
int main()
{
int i,j,idf,k,c;
f>>c>>m>>n;
for(i=1;i<=4;i++)
for(j=1;j<=n;j++)
f>>p[i][j];
int nr_linii=3;
if(c==2)
{
for(j=1;j<=n-1;j++)
g<<p[1][j]<<’ ’;
g<<p[1][n];
}
do
{
i=2;
for (k=2;k<=n-1;k++) lu[k]=1;
{
for (k=2;k<=n-1;k++)
{
lc[k]=lu[k];
lu[k]=1;
}
for(j=2;j<=n-1;j++)
{
if(lc[j])
{
idf=1;
if(idf&&(j<n-1)&&f1(i,j))
{
np++;
lu[j]=lu[j+1]=lu[j+2]=0;
j+=2;
idf=0;
}
if(idf&&(j<n-1)&&f2(i,j))
{
np++;idf=0;
lu[j-1]=lu[j]=lu[j+1]=0;
j+=2;
}
if(idf&&(j<n-1)&&f3(i,j))
{
np++;idf=0;
lu[j-1]=lu[j]=lu[j+1]=lu[j+2]=0;
j+=1;
}
if(idf&&(j>2)&&f4(i,j))
{
np++;idf=0;
lu[j-2]=lu[j-1]=lu[j]=lu[j+1]=0;
j+=1;
}
}
}
}
CAPITOLUL 22. ONI 2016 22.2. CRISTALE 266
if(c==2)
afis4_linii();
copiere_linii_peste_cele_vechi();
for(j=1;j<=n;j++)
f>>p[4][j];
nr_linii++;
i=1;
} while(nr_linii<m);
if(c==2)
{
for(i=2;i<=3;i++)
{
g<<’\n’;
for(j=1;j<=n-1;j++)
g<<p[i][j]<<’ ’;
g<<p[i][n];
}
g<<’\n’;
}
else
if(c==1)
g<<np<<’\n’;
return 0;
}
char a[805][805],val;
int n,m,rez1,p;
ifstream f("cristale.in");
ofstream g("cristale.out");
void citeste()
{
f>>p>>n>>m;
int i,j,x;
for(i=1; i<=n;i++)
for(j=1;j<=m;j++)
{
f>>x;
a[i][j]=char(x+’0’);
}
}
return 0;
}
CAPITOLUL 22. ONI 2016 22.2. CRISTALE 267
// short int
val=a[i+1][j+1];
if ( a[i][j]==a[i][j+1] && a[i][j]==a[i+1][j] && a[i][j]!=val
&& a[i-1][j]==val && a[i-1][j+1]==val && a[i][j-1]==val
&& a[i][j+2]==val && a[i+1][j-1]==val && a[i+2][j]==val )
{
a[i][j]=a[i][j+1]=a[i+1][j+1]=a[i+1][j]=val;
return 1;
}
return 0;
}
// short int
val=a[i][j-1];
if ( a[i][j]==a[i+1][j-1] && a[i][j]==a[i+1][j] && a[i][j]!=val
&& a[i-1][j]==val && a[i][j+1]==val&& a[i+1][j-2]==val
&& a[i+1][j+1]==val && a[i+2][j]==val && a[i+2][j-1]==val )
{
a[i][j]=a[i+1][j]=a[i][j-1]=a[i+1][j-1]=val;
return 1;
}
return 0;
}
// short int
val=a[i][j+1];
if ( a[i][j]==a[i+1][j+1] && a[i][j]==a[i+1][j] && a[i][j]!=val
&& a[i-1][j]==val && a[i][j-1]==val && a[i+1][j-1]==val
&& a[i+1][j+2]==val && a[i+2][j]==val && a[i+2][j+1]==val )
{
a[i][j]=a[i][j+1]=a[i+1][j+1]=a[i+1][j]=val;
return 1;
}
return 0;
}
void sol()
{
int i,j;
citeste();
for(i=2; i<=n-1;i++)
for(j=2;j<=m-1;j++)
if(tip1(i,j))
rez1++;
else
if(tip2(i,j))
rez1++;
else
if(tip3(i,j))
rez1++;
else
if(tip4(i,j))
rez1++;
CAPITOLUL 22. ONI 2016 22.2. CRISTALE 268
if(p==1)
g<<rez1<<endl;
else
for(i=1; i<=n;i++)
{
for(j=1;j<=m;j++)
g<<a[i][j]-’0’<<" ";
g<<endl;
}
}
int main()
{
sol();
return 0;
}
int v,m,n,i,j,cr;
ifstream f("cristale.in");
ofstream g("cristale.out");
short a[4][1502];
void muta()
{
int i,j;
for(i=0;i<4;i++)
for(j=0;j<n;j++)
a[i][j]=a[i+1][j];
for(j=0;j<n;j++)
f>>a[3][j];
}
void afis(int i)
{
for(int j=0;j<n;j++)
g<<a[i][j]<<’ ’;
g<<’\n’;
}
switch(k)
{
case 1: return (j<n-2 && a[i][j]!=x && a[i-1][j+1]==x &&
a[i][j+2]==x && a[i+1][j+1]==x && a[i+2][j]==x &&
a[i+1][j-1]==x && a[i][j-1]==x);
case 2: return (j<n-2 && a[i][j]!=x && a[i-1][j+1]==x &&
a[i][j+2]==x && a[i+1][j+2]==x && a[i+2][j+1]==x &&
a[i+1][j]==x && a[i][j-1]==x);
case 3: return (j<n-2 && a[i][j]!=x && a[i][j+1]==x &&
a[i+1][j+2]==x && a[i+2][j+1]==x && a[i+2][j]==x &&
a[i+1][j-1]==x && a[i][j-1]==x);
case 4: return (j>1 && a[i][j]!=x && a[i][j+1]==x &&
a[i+1][j+1]==x && a[i+2][j]==x && a[i+2][j-1]==x &&
a[i+1][j-2]==x && a[i][j-1]==x);
}
void numara(int i)
{
for(int j=1;j<n-1;j++)
CAPITOLUL 22. ONI 2016 22.2. CRISTALE 269
if(a[i][j]-a[i][j+1]==0&&a[i][j]-a[i+1][j]==0)
cr+=este_cristal(i,j,1);
else
if(a[i][j]-a[i][j+1]==0 && a[i][j]-a[i+1][j+1]==0)
cr+=este_cristal(i,j,2);
else
if(a[i][j]-a[i+1][j]==0 && a[i][j]-a[i+1][j+1]==0)
cr+=este_cristal(i,j,3);
else
if(a[i][j]-a[i+1][j]==0 && a[i][j]-a[i+1][j-1]==0)
cr+=este_cristal(i,j,4);
}
switch(k)
{
case 1:
{
if(j<n-2 && a[i][j]!=x && a[i-1][j+1]==x && a[i][j+2]==x &&
a[i+1][j+1]==x && a[i+2][j]==x && a[i+1][j-1]==x && a[i][j-1]==x)
a[i][j]=a[i][j+1]=a[i+1][j]=x;
break;
}
case 2:
{
if(j<n-2 && a[i][j]!=x && a[i-1][j+1]==x && a[i][j+2]==x &&
a[i+1][j+2]==x && a[i+2][j+1]==x && a[i+1][j]==x && a[i][j-1]==x)
a[i][j]=a[i][j+1]=a[i+1][j+1]=x;
break;
}
case 3:
{
if(j<n-2 && a[i][j]!=x && a[i][j+1]==x && a[i+1][j+2]==x &&
a[i+2][j+1]==x && a[i+2][j]==x && a[i+1][j-1]==x && a[i][j-1]==x)
a[i][j]=a[i+1][j]=a[i+1][j+1]=x;
break;
}
case 4:
{
if (j>1 && a[i][j]!=x && a[i][j+1]==x && a[i+1][j+1]==x &&
a[i+2][j]==x && a[i+2][j-1]==x && a[i+1][j-2]==x && a[i][j-1]==x)
a[i][j]=a[i+1][j]=a[i+1][j-1]=x;
break;
}
}
}
void cristalizeaza(int i)
{
for(int j=1;j<n-1;j++)
if(a[i][j]-a[i][j+1]==0&&a[i][j]-a[i+1][j]==0)
cristalizare(i,j,1);
else
if(a[i][j]-a[i][j+1]==0 && a[i][j]-a[i+1][j+1]==0)
cristalizare(i,j,2);
else
if(a[i][j]-a[i+1][j]==0 && a[i][j]-a[i+1][j+1]==0)
cristalizare(i,j,3);
else
if(a[i][j]-a[i+1][j]==0 && a[i][j]-a[i+1][j-1]==0)
cristalizare(i,j,4);
}
void solve1()
{
int i,j;
for(i=0;i<4;i++) for(j=0;j<n;j++)
f>>a[i][j];
numara(1);
while(i<m)
CAPITOLUL 22. ONI 2016 22.3. PARCHET 270
{
muta();
numara(1);
i++;
}
g<<cr<<’\n’;
}
void solve2()
{
int i, j;
for(i=0;i<4;i++)
for(j=0;j<n;j++)
f>>a[i][j];
cristalizeaza(1);
afis(0);
afis(1);
afis(2);
afis(3);
}
int main()
{
f>>v>>m>>n;
if(v==1)
solve1();
else
solve2();
f.close();
g.close();
return 0;
}
22.3 parchet
Problema 3 - parchet 100 de puncte
Meseria de parchetar a devenit mai uşoară de când a apărut parchetul laminat. Acesta se
2
livrează ı̂n plăci pătratice de câte 1 m şi montarea lui este destul de uşoară. Gigel este convins
că este suficient de priceput să facă această operaţie ı̂n propria locuinţă. El dispune de planul
2
locuinţei şi a cumpărat o anumită cantitate reprezentând X m de parchet laminat. Planul
locuinţei este descris printr-un tablou bidimensional de dimensiuni N x M, fiecare element al
2
tabloului reprezentând exact 1 m . Pereţii sunt reprezentaţi prin caracterul ’P’ iar suprafeţele
camerelor prin caracterul ’S’ (spaţiu).
În planul din figura alăturată este descrisă o locuinţă cu 5 camere acestea având
2
respectiv, suprafeţele de 10, 2, 1, 3, 5 m .
Gigel nu este sigur de faptul că parchetul cumpărat ı̂i ajunge. Din această
cauză a hotărât iniţial să pună parchetul ı̂ncepând cu camera cea mai mare, apoi
ı̂n următoarea, ı̂n ordinea descrescătoare a suprafeţei şi aşa mai departe, până ı̂n
momentul ı̂n care parchetul rămas nu mai este suficient pentru acoperirea suprafeţei
următoarei camere. Nu va lăsa neparchetată o cameră pentru a parcheta una cu
CAPITOLUL 22. ONI 2016 22.3. PARCHET 271
o suprafaţă mai mică. Gigel se mai gândeşte şi la posibilitatea de a acoperi complet un număr
maxim de camere folosind ı̂ntreaga cantitate de parchet.
Cerinţe
Date de intrare
Fişierul de intrare parchet.in conţine pe prima linie un număr natural p reprezentând cerinţa
care trebuie să fie rezolvată (1 sau 2). Linia a doua a fişierului de intrare conţine numerele naturale
N şi M separate printr-un spaţiu. Pe linia a treia se află numărul natural X. Următoarele N linii
¬ ¬ ¬ ¬
conţin câte M caractere P şi S descriind planul locuinţei.
Date de ieşire
Dacă valoarea lui p este 1, atunci fişierul de ieşire parchet.out conţine pe prima linie două
numere naturale C şi R separate printr-un spaţiu, reprezentând respectiv numărul de camere
2
acoperite cu parchet şi cantitatea de parchet rămasă, exprimată ı̂n m . Dacă valoarea lui p este
2, atunci pe prima linie a fişierului de ieşire se va scrie numărul de posibilităţi de parchetare a
unui număr maxim de camere folosind ı̂ntreaga cantitate de parchet, respectiv valoarea 0 ı̂n cazul
ı̂n care acest lucru nu este posibil.
Exemple
parchet.in parchet.out Explicaţii
1 31 Se va rezolva doar cerinţa 1.
2
79 Locuinţa are 5 camere având suprafeţele de 10, 2, 1, 3, 5 m .
19 Pot fi parchetate complet 3 camere consumând 18 = 10+5+3
2 2
PPPPPPPPP m . Rămâne 1 m de parchet nefolosit.
PSSSPSPSP
PSSSPSPPP
PSSPPPPSP
PSPPSSPSP
PSPSSSPSP
PPPPPPPPP
2 1 Se va rezolva doar cerinţa 2.
79 Dacă se aleg camerele cu suprafeţele 10, 1, 3, 5 va fi folosită
19 ı̂ntreaga suprafaţă de parchet. Există o singură posibilitate de
PPPPPPPPP a selecta un număr maxim de camere.
PSSSPSPSP
PSSSPSPPP
PSSPPPPSP
PSPPSSPSP
PSPSSSPSP
PPPPPPPPP
int main()
{
char linie[Nmax];
unsigned int i,j, k, ok, ii, jj,t, nr;
unsigned int sup, pus, putere;
ifstream f(in);
f>>v>>n>>m>>p;
f.get();
sup = 0;
for(i=1; i<=n; ++i)
{
f.get(linie,m+1);
f.get();
//cout<<linie<<endl;
for(j=0; j<m; ++j)
if(linie[j] == ’P’)
A[i][j+1] = -1;
else
A[i][j+1] = 0;
}
f.close();
NrCam = 0;
while(ok)
{
ok = 0; //cout<<ii<<’ ’<<jj<<endl;
if( A[ii+1][jj] == 0) ok = jj ;
A[ii][jj] = NrCam;
sup++;
CAPITOLUL 22. ONI 2016 22.3. PARCHET 274
ii++;
jj = ok;
}
S[NrCam] = sup;
}
ofstream g(ou);
//unesc camerele
for(i=1; i<=NrCam; ++i)
C[i] = i;
for(i=2; i<n; ++i)
for(j=2; j<m; ++j)
{
if( A[i][j] != -1 && A[i-1][j] != -1 &&
A[i][j] != A[i-1][j] && C[ A[i][j] ] != C [ A[i-1][j] ] )
uneste( C[ A[i][j] ], C[ A[i-1][j] ]);
//sortez descrescator
for(i=1; i<1000; ++i)
for(j=i+1; j<=1000; ++j)
if(ST[i]<ST[j])
t = ST[i], ST[i] = ST[j], ST[j] = t;
while( ST[NrCam] == 0)
NrCam--;
//cerinta 1
pus = 0;
cam = 0;
while(pus <= p && S[cam+1] <= p-pus)
pus +=S[cam+1], cam++;
if( v == 1)
{
if(NrCam == 1 && S[1]<=p)
g<<1<<’ ’<<p-pus<<’\n’;
else
g<<cam<<’ ’<<p-pus<<’\n’;
}
if( v == 2)
{
//cerinta 2
putere = 1;
pus = 0;
for(i=1; i<=NrCam; ++i)
x[i] = 0, putere *=2, pus +=S[i] ;
putere/=2;
if(pus == p)
g<<"1\n";
else
CAPITOLUL 22. ONI 2016 22.3. PARCHET 275
{
maxim = 0; nrmaxim = 0;
for(k = 1; k<putere; ++k)
{
t = 1;
pus = 0;
for(j=1; j<=NrCam && t; ++j)
ii = x[j] + t, x[j] = ii % 2, t = ii / 2;
nr = 0;
for(j=NrCam; j>=1; --j)
if(x[j]==1)
pus += S[j], nr++;
if(pus == p)
if(nr > maxim)
maxim = nr, nrmaxim = 1;
else
if(nr == maxim)
nrmaxim++;
nr = 0;
pus = 0;
for(j=NrCam; j>=1; --j)
if(x[j]==0)
pus += S[j], nr++;
if(pus == p)
if(nr > maxim)
maxim = nr, nrmaxim = 1;
else
if(nr == maxim)
nrmaxim++;
}
g<<nrmaxim<<endl;
}
}
g.close();
return 0;
}
ifstream f("parchet.in");
ofstream g("parchet.out");
int n,m,p,P,i,j,k,cate,numar;
char a[255][255];
int c[21],sum[21],nr[21],nrp,di[]={-1,0,1,0},dj[]={0,1,0,-1},cer;
void numara(int t)
{
for(int v=0;v<=1;v++)
CAPITOLUL 22. ONI 2016 22.3. PARCHET 276
{
nr[t]=nr[t-1]+v;
sum[t]=sum[t-1]+v*c[t];
if(sum[t]==P)
if(nr[t]>numar)
{
numar=nr[t];
cate=1;
}
else
{
if(nr[t]==numar)
cate++;
}
else
if(t<k && sum[t]<P)
numara(t+1);
}
}
int main()
{
f>>cer>>n>>m>>P;
for(i=0;i<n;i++)
{
f>>a[i];
for(j=1;j<m-1;j++)
if(a[i][j]==’S’)
nrp++;
}
if(nrp==(n-2)*(m-2))
if(cer==1)
{
g<<1<<’ ’;
if(P>=nrp)
g<<P-nrp<<’\n’;
else
g<<P<<’\n’;
}
else
if(P!=nrp)
g<<0<<’\n’;
else
g<<1<<’\n’;
else
{
for(i=1;i<n-1;i++)
for(j=1;j<m-1;j++)
if(a[i][j]==’S’)
{
cate=0;
sterge(i,j);
c[++k]=cate;
}
sort(c+1,c+k+1);
i=k;
while(i>0 && p+c[i]<=P)
{
p=p+c[i];
i--;
}
if(cer==1)
g<<k-i<<’ ’<<P-p<<’\n’;
else
{
cate=0;
while(k>0 && c[k]>P)
k--;
numara(1);
g<<cate<<’\n’;
}
CAPITOLUL 22. ONI 2016 22.3. PARCHET 277
f.close();
g.close();
return 0;
}
ifstream fin("parchet.in");
ofstream fout("parchet.out");
void Citire()
{
int i, j;
char X[255];
Casa[l][c] = nr;
sc++;
C[sc].lin = l;
C[sc].col = c;
return S;
}
void Suprafete_camere()
CAPITOLUL 22. ONI 2016 22.3. PARCHET 278
{
int i, j;
for (i = 2; i < N; ++i)
for (j = 2; j < M; ++j)
if (Casa[i][j] == 0) //camera goala - inca neprelucrata
{
nr_camere++;
Camere[nr_camere] = Suprafata(i, j, nr_camere);
}
}
void Cerinta_a()
{
int SS = S, i = 1;
int Cate_se_parcheteaza = 0;
void Cerinta_b()
{
int Contor = 0, nrsel, NRSEL = 0, Suprafata, i;
int b2 = 0, b2max = 1 << nr_camere;
if (Suprafata == S)
{
if (nrsel > NRSEL)
{
NRSEL = nrsel;
Contor = 1;
}
else
if (nrsel == NRSEL)
Contor++;
}
}
int main()
{
Citire();
Suprafete_camere();
if (Cerinta == 1)
Cerinta_a();
else
Cerinta_b();
return 0;
CAPITOLUL 22. ONI 2016 22.3. PARCHET 279
ifstream fin("parchet.in");
ofstream fout("parchet.out");
void Citire()
{
int i, j;
char X[255];
Casa[l][c] = nr;
sc++;
C[sc].lin = l;
C[sc].col = c;
return S;
}
void Suprafete_camere()
{
int i, j;
for (i = 2; i < N; ++i)
for (j = 2; j < M; ++j)
if (Casa[i][j] == 0) // camera goala - inca neprelucrata
CAPITOLUL 22. ONI 2016 22.3. PARCHET 280
{
nr_camere++;
Camere[nr_camere] = Suprafata(i, j, nr_camere);
}
}
void Cerinta_a()
{
int SS = S, i = 1;
int Cate_se_parcheteaza = 0;
if (Cerinta == 1)
fout << Cate_se_parcheteaza << ’ ’ << SS << ’\n’;
}
void Cerinta_b()
{
int Contor = 0, nrsel, NRSEL = 0, Suprafata, i;
int b2[100] = {0};
while (!b2[0])
{
i = nr_camere;
while (b2[i])
b2[i--] = 0;
b2[i] = 1;
Suprafata = 0;
nrsel = 0;
for (i = 1; i <= nr_camere; i++)
if (b2[i])
{
Suprafata += Camere[i];
nrsel++;
}
if (Suprafata == S)
{
if (nrsel > NRSEL)
{
NRSEL = nrsel;
Contor = 1;
}
else
if (nrsel == NRSEL)
Contor++;
}
}
if (Cerinta == 2)
fout << Contor << ’\n’;
}
int main()
{
Citire();
Suprafete_camere();
Cerinta_a();
Cerinta_b();
CAPITOLUL 22. ONI 2016 22.3. PARCHET 281
return 0;
}
ONI 2015
23.1 cript
Problema 1 - cript 100 de puncte
Ilinca a citit despre criptarea mesajelor, acum doreşte să comunice cu prietena ei Miruna numai
prin mesaje criptate folosind un sistem propriu de criptare.
Ilinca ştie că fiecare caracter se reprezintă ı̂n memoria calculatorului pe 8 biţi, ı̂n care se
memorează scrierea ı̂n baza 2 a codului ASCII al caracterului respectiv.
Pentru a cripta caracterul, Ilinca foloseşte o matrice pătratică având 8 linii (numerotate de la
0 la 7 de sus ı̂n jos) şi 8 coloane (numerotate de la 0 la 7 de la stânga la dreapta). Pe prima linie
a matricei Ilinca scrie cei 8 biţi reprezentând scrierea ı̂n baza 2 a codului ASCII al caracterului,
pe poziţia 0 fiind scrisă cifra cea mai semnificativă (corespunzătoare lui 27). Pe fiecare dintre
următoarele 7 linii din matrice scrie permutarea circulară cu o poziţie la stânga a liniei anterioare.
Ordonează lexicografic liniile matricei formate şi defineşte cript-ul caracterului ca fiind succesiunea
de biţi reprezentată de ultima coloană din matrice, parcursă de sus ı̂n jos, urmată de indicele liniei
din matrice pe care a ajuns după ordonarea lexicografică reprezentarea ı̂n baza 2 a codului ASCII
al caracterului. Dacă există linii egale ı̂n matrice, după ordonarea lexicografică acestea ı̂şi vor
păstra ordinea relativă iniţială, astfel că linia conţinând reprezentarea ı̂n baza 2 a codului ASCII
al caracterului va fi prima dintre acestea.
Pentru a cripta un mesaj, Ilinca scrie ı̂n ordine cript-urile caracterelor din mesajul respectiv.
Miruna cunoaşte sistemul de criptare al Ilincăi, ca urmare ştie să decripteze mesajele primite.
Cerinţe
Date de intrare
Fişierul de intrare cript.in conţine pe prima linie un număr natural c, care poate fi 1 sau
2, reprezentând cerinţa ce urmează a fi rezolvată. Pe a doua linie a fişierului se află un şir de
caractere.
Date de ieşire
Fişierul de ieşire cript.out va conţine o singură linie pe care va fi scrisă criptarea şirului din
fişierul de intrare (dacă c 1), respectiv decriptarea şirului din fişierul de intrare (dacă c 2).
282
CAPITOLUL 23. ONI 2015 23.1. CRIPT 283
Exemple
int c;
char s[LGMAX];
ifstream fin("cript.in");
ofstream fout("cript.out");
char M[8][9];
int ord[8];
char uc[9];
void criptare();
void decriptare();
int main()
{int lg;
fin>>c; fin.get();
assert(c==1 || c==2);
fin.getline(s,LGMAX);
lg=strlen(s);
if (c==1) {assert(lg<=30000); criptare();}
else {assert (lg<=270000 && lg%9==0);decriptare();}
fout<<’\n’; fout.close();
return 0;
}
void criptare()
{int i, j, k, aux, poz;
for (i=0; s[i]; i++)
{ assert (s[i]>=32 && s[i]<=127);
for (j=7; j>=0; j--)
{M[0][j]=(s[i]&1)+’0’; s[i]>>=1;}
for (k=1; k<8; k++)
{for (j=0; j<7; j++) M[k][j]=M[k-1][j+1];
M[k][7]=M[k-1][0];}
for (k=0; k<8; k++) ord[k]=k;
for (k=0; k<8; k++)
for (j=k+1; j<8; j++)
if (strcmp(M[ord[k]],M[ord[j]])>0)
{aux=ord[k]; ord[k]=ord[j]; ord[j]=aux;}
for (k=0; k<8; k++)
for (j=k+1; j<8; j++)
if (strcmp(M[ord[k]],M[ord[j]])==0&&ord[k]>ord[j])
{aux=ord[k]; ord[k]=ord[j]; ord[j]=aux;}
for (k=0; k<8; k++)
{fout<<M[ord[k]][7];
if (!ord[k]) poz=k;}
fout<<poz;
}
}
void decriptare()
{int i, j, poz, nr0, cod;
char *q;
for (i=0; s[i]; i++)
{ nr0=0; cod=0;
for (j=0; j<8; j++, i++)
{assert(s[i]==’0’|| s[i]==’1’);
uc[j]=s[i]; nr0+=(s[i]==’0’);}
q=uc;
for (j=0; j<nr0; j++)
{ord[j]=strchr(q,’0’)-uc; q=ord[j]+1+uc;}
CAPITOLUL 23. ONI 2015 23.1. CRIPT 285
q=uc;
for (j=nr0; j<8; j++)
{ord[j]=strchr(q,’1’)-uc; q=ord[j]+1+uc; }
assert(s[i]>=’0’ && s[i]<=’7’);
poz=s[i]-’0’;
for (j=0; j<8; j++)
{poz=ord[poz];
cod=(cod<<1)|(uc[poz]-’0’);
}
fout<<(char)cod;
}
}
ifstream fin("cript.in");
ofstream fout("cript.out");
n=c;
for(i=7; i>=0; i--)
{
s[0][i]=’0’+n%2;
n=n/2;
}
s[0][8]=’\0’;
for(i=1;i<=7;i++)
{
for(j=0;j<7;j++)
s[i][j]=s[i-1][j+1];
s[i][7]=s[i-1][0];
s[i][8]=’\0’;
}
cod[8]=’0’+i;
cod[9]=’\0’;
}
t=ss[8]-’0’;
j=a[t];
for(i=0; i<=7; i++)
{
ds[i]=ss[j];
j=a[j];
}
css=(char)cod;
}
int main()
{
fin>>c;
if(c==1)
{
fin.get();
fin.getline(s,40001);
for(i=0; s[i]; i++)
{
cript(s[i],ss);
fout<<ss;
}
}
else
{
fin>>t;
for(i=0; t[i]; i=i+9)
{
for(j=0;j<=8;j++)
ss[j]=t[i+j];
ss[9]=’\0’;
decript(ss,css);
fout<<css;
}
}
return 0;
}
ifstream fin("cript.in");
ofstream fout("cript.out");
int main()
{
char caracter;
fin>>p; fin.get(caracter);
for ( i = 32 ; i <= 127 ; i++)
{
z = y = i ;
if (i == 65)
i = i;
q1 = q;
q = (q << 8);
s = 0;
for (j = 0; j < 8; j++)
{
s = s * 2 + (a[ j ] & 1);
if ( (a[ j ] & 1) == 0)
b[ j ] = ’0’;
else
b[ j ] = ’1’;
}
sol[ i ] = s + q;
b[ 8 ] = q1 + 48;
b[ 9 ] = ’\0’;
strcpy(sol_char[i], b);
}
if (p == 1)
{
fin.getline(sir, LGMAX);
n = strlen(sir);
for (i = 0; i < n; i++)
{
fout<<sol_char[ sir[ i ] ];
}
}
else
{
fin.getline(cript, LGMAX);
n = strlen(cript);
s = 0;
CAPITOLUL 23. ONI 2015 23.1. CRIPT 288
fout<<’\n’;
fout.close();
return 0;
}
ifstream f("cript.in");
ofstream g("cript.out");
int c;
char s[9*30001];
int codif[200][10];
// for(i=0;i<=7;i++)
// {for(j=0;j<8;j++)
// g<<a[i][j];
// g<<’\n’;}
for(i=0;i<8;i++)
nr[i]=i;
for(i=0;i<7;i++)
CAPITOLUL 23. ONI 2015 23.1. CRIPT 289
aux=nr[i];
nr[i]=nr[j];
nr[j]=aux;
}
for(i=0;i<7;i++)
for(j=i+1; j<=7; j++)
if(cmp(a[i], a[j])==0 && nr[i]>nr[j])
{
for(k=0;k<=7;k++)
{
aux=a[i][k];
a[i][k]=a[j][k];
a[j][k]=aux;
}
aux=nr[i];
nr[i]=nr[j];
nr[j]=aux;
}
//g<<’\n’;
// for(i=0;i<=7;i++)
// {for(j=0;j<8;j++)g<<a[i][j];g<<’\n’;}
for(j=0;j<=7;j++)
cod[j]=a[j][7];
for(i=0;i<=7;i++)
if(nr[i]==0)
cod[8]=i;
}
for(i=32;i<=127;i++)
if(cmp(codif[i], cod)==0 && codif[i][8]==cod[8])
return i;
return -1; // ... !!!
}
int main()
{
f>>c;
f.get();
f.getline(s,9*30001);
if(c==1)
{
int i, j, cod[10];
char codul[10];
}
}
else
{
int n=strlen(s), i, j;
int cod[10];
char codul[10];
for(i=0;i<n;i=i+9)
{
strncpy(codul, s+i, 9);
codul[9]=0;
for(j=0;j<9;j++)
cod[j]=codul[j]-’0’;
g<<decodific(cod);
}
}
return 0;
}
23.2 scadere
Problema 2 - scadere 100 de puncte
Fie n un număr natural nenul.
Să considerăm o expresie de forma: x1 x2 x3 ... xn
Se ştie că scăderea nu este o operaţie asociativă, adică x1 x2 x3 j x1 x2 x3 .
Ca urmare, prin plasarea unor perechi de paranteze ı̂n expresie, putem obţine diferite valori.
Pentru problema noastră, vom denumi scădere o expresie de forma de mai sus ı̂n care pot apărea
şi paranteze rotunde care se ı̂nchid corect. Valoarea unei scăderi se obţine efectuând operaţiile de
scădere ı̂n ordine de la stânga la dreapta; dacă apar paranteze, se efectuează mai ı̂ntâi operaţiile
din paranteze.
Cerinţe
Date fiind valorile variabilelor x1 , x2 , ..., xn care intervin ı̂n scădere, scrieţi un program care să
rezolve următoarele două cerinţe:
1. să se determine valoarea maximă a unei scăderi (obţinută prin inserarea convenabilă a unor
paranteze rotunde ı̂n expresia x1 x2 x3 ... xn ), precum şi o scădere având valoare maximă.
2. să se determine valoarea unei scăderi specificate.
Date de intrare
Fişierul de intrare scadere.in conţine pe prima linie un număr natural c indicând cerinţa care
trebuie să fie rezolvată (1 sau 2).
Pe a doua linie este scris numărul natural n, care reprezintă numărul de variabile care intervin
ı̂n scădere. Variabilele sunt numerotate de la 1 la n ı̂n ordinea ı̂n care intervin ı̂n scădere. Pe
următoarele n linii sunt scrise ı̂n ordine valorile variabilelor x1 , x2 , ..., xn , câte o valoare pe o linie.
Dacă cerinţa este 2, fişierul mai conţine o linie pe care este scris un şir de caractere reprezentând
o scădere.
Date de ieşire
CAPITOLUL 23. ONI 2015 23.2. SCADERE 291
Fişierul de ieşire scadere.out va conţine pentru c 1 două linii; pe prima linie va fi scris un
număr ı̂ntreg reprezentând valoarea maximă a unei scăderi (obţinută prin inserarea convenabilă
a unor paranteze rotunde ı̂n expresia x1 x2 x3 ... xn ), iar pe a doua linie o scădere având
valoare maximă. Dacă c 2 fişierul de ieşire va conţine o singură linie pe care va fi scris un număr
ı̂ntreg reprezentând valoarea scăderii specificate pe ultima linie a fişierului de intrare.
Exemple
scadere.in scadere.out Explicaţii
1 17 Parantezarea care conduce la valoarea maximă este:
4 x1-x2-(x3-x4) x1-x2-(x3-x4)=-7-5-(-10-19)=-12-(-29)=-12+29=17
-7
5
-10
19
2 -3 x1-((x2-x3)-x4)=
4 -7-((5-10)-19)=
-7 -7-(15-19)=-7-(-4)=
5 -7+4=-3
-10
19
x1-((x2-x3)-x4)
Observăm că prin parantezare nu putem schimba semnul termenului x1, iar semnul termenului
x2 va fi ı̂ntotdeauna schimbat.
Pentru orice alt termen, plasând o paranteză ı̂n faţa termenului precedent păstrăm semnul
acestuia.
x1 x2 x3
x1 x2 x3 x1 x2 x3
Pentru a obţine suma maximă intenţionăm să schimbăm semnul termenilor negativi şi să
păstrăm semnul termenilor pozitivi.
Pentru cerinta 2 trebuie să evaluăm o expresie dată. Acest lucru se poate realiza ı̂n mai multe
moduri.
O varianta ar fi de a utiliza o stivă (implementată ca un vector: inserarea se realizează la vârful
stivei, adică la sfârşitul vectorului, iar extragerea se realizează de asemenea de la vârful stivei, adică
se elimină ultimul element din vector). ı̂n acest vector se vor reţine rezultatele parţiale obţinute
pe parcursul evaluării expresiei.
Parcurgem şirul care conţine expresia.
În cazul ı̂n care caracterul curent este ’(’, inserăm la sfârşitul vectorului valoarea INFINIT
pentru a marca faptul că nu am plasat ı̂ncă pe stivă nicio valoare pe acel nivel.
În cazul ı̂n care caracterul curent este ’)’, vom elimina ultimul element din vector (adică vom
coborı̂ ı̂n stivă), transmiţând pe nivelul precedent valoarea elementului eliminat (această valoare
CAPITOLUL 23. ONI 2015 23.2. SCADERE 292
va fi scăzută din nivelul precedent sau copiată pe nivelul precedent, ı̂n funcţie de caz - dacă pe
nivelul precedent se află o valoare sau nu).
În caz contrar, determin numărul variabilei care urmează ı̂n şir, aflu valoarea acestei variabile
şi o scad din valoarea aflată la vârful stivei (dacă există o astfel de valoare) sau o copiez la vârful
stivei (dacă la vârful stivei este plasată valoarea INFINIT).
ifstream fin("scadere.in");
ofstream fout("scadere.out");
int main()
{int i, nrp=0;
fin>>cerinta>>n;
for (i=1; i<=n; i++) fin>>x[i];
if (cerinta==1)
{
rez=x[1]-x[2];
for (i=3; i<=n; i++)
if (x[i]>=0) rez+=x[i];
else rez-=x[i];
fout<<rez<<’\n’;
fout<<"x1-";
for (i=3; i<=n; i++)
{
if (x[i]>=0)
{if (nrp%2==0)
{fout<<"("; nrp++;}
}
else
{if (nrp%2)
{fout<<"("; nrp++;}
}
fout<<"x"<<i-1<<"-";
}
fout<<"x"<<n;
for (i=0; i<nrp; i++) fout<<")";
fout<<’\n’;
fout.close();
return 0;}
fin>>s;
rez=evalexp();
fout<<rez<<’\n’;
fout.close();
return 0;
}
int evalexp()
{int vf=0, i, nr;
st[0]=INF;
for (i=0; s[i]; )
CAPITOLUL 23. ONI 2015 23.2. SCADERE 293
if (s[i]==’(’)
{st[++vf]=INF; i++;}
else
if (s[i]==’)’)
{if (st[vf-1]==INF) st[vf-1]=st[vf];
else st[vf-1]-=st[vf];
vf--;i++;}
else
{
if (s[i]==’-’)i++;
if (s[i]==’x’)
{i++;//sar x
nr=0;
while (s[i]>=’0’&& s[i]<=’9’) {nr=nr*10+s[i]-’0’; i++;}
if (st[vf]==INF) st[vf]=x[nr];
else st[vf]-=x[nr];
}
}
return st[0];
}
int main()
{
freopen("scadere.in", "r", stdin);
freopen("scadere.out", "w", stdout);
scanf("%d\n",&p);
scanf("%d\n", &n);
for (i = 1; i <= n; i++)
scanf("%d\n",&x[ i ]);
if (p == 1)
{
s = x[1];
start = 2;
stop = 2;
s1 = 0;
j=2;
if (i > n)
{
semn[start] = 1;
semn[stop] = -1;
s = s - s1 - 2 * x[2];
}
else
{
if (j == 2)
s = s - x[ 2 ],j++ ;
else
if (j > 2)
CAPITOLUL 23. ONI 2015 23.2. SCADERE 294
{
s = s - (s1 + 2 * x[ 2 ]);
semn [ start ] = 1;
semn [ stop - 1 ] = -1;
j++;
};
if ( j == 1)
s += x[2];
start = stop = j ;
s1 = 0;
for (i = j ; i <= n; i++)
if (x[ i ] >= 0)
{
s1 += x[ i ];
stop ++;
}
else
{
if (stop - start >= 1)
{
s += s1;
semn[ start ] = 1;
semn[ stop ] = -1;
}
else
s += s1;
s1 = -x[ i ];
start = stop = i;
}
s = s + s1;
}
printf("%d\n", s);
if (semn[1] == 1)
printf("(");
printf("x1-");
printf("x%d",n);
if (semn[ n ] == -1 || semn[ n + 1 ] == -1)
printf(")");
}
else
{
gets ( sir );
m = strlen(sir);
y[ 1 ] = 1;
t = 1;
paranteze = 0;
q = 0;
nr_minus = 0;
if (sir[ i ] == ’)’)
q--,nr_minus = st[q];
else
if (sir[ i ] ==’-’ )
nr_minus =st[q], nr_minus++;
else
if (sir[ i ] == ’x’)
if (nr_minus % 2 == 0)
y[ t++ ] = 1;
else
y[ t++ ] = -1;
else
while(i+1<m && sir[i+1]>=’0’ && sir[i+1]<=’9’)
i++;
s = 0;
for (i = 1;i <= n; i++)
s = s + y[ i ] * x[ i ];
printf("%d\n",s);
}
return 0;
}
23.3 tv
Problema 3 - tv 100 de puncte
Comisia Naţională a Audiovizualului (CNA) este autoritatea care coordonează activitatea
posturilor media din România. şeful CNA-ului doreşte o statistică referitoare la publicitatea
transmisă de posturile de televiziune. ı̂n acest scop, el primeşte pentru fiecare zi informaţii ı̂n
următorul format:
d hh mm ss
unde d este durata exprimată ı̂n secunde a publicităţii, iar hh mm ss este momentul de start
al publicităţii (hh este ora, mm este minutul, iar ss este secunda). Observaţi că d este separat de
hh printr-un singur spaţiu, iar următoarele valori sunt separate prin caracterul ’:’.
De exemplu o linie de forma:
150 05 02 45
se interpretează astfel: există un post TV care a transmis publicitate cu durata de 150 secunde,
ora de ı̂nceput fiind 5, 2 minute şi 45 de secunde.
”Secunda de aur” este o secundă ı̂n care se difuzează cât mai multă publicitate, adică pe un
număr maxim de posturi ı̂n acea secundă se transmite publicitate. Dacă sunt mai multe astfel
de secunde, ”secunda de aur” este considerată prima secundă cu această proprietate ı̂n derularea
zilei.
Şeful CNA primeşte ı̂n fiecare dimineaţă lista cu activitatea din ziua anterioară ca o succesiune
de linii, fiecare linie având forma descrisă mai sus.
Cerinţe
Scrieţi un program care, cunoscând lista din ziua anterioară, să rezolve următoarele cerinţe:
1. să determine durata totală ı̂n care niciun post de televiziune nu a difuzat publicitate;
2. să determine care este ”secunda de aur”.
Date de intrare
Fişierul de intrare tv.in conţine pe prima linie numărul natural c, care poate fi 1 sau 2,
reprezentând cerinţa care urmează să fie rezolvată. Pe a doua linie se află numărul natural N ,
reprezentând numărul de linii din lista cu informaţii primită de şef. Pe următoarele N linii sunt
descrise informaţiile, ı̂n formatul specificat ı̂n enunţ.
Date de ieşire
CAPITOLUL 23. ONI 2015 23.3. TV 296
Fişierul de ieşire tv.out va conţine o singură linie pe care vor fi scrise 3 numere naturale
separate prin caracterul ’:’ ı̂n formatul următor:
hh mm ss
semnificând durata totală exprimată ı̂n ore (hh), minute (mm) şi secunde (ss) pe parcursul
căreia niciun post de televiziune nu a difuzat publicitate ı̂n ziua respectivă (dacă c 1), respectiv
”secunda de aur” (dacă c 2).
Exemple
tv.in tv.out Explicaţii
1 23:18:40 Pentru exemplul 1, cerinţa este 1.
6 Pe parcursul zilei, timp de 23 de ore, 18 minute şi 40 de secunde
120 12:00:00 nu s-a difuzat publicitate.
200 12:01:50
1000
13:00:00
2000
13:01:00
100 14:05:05
10 23:59:49
2 12:01:50 Pentru exemplul 2, cerinţa este 2.
6 Secunda de aur este 12:01:50 pentru că există un număr maxim
1200 posturi care difuzează publicitate (3 posturi).
12:00:00
2000
12:01:50
1000
12:00:00
2000
13:01:00
100 14:05:05
10 23:59:49
int main()
{
freopen("tv.in", "r", stdin);
freopen("tv.out", "w", stdout);
ss = 0;
liber = 0;
ma = 0;
for (i = 0; i < 60*60*24; i++)
{
ss += h[i];
if (ss > ma)
{
ma = ss;
timp = i;
}
if (ss == 0)
liber++;
}
if (p == 1)
yy = liber;
else
yy = timp;
strcpy(s,"");
h1 = yy/3600;
m1 = yy%3600/60;
s1 = yy%60;
s[0]=h1/10+48;
s[1]=h1%10+48;
s[2]=’:’;
s[3]=m1/10+48;
s[4]=m1%10+48;
s[5]=’:’;
s[6]=s1/10+48;
s[7]=s1%10+48;
s[8]=’\0’;
printf("%s\n", s);
return 0;
}
CAPITOLUL 23. ONI 2015 23.3. TV 298
ONI 2014
24.1 codat
Problema 1 - codat 100 de puncte
Se consideră un şir de N numere naturale, notate x1 , x2 , x3 , ..., xN . Definim pentru orice
pereche de indici i, j, 1 & i & j & N , distanţa ı̂ntre elementele xi şi xj ca fiind egală cu j i.
Acest şir va fi codificat după următoarele reguli:
a fiecare element din şir este ı̂nlocuit cu indicele celui mai apropiat element din şir (cel faţă de
care distanţa este minimă) strict mai mare decât el;
a dacă pentru un element din şir există două elemente care respectă regula de mai sus, atunci
el va fi ı̂nlocuit cu indicele mai mare, adică al elementului strict mai mare decât el, aflat ı̂n dreapta
lui;
a elementele de valoare maximă din şir vor fi ı̂nlocuite cu -1.
Cerinţe
Date de intrare
Date de ieşire
Fişierul codat.out va conţine pe prima linie N numere ı̂ntregi nenule, separate prin câte un
spaţiu, reprezentând şirul codificat.
299
CAPITOLUL 24. ONI 2014 24.1. CODAT 300
???-???
Considerăm şirul numerelor citite memorat ı̂n vectorul A1..N . Algoritmul construieşte ı̂n
O N un vector St1..N , ı̂n care elementul Sti memorează indicele celui mai apropiat element
mai mare decât Ai situat ı̂n vectorul A de la poziţia 1..i 1. În mod identic ı̂n urma unei noi
parcurgeri a vectorului A, se va construi vectorul Dr1..N , ı̂n care elementul Dri memorează
indicele celui mai apropiat element mai mare decât Ai situat ı̂n vectorul A de la poziţia i 1..N .
Pentru fiecare element Ai soluţia o reprezintă cel cel mai apropiat dintre indicii elementului
maxim aflat ı̂n stânga, salvat ı̂n Sti, şi cel mai mare element aflat ı̂n dreapta lui, salvat ı̂n Dri.
Pentru construcţia vectorului St elementele lui A sunt parcurse de la stânga la dreapta. Vom
folosi un vector suplimentar Cnd pentru pastrarea doar a elementelor ce candidează la a fi maxime
pentru unul dintre elementele următoare. În fapt ı̂n vectorul Cnd vom plasa indicii acestora.
Pentru exemplificare vom construi vectorul St pentru vectorul iniţial A 2, 7, 4, 8, 6.
Notăm cu nr, numărul de elemente din vectorul candidaţilor Cnd. Când indicele i este introdus
ı̂n vectorul Cnd, toate elementele ai caror indici sunt deja salvaţi vor fi extrase dacă sunt mai mici
decât Ai. Operaţia se realizează decrementând valoare indicelui nr atâta timp cât ACndnr &
Ai. La final, Cndnr 1 reprezintă indicele primului element mai mare decât Ai. Iniţializăm
Cnd0 1.
Pentru asta vom gestiona vectorul Cnd astfel:
A1 2 este plasat ı̂n vectorul Cnd1 1, nr 1. Elementul St1 1 deoarece nu are
element mai mare situat ı̂n stânga lui.
A2 7 Elementul ACndnr fiind mai mic decât A2, este scos din şirul canditaţilor şi
ı̂nlocuit cu indicele acestuia (Cndnr 2), nr 1.
Deasemenea, St2 1 deoarece nu are element mai mare situat ı̂n stanga lui A3 4.
Acesta poate reprezenta maximul unui element aflat ı̂n vectroul A după el, deci este salvat ı̂n
vectorul Cnd pe poziţia a doua.
Acesta conţine acum indicii 2, 3. Deasemenea St3 Cnd1 2.
A4 8, acest element este mai mare decât ambele elemente aflate ı̂n Cnd, deci le va extrage
pe toate. Vectorul Cnd va conţine doar indicele (4). Fiind plasat pe prima poziţie ştim că
St4 1 deoarece nu are element mai mare situat ı̂n stânga lui.
A5 6, acesta poate reprezenta maximul unui element aflat după el, deci este salvat ı̂n Cnd
pe poziţia a doua. Vectorul Cnd conţine acum indicii 4, 5. Deasemenea St5 Cnd1 4.
Astfel indicele celui mai apropiat maxim din stânga este primul element din Cnd care nu a fost
extras la introducerea lui 5.
ifstream fin("codat.in");
ofstream fout("codat.out");
int main()
{
fin>>n;
for (i=1;i<=n;i++)
{
fin>>v[i];
if (v[i] > maxim)
CAPITOLUL 24. ONI 2014 24.1. CODAT 301
maxim = v[i];
while (k!=0 && v[i] >= v[s[k]])
{
k--;
}
L[i] = s[k];
s[++k] = i;
}
k = 0;
s[k] = n+1;
for (i=n;i>=1;i--)
{
while (k!=0 && v[i] >= v[s[k]])
{
k--;
}
R[i] = s[k];
s[++k] = i;
for (i=1;i<=n;i++)
{
if (v[i] == maxim)
{
v[i] = -1;
continue;
}
minim = n+2;
if (L[i] != 0 && i-L[i]<minim)
{
minim = i-L[i];
pminim = L[i];
}
if (R[i]!=n+1 && R[i]-i <= minim)
{
minim = R[i]-i;
pminim = R[i];
}
v[i] = pminim;
}
for(i=1;i<=n;i++)
fout<<v[i]<<" ";
return 0;
}
ifstream in("codat.in");
ofstream out("codat.out");
int v[MAXN];
int idx[MAXN];
int abs(int x)
{
if(x<0) x*=-1;
return x;
}
int main()
{
int N;
in>>N;
CAPITOLUL 24. ONI 2014 24.1. CODAT 302
for(int i=1;i<=N;++i)
in>>v[i];
for(int i=1;i<=N;++i)
{
idx[i]=-1;
for(int j=i-1;j>=1;--j)
if(v[j]>v[i])
{
idx[i]=j;
break;
}
for(int j=i+1;j<=N;++j)
if(v[j]>v[i])
{
if(idx[i]==-1||abs(idx[i]-i)>=abs(j-i))
idx[i]=j;
break;
}
}
for(int i=1;i<=N;++i)
out<<idx[i]<<’ ’;
out<<’\n’;
in.close();
out.close();
return 0;
}
ifstream in("codat.in");
ofstream out("codat.out");
int abs(int x)
{
if(x<0) x*=-1;
return x;
}
int v[MAXN];
int idx[MAXN];
int main()
{
int N;
in>>N;
for(int i=1;i<=N;++i)
{
while(!st.empty()&&v[st.top()]<=v[i])
st.pop();
if(st.empty())
idx[i]=-1;
else
idx[i]=st.top();
st.push(i);
}
CAPITOLUL 24. ONI 2014 24.2. NOD 303
while(!st.empty())
st.pop();
for(int i=N;i>=1;--i)
{
while(!st.empty()&&v[st.top()]<=v[i])
st.pop();
if(!st.empty())
if(idx[i]==-1||abs(idx[i]-i)>=abs(st.top()-i))
idx[i]=st.top();
st.push(i);
}
for(int i=1;i<=N;++i)
out<<idx[i]<<’ ’;
out<<’\n’;
in.close();
out.close();
return 0;
}
24.2 nod
Problema 2 - nod 100 de puncte
Pe vremea maurilor, transmiterea unor mesaje codificate ı̂ntre două persoane se făcea folosind
un cifru numit nod.
Cele două persoane alegeau ı̂n secret o poveste. Aceasta era scrisă ı̂ntr-o carte folosind litere
mici şi mari ale alfabetului englez, pe P pagini, numerotate de la 1 la P , fiecare conţinând exact
R rânduri, numerotate ı̂n cadrul fiecărei pagini de la 1 la R, iar fiecare rând fiind format din exact
C cuvinte, numerotate ı̂n cadrul fiecărui rând de la 1 la C.
Un cuvânt al mesajului de transmis era codificat prin poziţia sa ı̂n povestea aleasă de cei
doi, folosind trei numere scrise cu cifre romane, ce indicau ı̂n ordine: numărul paginii, numărul
rândului ı̂n cadrul paginii, respectiv al cuvântului ı̂n cadrul rândului.
Mesajul astfel codificat era scris pe trei linii. Pe prima linie erau scrise numerele paginilor, pe
a doua linie numerele rândurilor, iar pe a treia linie erau scrise numerele de ordine ale cuvintelor.
Presupunem că mesajul este format din primul cuvânt de pe al cincilea rând al celei de a doua
pagini şi din al patrulea cuvânt de pe rândul al doilea al primei pagini. Mesajul putea fi transmis
pe trei linii ı̂n modul următor:
II I (numerele paginilor)
V II (numerele rândurilor)
I IV (numerele cuvintelor)
Cifrele romane sunt scrise cu majusculele M, D, C, L, X, V, I, iar valorile corespunzătoare
lor sunt ı̂n ordine: 1000, 500, 100, 50, 10, 5, 1. Valoarea unui număr scris cu cifre romane se
calculează parcurgând de la stânga la dreapta cifrele numărului astfel:
- cifra curentă se adună la valoarea obţinută până ı̂n acel moment, dacă cifra următoare este
mai mică sau egală cu ea;
- cifra curentă se scade din valoarea obţinută până ı̂n acel moment, dacă cifra următoare este
mai mare decât ea;
- ultima cifră se adună ı̂ntotdeauna la valoarea obţinută până ı̂n acel moment.
De exemplu pentru numărul MCDXLVI scris cu cifre romane, se obţine valoarea 1446 ı̂n sistem
zecimal, astfel: 1000-100+500-10+50+5+1, iar pentru numărul XXI scris cu cifre romane se obţine
valoarea 21 ı̂n sistemul zecimal astfel: 10+10+1.
CAPITOLUL 24. ONI 2014 24.2. NOD 304
Cerinţe
Cunoscându-se textul poveştii ales de cei doi şi mesajul codificat de ei scrieţi un program care
rezolvă următoarele două cerinţe:
a) Rescrie mesajul codificat folosind scrierea cu cifre din sistemul zecimal.
b) Afişează toate cuvintele mesajului decodificat ı̂n ordinea ı̂n care acestea apar ı̂n poveste.
Date de intrare
Fişierul nod.in conţine:
a pe prima linie numărul 1, dacă se cere rezolvarea doar a cerinţei a) sau numărul 2, dacă se
cere rezolvarea cerinţei b);
a pe următoarele trei linii mesajul codificat după regulile descrise ı̂n enunţ;
a dacă primul număr din fişier este 2 atunci a cincea linie conţine trei numere naturale P , R
şi C, separate ı̂ntre ele prin câte un spaţiu, cu semnificaţia din enunţ;
a pe următoarele P R linii este scris textul poveştii, fiecare linie conţinând C cuvinte, separate
prin câte un spaţiu.
Date de ieşire
Dacă primul număr din fişierul de intrare este 1 atunci fişierul nod.out va conţine, ı̂n aceeaşi
ordine, pe trei linii, numerele din mesajul codificat scrise ı̂n sistem zecimal. Numerele vor fi
despărţite ı̂n cadrul liniilor prin câte un spaţiu.
Dacă primul număr din fişierul de intrare este 2 atunci fişierul nod.out va conţine pe o singură
linie cuvintele mesajului decodificat, ı̂n ordinea din poveste. Cuvintele vor fi separate prin câte
un spaţiu.
Restricţii şi precizări
a 1 & P & 2000; 1 & R & 25; 1 & C & 15
a 1 & lungimea unui cuvânt din poveste & 12
Exemplul 1:
nod.in nod.out Explicaţii
1 321 Testul de intrare indică rezolvarea primei cerinţe, adică cerinţa a).
III II I 252 Numerele de pe fiecare linie sunt scrise ı̂n aceeaşi ordine, ı̂n sistemul
II V II 614 zecimal.
VI I IV
Exemplul 2:
nod.in nod.out
2 La Olimpiada comisia decide prima
I III II I II
I I II I II
I II II II IV
324
La Olimpiada problemele pot
avea una sau mai
multe cerinte Pentru unele
probleme comisia poate decide
ca prima cerinta sa
fie evaluata si separat
Explicaţii:
Testul de intrare indică rezolvarea celei de a doua cerinţe, adică cerinţa b).
Cuvintele identificate ı̂n poveste sunt:
La - prin (I,I,I)
prima - prin (III,I,II)
comisia - prin (II,II,II)
Olimpiada - prin (I,I,II)
decide - prin (II,II,IV)
Cuvintele mesajului decodificat, ı̂n ordinea din poveste, sunt:
La Olimpiada comisia decide prima
CAPITOLUL 24. ONI 2014 24.2. NOD 305
??? - ???
Definesc o structură care să reţină pagina, rândul, poziţia cuvântului pe rând.
Definesc un tablou de tipul structurii descrise mai sus, care va reţine pentru fiecare cod, pagina,
rândul şi numărul cuvântului de pe rând.
Citim primul număr din fişier, care reprezintă cerinţa, apoi citim pe rând următoarele trei linii
din fişierul de date, care conţin respectiv paginile, rândurile şi numărul cuvântului pe linie.
Pentru cerinţa 1
De pe fiecare linie separăm câte un cuvânt, care reprezintă un număr scris cu cifre romane şi
transformăm numărul scris cu cifre romane ı̂n număr ı̂ntreg scris ı̂n sistem zecimal:
Parcurgem cifrele numărului de la stânga la dreapta câte una, o transformăm ı̂n sistem zecimal
şi
daca(cif[i]<cif[i+1])
nr=nr-cif[i];
else
nr=nr+cif[i+1];
ifstream f("nod.in");
ofstream g("nod.out");
struct cuvinte
{
int pag, rand, cuv;
};
void extrage_nr();
int calculeaza(int x);
void transforma(char numar[11],int k);
void ordonare();
void cauta_cuvinte();
void afisare();
int main()
{
f>>k; f.get();
extrage_nr();
if(k==1)
{
for(int d=1;d<=3;d++)
for(int i=1; i<=n;i++)
{
switch (d)
{
case 1:g<<t[i].pag; break;
case 2:g<<t[i].rand; break;
case 3:g<<t[i].cuv; break;
}
if(i<n)
g<<" ";
else
g<<’\n’;
}
}
else
{
ordonare();
cauta_cuvinte();
}
f.close();
g.close();
return 0;
}
void extrage_nr()
{
int i;
for(i=1;i<=3;i++)
{
n=0;
f.getline(sir,600);//cout<<sir<<endl;
p=strtok(sir,sep);
while (p)
{
n++;
strcpy(numar, p);
transforma(numar,i);
p=strtok(NULL,sep);
}
}
}
if(l==1)
nr=calculeaza(numar[i]);
else
CAPITOLUL 24. ONI 2014 24.2. NOD 307
nr=nr+cif2;
switch (d)
{
case 1:t[n].pag=nr;break;
case 2:t[n].rand=nr;break;
case 3:t[n].cuv=nr;break;
}
}
int calculeaza(int x)
{
int cif;
switch (x)
{
case ’M’:cif=1000;break;
case ’D’:cif=500;break;
case ’C’:cif=100;break;
case ’L’:cif=50;break;
case ’X’:cif=10;break;
case ’V’:cif=5; break;
case ’I’:cif=1;break;
}
return cif;
}
void ordonare()
{
int i,sw; cuvinte aux;
do
{
sw=1;
for(i=1;i<n;i++)
if(t[i].pag>t[i+1].pag ||
(t[i].pag==t[i+1].pag && t[i].rand>t[i+1].rand) ||
(t[i].pag==t[i+1].pag &&
t[i].rand==t[i+1].rand &&
t[i].cuv>t[i+1].cuv))
{
aux=t[i];
t[i]=t[i+1];
t[i+1]=aux;
sw=0;
}
} while (sw==0);
}
void cauta_cuvinte()
{
int i=1,nrct=0, nrc=0;
char *p;
f>>P>>R>>C;
f.get();
if(nrc==nrct)
{
if (i<n)
g<<p<<" ";
else
g<<p;
i++;
nrct=(t[i].pag-1)*R*C+(t[i].rand-1)*C + t[i].cuv;
}
CAPITOLUL 24. ONI 2014 24.2. NOD 308
p=strtok(NULL,sep);
}
}
}
void afisare()
{
int i;
for(i=1;i<=n;i++)
{
g<<t[i].pag<<" "<<t[i].rand<<" "<<t[i].cuv<<’\n’;
}
}
struct tag
{
short int pg,rd,cv;
};
tag L[Cuvmes];
int cif(char x)
{
if(x==’M’) return 1000;
if(x==’D’) return 500;
if(x==’C’) return 100;
if(x==’L’) return 50;
if(x==’X’) return 10;
if(x==’V’) return 5;
if(x==’I’) return 1;
return Nr;
}
while (p)
{
CAPITOLUL 24. ONI 2014 24.2. NOD 309
strcpy(x,p);
V[++n]=NrRo(x);
p=strtok(NULL," ");
}
}
int main()
{
freopen("nod.in", "r", stdin);
freopen("nod.out", "w", stdout);
scanf("%d\n", &test);
gets(Pag);
int x=strlen(Pag);
PuneNr(R,nr,Rand);
gets(Cuv);
x=strlen(Cuv);
PuneNr(C,nc,Cuv);
assert(np>=1&&np<=20);
if(test==1)
{
for(i=1; i<=np;i++)
{
printf("%d", L[i].pg);
if(i<np)
printf(" ");
else
printf("\n");
}
for(i=1; i<=np;i++)
{
printf("%d", L[i].rd);
if(i<np)
printf(" ");
else
printf("\n");
}
for(i=1; i<=np;i++)
{
printf("%d", L[i].cv);
CAPITOLUL 24. ONI 2014 24.2. NOD 310
if(i<np)
printf(" ");
else
printf("\n");
}
}
else
{
scanf("%d %d %d\n", &p, &r, &c);
assert(p>=1&&p<=2000&&r>=1&&r<=25&&c>=1&&c<=15);
sort(L + 1, L + np + 1, cmp);
scanf("\n");
}
}
return 0;
}
ifstream f("nod.in");
ofstream g("nod.out");
int p[256],r[30],c[25],poz[100103];
char *q1,*q2,*q, sir[]="MDCLXVI",b[256],w[256],s[256],x[2];
int nr_pag=1,nr_r=1,nr_c=1,v[8]={1000, 500, 100, 50, 10, 5,1};
void citire_pagini()
{
int i,j,k;
f.getline(b,255);
q=strtok(b," ");
while(q)
{
strcpy(w,q);
q1=strchr(sir,w[0]);
i=q1-sir;
CAPITOLUL 24. ONI 2014 24.2. NOD 311
if(strlen(w)==1)
p[nr_pag]=v[i];
else
{
for(k=1;k<strlen(w);k++)
{
q2=strchr(sir,w[k]);
j=q2-sir;
if(j>=i)
p[nr_pag]=p[nr_pag]+v[i];
else
p[nr_pag]=p[nr_pag]-v[i];
q1=q2;i=j;
}
q1=strchr(sir,w[strlen(w)-1]);
i=q1-sir;
p[nr_pag]=p[nr_pag]+v[i];
}
nr_pag++;
q=strtok(NULL," ");
}
nr_pag--;
if(x[0]==’1’)
{
for(i=1;i<=nr_pag;i++)
g<<p[i]<<’ ’;
g<<’\n’;
}
}
void citire_randuri()
{
int i,j,k;
f.getline(b,255);
q=strtok(b," ");
while(q)
{
strcpy(w,q);
q1=strchr(sir,w[0]);
i=q1-sir;
if(strlen(w)==1)
r[nr_r]=v[i];
else
{
for(k=1;k<strlen(w);k++)
{
q2=strchr(sir,w[k]);
j=q2-sir;
if(j>=i)
r[nr_r]=r[nr_r]+v[i];
else
r[nr_r]=r[nr_r]-v[i];
q1=q2;i=j;
}
q1=strchr(sir,w[strlen(w)-1]);
i=q1-sir;
r[nr_r]=r[nr_r]+v[i];
}
nr_r++;
q=strtok(NULL," ");
}
nr_r--;
if(x[0]==’1’)
CAPITOLUL 24. ONI 2014 24.2. NOD 312
{
for(i=1;i<=nr_r;i++)
g<<r[i]<<’ ’;
g<<’\n’;
}
}
void citire_cuv()
{
int i,j,k;
f.getline(b,255);
q=strtok(b," ");
while(q)
{
strcpy(w,q);
q1=strchr(sir,w[0]);
i=q1-sir;
if(strlen(w)==1)
c[nr_c]=v[i];
else
{
for(k=1;k<strlen(w);k++)
{
q2=strchr(sir,w[k]);
j=q2-sir;
if(j>=i)
c[nr_c]=c[nr_c]+v[i];
else
c[nr_c]=c[nr_c]-v[i];
q1=q2;i=j;
}
q1=strchr(sir,w[strlen(w)-1]);
i=q1-sir;
c[nr_c] =c[nr_c]+v[i];
}
nr_c++;
q=strtok(NULL," ");
}
nr_c--;
if(x[0]==’1’)
{
for(i=1;i<=nr_c;i++)
g<<c[i]<<’ ’;
g<<’\n’;
}
}
int main()
{
int i,P,R,C,nr=0,j,aux;
f.getline(x,2);
citire_pagini();
citire_randuri();
citire_cuv();
if(x[0]==’2’)
{
f>>P>>R>>C;
for(i=1;i<=nr_pag;i++)
poz[i]=(p[i]-1)*R*C+(r[i]-1)*C+c[i];
for(i=1;i<=nr_pag-1;i++)
for(j=i+1;j<=nr_pag;j++)
if(poz[i]>poz[j])
{
aux=poz[i];
poz[i]=poz[j];
CAPITOLUL 24. ONI 2014 24.3. PLACA 313
poz[j]=aux;
}
j=1;
nr=1;
for(i=1;i<=R*P;i++)
{
f.getline(b,255);
q=strtok(b," ");
while(q)
{
strcpy(w,q);
if(nr==poz[j])
{
g<<w<<’ ’;j++;
}
nr++;
q=strtok(NULL," ");
}
}
}
f.close();
g.close();
return 0;
}
24.3 placa
Problema 3 - placa 100 de puncte
Un gard este format din mai multe plăci dreptunghiulare. Fiecare placă este, la rândul ei,
construită din N M cărămizi. Una dintre plăci ridică o problemă, deoarece este deteriorată.
Placa este reprezentată pe hârtie cu ajutorul unei matrice cu N linii şi M coloane, numerotate
de la 1 la N , respectiv de la 1 la M . Matricea conţine doar valori 0 şi 1, şi respectă următoarele
reguli:
- un element egal cu 1 indică prezenţa ı̂n aceea poziţie a unei cărămizi, iar un element egal cu
0 indică absenţa ei;
- linia 1 şi linia N conţin numai valori egale cu 1, pentru că marginea de sus şi cea de jos a
plăcii este intactă;
- din orice element egal cu 1, situat ı̂n interiorul matricei, se poate ajunge pe linia 1 sau pe
linia N sau pe amândouă, mergând doar ı̂n sus sau doar ı̂n jos, parcurgând numai valorile egale
cu 1;
- există cel puţin o coloană stabilă (formată numai din elemente egale cu 1).
Se doreşte modificarea plăcii şi pentru aceasta se pot şterge din matrice maximum K coloane
alăturate. După ştergere se alipesc coloanele rămase şi se deplasează pe verticală partea de sus a
plăcii spre cea de jos, până când se va forma o coloană stabilă.
Cerinţe
Să se determine ı̂nălţimea minimă Hmin pe care o poate avea placa ştergând cel mult K
coloane alăturate. Identificaţi numărul minim de coloane alăturate care trebuie şterse pentru a
obţine ı̂nălţimea Hmin.
Date de intrare
Din fişierul placa.in se citesc de pe prima linie 3 numere naturale N , M , K separate prin câte
un spaţiu, având semnificaţia din enunţ.
Pe fiecare dintre următoarele M linii ale fişierului se găsesc perechi de numere naturale N 1,
N 2, separate printr-un spaţiu. Astfel pe linia i 1 a fişierului de intrare numărul N 1 reprezintă
numărul de elemente de 1 situate pe coloana i, ı̂ncepând cu linia 1, deplasându-ne ı̂n ”jos” până la
ı̂ntâlnirea unei valori egale cu 0, sau până se ajunge pe linia N ; numărul N 2 reprezintă numărul de
CAPITOLUL 24. ONI 2014 24.3. PLACA 314
elemente de 1 situate pe coloana i, ı̂ncepând cu linia N , deplasândune ı̂n ”sus” până la ı̂ntâlnirea
unei valori egale cu 0, sau până se ajunge pe linia 1.
Date de ieşire
În fişierul placa.out se va scrie pe prima linie ı̂nălţimea minimă cerută Hmin, iar pe a doua
linie numărul minim de coloane ce trebuie eliminate pentru a obţine ı̂nălţimea Hmin.
Exemple
placa.in placa.out Explicaţii
563 3 Matricea iniţială:
11 2 111111
21 010100
12 000110
55 001110
13 111111
11 ı̂nălţimea minimă este 3 şi se poate obţine eliminând, de exemplu,
coloanele 3, 4, 5 rezultând matricea:
111
010
111
O altă modalitate de a obţine aceeaşi ı̂nălţime dar prin ştergerea
unui număr minim de coloane (4 şi 5) conduce la:
1111
0110
1111
int main()
{
ifstream fin("placa.in");
ofstream fout("placa.out");
fin>>n>>m>>k;
for (i=1;i<=m;i++)
{
fin>>x>>y;
if (x!=n)
v[i] = x+y;
else
v[i] = n;
}
a[1] = v[1];
for (i=2;i<=m;i++)
if (a[i-1] > v[i])
a[i] = a[i-1];
else
a[i] = v[i];
b[m] = v[m];
for (i=m-1;i>=1;i--)
if (v[i] > b[i+1])
b[i] = v[i];
else
b[i] = b[i+1];
sol = m+2;
for (i=1,j=k;j<=m;i++,j++)
{
if (a[i-1] > b[j+1])
x = a[i-1];
else
x = b[j+1];
if (x < sol)
sol = x;
}
fout<<sol<<"\n";
for (i=1;i<=m;i++)
{
if (a[i] > sol)
c[i] = 1;
else
c[i] = c[i-1];
}
for (i=m;i>=1;i--)
{
if (b[i] > sol)
d[i] = 1;
else
d[i] = d[i+1];
fout<<p<<"\n";
return 0;
}
int main()
{
ifstream fin("placa.in");
ofstream fout("placa.out");
fin>>n>>m>>k;
for (i=1;i<=m;i++)
{
fin>>x>>y;
if (x!=n)
v[i] = x+y;
else
v[i] = n;
}
a[1] = v[1];
for (i=2;i<=m;i++)
if (a[i-1] > v[i])
a[i] = a[i-1];
else
a[i] = v[i];
b[m] = v[m];
for (i=m-1;i>=1;i--)
if (v[i] > b[i+1])
b[i] = v[i];
else
b[i] = b[i+1];
sol = m+2;
for (i=1,j=k;j<=m;i++,j++)
{
if (a[i-1] > b[j+1])
x = a[i-1];
else
x = b[j+1];
if (x < sol)
sol = x;
}
fout<<sol<<"\n";
if (sol == n)
{
fout<<"0\n";
return 0;
}
p = 1;
u = k;
while (p<=u)
{
mid = (p+u)/2;
solc = m+2;
for (i=1,j=mid;j<=m;i++,j++)
{
if (a[i-1] > b[j+1])
x = a[i-1];
CAPITOLUL 24. ONI 2014 24.3. PLACA 317
else
x = b[j+1];
if (x < solc)
solc = x;
}
if (solc == sol)
u = mid-1;
else
p = mid+1;
}
fout<<p<<"\n";
return 0;
}
ifstream f("placa.in");
ofstream g("placa.out");
int s[300003],d[300003],m,n;
int calcul(int k)
{
int i,x=n+1,max;
for(i=1;i+k<=m;i++)
{
if(s[i]>d[i+k])
max=s[i];
else
max=d[i+k];
if(x>max)
x=max;
}
return x;
}
for(int i=1;i+k<=m;i++)
if(s[i]<=d[i+k] &&min1<=s[i])
min1=s[i];
else
if(s[i]>=d[i+k]&&min1<=d[i+k])
min1=d[i+k];
return min1;
}
int main()
{
int i,j,k,x,min,y,v[300003],st,dr,mij;
f>>n>>m>>k;
for(i=1;i<=m;i++)
{
f>>x>>y;
if(x+y>n)
v[i]=x;
else
v[i]=x+y;
}
CAPITOLUL 24. ONI 2014 24.3. PLACA 318
s[1]=v[1];
for(j=2;j<=m;j++)
if(v[j]<s[j-1])
s[j]=s[j-1];
else
s[j]=v[j];
d[m]=v[m];
for(j=m-1;j>=1;j--)
if(v[j]<d[j+1])
d[j]=d[j+1];
else
d[j]=v[j];
min=minim(k,s[1]);
g<<min<<’\n’;
st=1;dr=k;
mij=(st+dr)/2;
while(st<dr)
{
if(calcul(mij)>min)
st=mij+1;
else
dr=mij;
mij=(st+dr)/2;
}
g<<st-1<<’\n’;
f.close();
g.close();
return 0;
}
int n,m,k;
int hmin,kmin;
int nr1[MAXM]; //numarul de 1 de pe fiecare coloana
int x,y;
int maxS[MAXM];
int maxD[MAXM];
void solve_good()
{
maxS[0] = 0;
for(int i=1; i<=m; i++)
maxS[i] = max(maxS[i-1],nr1[i]);
maxD[m+1] = 0;
for(int i=m; i>=1; i--)
maxD[i] = max(maxD[i+1],nr1[i]);
kt = (lb+ub)/2;
if (hcmin==hmin)
kmin = min(kmin,kt);
if (hcmin>hmin)
lb = kt+1;
else
if (hcmin==hmin)
ub = kt-1;
}
}
int main()
{
ifstream fin("placa.in");
ofstream fout("placa.out");
fin>>n>>m>>k;
fin.close();
hmin = INF;
kmin = INF;
solve_good();
fout<<hmin<<"\n"<<kmin<<"\n";
fout.close();
return 0;
}
ifstream fin("placa.in");
ofstream fout("placa.out");
int main()
{
fin>>n>>m>>k;
for (i=1;i<=m;i++)
{
fin>>x>>y;
if (x == n)
v[i] = n;
else
v[i] = x+y;
}
a[1] = v[1];
for (i=2;i<=m;i++)
if (a[i-1] > v[i])
a[i] = a[i-1];
else
a[i] = v[i];
CAPITOLUL 24. ONI 2014 24.3. PLACA 320
b[m] = v[m];
for (i=m-1;i>=1;i--)
if (v[i] > b[i+1])
b[i] = v[i];
else
b[i] = b[i+1];
sol = m+2;
if (x < sol)
sol = x;
}
aux = k;
for (k=1;k<=aux;k++)
{
solc = m+2;
if (x < solc)
solc = x;
}
if (solc == sol)
break;
}
fout<<sol<<"\n"<<k<<"\n";
return 0;
}
ifstream fin("placa.in");
ofstream fout("placa.out");
int a[DIM];
int x, y, n, m, k, i, st, dr, maximst, maximdr, sol1;
int main()
{
fin>>n>>m>>k;
for(i=1;i<=m;i++)
{
fin>>x>>y;
if (x == n)
{
a[i] = x;
if (st == 0)
st = i;
dr = i;
}
CAPITOLUL 24. ONI 2014 24.3. PLACA 321
else
a[i] = x + y;
}
maximst = 0;
for (i=1;i<st;i++)
if (a[i] > maximst)
maximst = a[i];
maximdr = 0;
for (i=m;i>dr;i--)
if (a[i] > maximdr)
maximdr = a[i];
fout<<sol1<<"\n"<<dr-st+1;
return 0;
}
int main()
{
ifstream fin("placa.in");
ofstream fout("placa.out");
fin>>n>>m>>k;
for (i=1;i<=m;i++)
{
fin>>x>>y;
if (x!=n)
v[i] = x+y;
else
v[i] = n;
}
a[1] = v[1];
for (i=2;i<=m;i++)
if (a[i-1] > v[i])
a[i] = a[i-1];
else
a[i] = v[i];
b[m] = v[m];
for (i=m-1;i>=1;i--)
if (v[i] > b[i+1])
b[i] = v[i];
else
b[i] = b[i+1];
sol = m+2;
for (i=1,j=k;j<=m;i++,j++)
{
if (a[i-1] > b[j+1])
x = a[i-1];
else
x = b[j+1];
if (x < sol)
sol = x;
}
CAPITOLUL 24. ONI 2014 24.3. PLACA 322
fout<<sol<<"\n";
fout<<k<<"\n";
return 0;
}
ifstream f("placa.in");
ofstream g("placa.out");
int c[300000],m,n,k;
void afi(int m)
{
int i;
for(i=1;i<=m;i++)
cout<<c[i]<<" ";
cout<<endl;
}
int main()
{
int hmin,max,colmax1=3000000,colmax2=0,i,x,y,cm1,cm2;
f>>n>>m>>k;
hmin=n;
for(i=1;i<=m;i++)
{
f>>x>>y;
if(x==n)
c[i]=n;
else
c[i]=x+y;
}
// afi(m);
maxcol(max,colmax1,colmax2);
while(colmax2-colmax1+1<=k)
{
sterge(colmax1,colmax2);
hmin=colmax2-colmax1+1;
//afi(m);
maxcol(max,cm1,cm2);
CAPITOLUL 24. ONI 2014 24.3. PLACA 323
if(colmax1>cm1) colmax1=cm1;
if(colmax2<cm2) colmax2=cm2;
}
g<<max<<endl;
g<<hmin<<endl;
return 0;
}
ifstream fin("placa.in");
ofstream fout("placa.out");
int main()
{
fin>>n>>m>>k;
for (i=1;i<=m;i++)
{
fin>>x>>y;
if (x == n)
v[i] = n;
else
v[i] = x+y;
}
a[1] = v[1];
for (i=2;i<=m;i++)
if (a[i-1] > v[i])
a[i] = a[i-1];
else
a[i] = v[i];
b[m] = v[m];
for (i=m-1;i>=1;i--)
if (v[i] > b[i+1])
b[i] = v[i];
else
b[i] = b[i+1];
sol = m+2;
if (x < sol)
sol = x;
}
aux = k;
for (k=aux;k>=1;k--)
{
solc = m+2;
if (x < solc)
solc = x;
}
if (solc != sol)
break;
}
fout<<sol<<"\n"<<k+1<<"\n";
return 0;
}
ONI 2013
25.1 secvp
Problema 1 - secvp 100 de puncte
Se consideră un şir cu N numere naturale a1 , a2 , ..., aN . Asupra unui element ai , din şir, se
pot efectua operaţii de incrementare (adunare cu 1: ai ai 1) sau decrementare (scădere cu 1:
ai ai 1). Fiecare element din şir poate fi incrementat sau decrementat de oricâte ori.
Cerinţe
Date de intrare
Fişierul de intrare secvp.in conţine pe prima linie numerele naturale N şi K, iar pe următoarea
linie N numere naturale. Numerele scrise pe aceeaşi linie sunt separate prin spaţii.
Date de ieşire
Fişierul de ieşire secvp.out conţine pe prima linie un număr natural T , reprezentând numărul
total minim de operaţii necesare pentru a transforma toate numerele din şir ı̂n numere prime.
Pe a doua linie vor fi scrise două numere naturale separate prin spaţiu minK nrsK, unde minK
reprezintă numărul minim de operaţii ce trebuie să fie efectuate asupra elementelor şirului astfel
ı̂ncât să existe o secvenţă de lungime K formată numai din numere prime, iar nrsK reprezintă
numărul de secvenţe de lungime K care se pot obţine cu acelaşi număr minK de operaţii de
incrementare/decrementare.
Exemple
325
CAPITOLUL 25. ONI 2013 25.1. SECVP 326
https://infogenius.ro/problema-secvp-oni-2013-clasa-7/
Pentru prima cerinţă vom parcurge şirul, iar pentru fiecare număr, calculăm modulul diferenţei
dintre el şi cel mai apropiat număr prim de acesta. Pentru asta vom folosi o funcţie minInc ı̂n
care iterăm pe i de la 0 ı̂n sus până când x i sau x i este prim. Reţinem valorile găsite ı̂ntr-un
vector inc de dimensiune N M AX (pentru a doua cerinţă). Pe parcurs, pentru a afla răspunsul
primei cerinţe, calculăm suma acestor rezultate.
La a doua cerinţă practic trebuie să determinăm suma minimă pe care o poate avea o secvenţă
de lungime k şi câte astfel de secvenţe există ı̂n vectorul nostru.
Vom folosi Ciurul lui Eratostene pentru a testa mai apoi ı̂n O 1 primalitatea numerelor.
https://infogenius.ro/problema-secvp-oni-2013-clasa-7/
std::ifstream fin("secvp.in");
std::ofstream fout("secvp.out");
int n, k;
bool sieve[NRMAX]; // ciurul
short int inc[NMAX];
int minInc(int x)
{
// Tratam separat cazul x == 0 deoarece
// nu putem accesa ciur[-1] \c si ciur[-2]:
if (!x)
return 2;
{
int i, j;
sieve[0] = sieve[1] = true;
sumMin = sum;
apMin = 1;
int main()
{
read();
solve();
return 0;
}
25.2 patrate2
Problema 2 - patrate2 100 de puncte
Bia şi Ştefan joacă un nou joc. Bia i-a cerut lui Ştefan să se gândească la un număr natural
n
nenul mai mic strict decât V M AX 2 . Apoi, ea a luat un pix şi o foaie şi a desenat n matrice
pătratice (denumite pe scurt pătrate), pe care le-a numerotat de la 1 la n. Apoi a completat
pătratele ı̂n modul următor: ı̂n pătratul cu numărul i au fost scrise ı̂n ordine crescătoare toate
numerele naturale nenule mai mici decât V M AX, care, scrise ı̂n baza 2, au cifra corespunzătoare
i1
lui 2 , egală cu 1; plasarea numerelor s-a făcut parcurgând coloanele de la stânga la dreapta şi
completând fiecare coloană de sus ı̂n jos.
Fiecare pătrat are latura minimă necesară pentru ca numerele pe care trebuie să le conţină să
ı̂ncapă.
Este posibil ca pătratele să nu se umple integral (ı̂n acest caz pătratul se va completa cu
valoarea 0).
După ce a desenat pătratele, Bia ı̂l ı̂ntreabă pe Ştefan ı̂n care dintre pătrate se află numărul
la care s-a gândit el. Apoi face o magie şi ghiceşte numărul la care s-a gândit Ştefan.
În plus, ca să-l impresioneze şi mai tare pe Ştefan, Bia i-a spus linia şi coloana pe care este
plasat acest număr ı̂n primul pătrat spus de Ştefan.
Cerinţe
Fiindcă voi nu credeţi ı̂n magie, scrieţi un program care să determine numărul la care s-a
gândit Ştefan, precum şi poziţia acestui număr ı̂n primul pătrat spus de Ştefan.
Date de intrare
Fişierul de intrare patrate2.in conţine pe prima linie numerele naturale n şi m, separate prin
spaţiu, reprezentând numărul de pătrate pe care le va desena Bia, respectiv ı̂n câte dintre pătratele
desenate se află numărul la care s-a gândit Ştefan. Pe al doilea rând se află, separate prin câte
un spaţiu, m numere naturale cuprinse ı̂ntre 1 şi n, reprezentând cele m pătrate ı̂n care se află
numărul la care s-a gândit Ştefan.
Date de ieşire
Fişierul de ieşire patrate2.out va conţine pe prima linie numărul la care s-a gândit Ştefan.
Pe a doua linie vor fi scrise două numere naturale separate prin spaţiu L C, reprezentând, linia,
respectiv coloana pe care se află numărul respectiv ı̂n primul pătrat menţionat de Ştefan.
a 1 $ m & n & 28
a ı̂n fiecare matrice pătratică liniile sunt numerotate de sus ı̂n jos ı̂ncepând cu 1, iar coloanele
de la stânga la dreapta ı̂ncepând cu 1.
a Pentru teste valorând 50% din punctaj, n este & 14.
a Pentru determinarea corectă a numărului la care s-a gândit Ştefan se acordă 40% din punc-
tajul pe test. Punctajul integral se obţine pentru rezolvarea ambelor cerinţe.
Exemple
patrate2.in patrate2.out Explicaţii
43 13
143 13
25.3 cursa
Problema 3 - cursa 100 de puncte
O cursă de maşini electrice prevăzute cu panouri solare are loc pe un traseu care traversează
n localităţi, numerotate ı̂n ordinea de pe traseu de la 1 la n. Linia de start se află la kilometrul
zero şi coincide cu ı̂nceputul primei localităţi. Linia de sosire este la sfârşitul ultimei localităţi.
Orice localitate, exceptând localitatea 1, ı̂ncepe la sfârşitul localităţii precedente. Prin urmare,
pentru fiecare localitate i se cunoaşte distanţa di de la linia de start până la sfârşitul localităţii,
exprimată ı̂n km.
În momentul ı̂nceperii competiţiei, din fiecare localitate există exact o maşină aliniată la linia
de start. Maşinile au aceleaşi caracteristici, ca urmare se deplasează cu aceeaşi viteză, cu excepţia
traversării localităţii din care provin unde, datorită avantajelor terenului propriu (suporteri dotaţi
cu oglinzi, lămpi, etc...), ı̂şi dublează instantaneu viteza până la ieşirea din localitate, apoi revin
la viteza iniţială.
La concurs sunt invitate şi televiziunile locale, iar pentru telespectatori, sarea şi piperul sunt
depăşirile, de aceea este important să reţinem informaţii despre acestea, pentru a le putea viziona
ı̂n reluare. Se consideră depăşire situaţia ı̂n care o maşină ajunge din urmă o altă maşină, apoi
trece ı̂n faţa acesteia.
Cerinţe
Cunoscând localităţile de pe traseu, scrieţi un program care tipăreşte ordinea sosirii maşinilor
la linia de sosire, respectiv informaţii despre toate depăşirile efectuate ı̂n timpul concursului.
Date de intrare
Fişierul de intrare cursa.in va conţine pe prima linie numărul de localităţi n. Urmează n linii
care descriu informaţii despre cele n localităţi. Pe linia i 1 din fişier se află două numere naturale
c şi d, separate prin spaţiu, cu semnificaţia că numărul de concurs al maşinii din localitatea i este
c şi că localitatea i se termină la d kilometri faţă de linia de start.
Date de ieşire
Fişierul de ieşire cursa.out va conţine pe prima linie numerele de concurs ale maşinilor ı̂n
ordinea sosirii lor, separate prin câte un spaţiu. ı̂n cazul ı̂n care există mai multe maşini care
sosesc simultan la linia de sosire, acestea vor fi afişate ı̂n ordinea crescătoare a numerelor de
concurs.
Pe următoarele linii sunt descrise depăşirile, ı̂n ordinea crescătoare a localităţilor ı̂n care se
produc. O depăşire este descrisă printr-o succesiune de valori de forma L c k m1 m2 ... mk ,
cu semnificaţia că ı̂n localitatea L maşina cu numărul de concurs c depăşeşte k maşini, maşinile
depăşite fiind, ı̂n ordinea ı̂n care sunt depăşite, m1 m2 ... mk . Dac sunt depşite ı̂n acelaşi moment
două sau mai multe maşini, acestea se vor afişa ı̂n ordinea descresctoare a numerelor de concurs.
a 2 $ n & 500
a Numerele de concurs ale maşinilor sunt numere naturale nenule distincte de maxim 3 cifre.
a Distanţa dintre linia de start şi linia de sosire (sfârşitul ultimei localităţi) & 30 000
a Dacă prima cerinţă este rezolvată corect, se obţine 40% din punctajul pe test. Dacă prima
cerinţă este rezolvată corect, dar la afişarea depăşirilor maşinile dintr-o localitate nu sunt afişate
ı̂n ordinea solicitată, se acordă 70% din punctajul pe test. Punctajul integral se obţine pentru
rezolvarea corectă a ambelor cerinţe.
Exemple
cursa.in cursa.out Explicaţii
5 70 35 99 10 66 Prima localitate ı̂ncepe de la km.0 şi se termină la km.5 şi are
10 5 3 99 2 66 10 maşina nr. 10.
66 7 4 35 2 66 10 A doua localitate se află ı̂ntre km 5-7 şi are maşina nr. 66.
99 15 5 70 4 66 10 99 35 A treia localitatea se află ı̂ntre km 7-15 şi are maşina nr. 99.
35 23 A patra ı̂ntre km 15-23 are maşina nr. 35 şi ultima ı̂ntre km
70 34 23-34 are maşina 70.
Ordinea de sosire a maşinilor este: 70 35 99 10 66.
Maşinile 35 şi 99 termină cursa deodată, se enumeră ı̂n ordinea
crescătoare a numerelor.
Depăşiri: Localitatea 3: maşina 99 va depăşi 2 maşini, ı̂n or-
dine maşinile 66 apoi 10.
Localitatea 4: maşina 35 depăşeşte 2 maşini, pe 66 şi 10 şi
ajunge pe 99 fără să o depăşească.
Localitatea 5: maşina 70 depăşeşte 4 maşini, ı̂n ordine pe 66,
10, apoi simultan pe 99 şi 35 aflate la egalitate (se enumeră ı̂n
ordine descrescătoare).
ONI 2012
26.1 bile
Problema 1 - bile 100 de puncte
Matei a inventat un nou joc cu bile. Terenul de joc este o tablă dreptunghiulară aşezată
vertical. Tabla este ı̂mpărţită ı̂n m n celule, aşezate ı̂n m linii şi n coloane. În unele dintre celule
se află obstacole.
De sus, din celulele aflate pe prima linie, sunt lăsate să cadă bile. Bilele cad vertical până
la ı̂ntâlnirea unui obstacol sau până ı̂n celula cea mai de jos din coloana pe care se află. Prima
bilă care loveşte un obstacol se deplasează pe orizontală ı̂n coloana alăturată din stânga, apoi
ı̂şi continuă căderea. Fiecare dintre celelalte bile care lovesc acelaşi obstacol se deplasează pe
orizontală, ı̂n coloana alăturată, dar ı̂n direcţie opusă faţă de bila care a lovit acest obstacol exact
ı̂naintea lor, apoi ı̂şi continuă căderea.
Cerinţe
Cunoscând numărul de bile lăsate să cadă de pe fiecare celulă a primei linii şi poziţia obsta-
colelor, determinaţi numărul de bile ajunse ı̂n fiecare celulă a ultimei linii. Poziţiile obstacolelor
sunt indicate prin linia şi coloana lor (colţul din stânga sus corespunde liniei 1 şi coloanei 1).
Date de intrare
Fişierul bile.in conţine pe prima linie, separate prin câte un spaţiu, numerele naturale m, n şi
p (numărul de linii, numărul de coloane şi numărul de obstacole). Următoarele p linii conţin câte
două numere, separate de câte un spaţiu, reprezentând poziţiile celor p obstacole. Ultimele n linii
conţin câte un număr natural, reprezentând numărul bilelor lansate din fiecare celulă a primei
linii (ı̂ncepând cu prima celulă de pe linie).
Date de ieşire
Fişierul de ieşire bile.out va conţine n linii cu câte un număr, acesta reprezentând numărul
de bile din fiecare celulă a ultimei linii (ı̂ncepând cu prima celulă de pe această linie).
Exemple
331
CAPITOLUL 26. ONI 2012 26.1. BILE 332
Se poate simula căderea bilelor folosind o matrice m n ı̂n care punem, de exemplu, 1 ı̂n
celulele cu obstacole şi un număr pozitiv - numărul de bile ajunse ı̂n celula respectivă. Soluţia nu
se va ı̂ncadra ı̂n timp pentru dimensiuni mai mari.
Se poate ı̂ncerca eliminarea liniilor care nu au obstacole, ceea ce nu va aduce un câştig
substanţial de timp.
Soluţia optimă presupune ordonarea poziţiilor obstacolelor crescător după linii (pe aceeaşi linie
nu contează ordinea obstacolelor, ele neinfluenţându-se reciproc) apoi, considerând şirul bilelor de
pe prima linie b1 , b2 , ..., bn , fiecare obstacol de pe poziţia i, j va modifica 3 termeni din acest
şir: la bj 1 se adaugă bj 1©2, la bj 1 se adaugă bj ©2 iar bj devine 0.
Astfel complexitatea algoritmului va fi dată de complexitatea algoritmului de sortare, după
care determinarea numărului de bile de pe fiecare coloană se obţine ı̂n O p.
struct coord
{
int x;
int y;
} a[10002];
int main()
{
FILE *fi, *fo;
int m,n,i,j,p,b[5002];
coord t;
fi=fopen("bile.in","r");
fscanf(fi,"%d %d %d",&m,&n,&p);
CAPITOLUL 26. ONI 2012 26.2. PROIECTE 333
for(i=1;i<=p;i++)
fscanf(fi,"%d %d",&a[i].x,&a[i].y);
for(i=1;i<=n;i++)
fscanf(fi,"%d",&b[i]);
fclose(fi);
qsort(a+1,p,sizeof a[0],fc);
for(i=1;i<=p;i++)
{
j=a[i].y;
b[j-1]+=b[j]/2+b[j]%2;
b[j+1]+=b[j]/2;
b[j]=0;
}
fo=fopen("bile.out","w");
for(i=1;i<=n;i++)
fprintf(fo,"%d\n",b[i]);
fclose(fo);
return 0;
}
26.2 proiecte
Problema 2 - proiecte 100 de puncte
În oraşul Iaşi, cele N firme IT derulează ı̂n prezent M proiecte din acest domeniu (printre
care şi ONI 2012). Firmele sunt identificate prin numere naturale de la 1 la N , iar proiectele
sunt identificate prin numere naturale de la 1 la M . Fiecare proiect are una sau mai multe etape,
o etapă fiind executată de o singură firmă IT. Spunem că o firmă coordonează un proiect dacă
execută mai mult de jumătate din etapele proiectului.
Cerinţe
Cunoscând numărul firmelor IT, numărul proiectelor, numărul de etape ale fiecărui proiect
şi firmele ce execută fiecare etapă, să se determine firma/firmele care coordonează cel mai mare
număr de proiecte.
Date de intrare
Fişierul de intrare proiecte.in conţine, pe prima linie, numerele naturale N şi M , sepa-
rate printr-un spaţiu, cu semnificaţia de mai sus. Pe fiecare dintre următoarele M linii se află
informaţii despre câte un proiect, ı̂n ordinea numerelor de identificare a acestora. Astfel, pe linia
corespunzătoare proiectului i (1 & i & M ), se află un număr natural nri , urmat de nri numere
naturale f1 f2 ... fnri , reprezentând numărul de etape ale acestui proiect, respectiv firmele care
execută fiecare etapă din proiect (firma fk execută etapa k, 1 & k & nri ). Numerele de pe aceeaşi
linie sunt separate prin câte un spaţiu.
Date de ieşire
Fişierul de ieşire proiecte.out va conţine o singură linie, pe care va fi scris numărul de iden-
tificare al firmei/firmelor care coordonează cel mai mare număr de proiecte. Dacă sunt mai
multe astfel de firme, numerele de identificare ale acestora se vor afişa pe aceeaşi linie, ı̂n ordine
crescătoare, separate prin câte un spaţiu.
Exemple
proiecte.in proiecte.out Explicaţii
54 13 Numărul maxim de proiecte coordonate de aceeaşi firmă este 2:
233 firma 1 coordonează proiectele 2 şi 4, iar firma 3 coordonează
3121 proiectele 1 şi 3.
534331
11
FILE * fin;
ofstream fout("proiecte.out");
int main()
{
fin=fopen("proiecte.in","r");
fscanf(fin,"%d%d",&n,&m);
for(i=1;i<=m;i++)
{
fscanf(fin,"%d",&nr);//fin>>nr;
for(j=1;j<=nr;j++)
fscanf(fin,"%d",&x[j]);
cand=x[1];nrap=1;
for(j=2;j<=nr;j++)
if(x[j]==cand)
nrap++;
else
if(nrap>0)nrap--;
else
{
nrap=1;
cand=x[j];
}
if(nrap>0)
{
nrap=0;
for(j=1;j<=nr;j++)
if(x[j]==cand)nrap++;
}
if(nrap>nr/2)
{
ok=0;
for(j=1;j<=k;j++)
if(v[j]==cand)
{
++Nr[j];
ok=1;
break;
}
if(ok==0)
{
v[++k]=cand;
Nr[k]=1;
}
}
}
ok=0;
while(!ok)
{
ok=1;
for(j=1;j<=k-1;j++)
if(v[j]>v[j+1])
{
aux=v[j];
v[j]=v[j+1];
v[j+1]=aux;
aux=Nr[j];
Nr[j]=Nr[j+1];
Nr[j+1]=aux;
ok=0;
}
}
nrmax=Nr[1];
for(j=2;j<=k;j++)
if(nrmax<Nr[j])
nrmax=Nr[j];
for(j=1;j<=k;j++)
if(nrmax==Nr[j])
fout<<v[j]<<’ ’;
CAPITOLUL 26. ONI 2012 26.2. PROIECTE 336
fout<<’\n’;
fout.close();
return 0;
}
int f[1000],pr[1000],N,c[210],K;
int a[200002];
int m,n,i,j,k,val,ap,p,q,r,max1;
void sortare()
{
int s;
do
{
s=1;
for(int i=1;i<N;i++)
if(f[i]>f[i+1])
swap(f[i],f[i+1]),s=0;
} while(!s);
}
int main()
{
freopen("proiecte.in","r",stdin);
freopen("proiecte.out","w",stdout);
cin>>n>>m;
for(i=1;i<=m;i++)
{
cin>>k;
for(j=1;j<=k;j++)
//cin>>a[j];
scanf("%d",&a[j]);
sort(a+1,a+k+1);
val=a[(k+1)/2];
a[0]=a[k+1]=0;
ap=1;
p=(k+1)/2;
q=p+1;
r=p-1;
while(a[q]==val)
ap++,q++;
while(a[r]==val)
ap++,r--;
if(ap>=k/2+1)
{
N++;
f[N]=val;
}
}
sortare();
else
if(max1==nr)
K++,c[K]=f[i-1];
}
for(i=1;i<=K;i++)
cout<<c[i]<<" ";
return 0;
}
26.3 zigzag
Problema 3 - zigzag 100 de puncte
Rail Fence Cipher, cunoscut sub numele de cifru zig-zag, este o metodă de codificare a mesajelor
folosind un caroiaj ı̂n care textul este scris ı̂ncepând din colţul stânga-sus, diagonal de sus ı̂n jos,
iar apoi, după ce s-a scris caracterul de pe ultima linie, se continuă, diagonal de jos ı̂n sus, ca ı̂n
exemplu. Numărul de linii ale caroiajului este cheia de codificare. După ce textul a fost scris ı̂n
acest mod, mesajul codificat se obţine parcurgând liniile de sus ı̂n jos şi preluând de pe fiecare
linie toate caracterele de la stânga la dreapta. Dacă vrem să codificăm textul ”OLIMPIADA DE
INFORMATICA”, cu cheia de codificare 6, atunci se procedează astfel:
1. Se scrie textul ı̂n zigzag ı̂n caroiaj
2. Se iau caracterele pe linii şi se formează mesajul codificat: ODTL EAIIA MCMDIRA-
PANOIF
Cerinţe
Scrieţi un program care citeşte cheia de codificare şi un text codificat şi determină mesajul
decodificat.
Date de intrare
Pe prima linie a fişierului zigzag.in se află două numere naturale c şi n, separate printr-
un spaţiu, unde c reprezintă cheia de codificare, iar n numărul de caractere al mesajului, şi pe
următoarea linie un şir format din n caractere ce reprezintă mesajul codificat.
Date de ieşire
Fişierul zigzag.out va conţine o singură linie, pe care se află mesajul decodificat.
Restricţii şi precizări
a 1 $ c $ 5000;
a 1 $ n $ 50000;
a ı̂n mesaj sunt doar caractere cu codul ASCII mai mic ca 127 şi mai mare ca 31.
Exemple
zigzag.in zigzag.out Explicaţii
6 24 OLIMPIADA DE INFORMATICA
ODTL EAIIA MCMDIRAPANOIF
CAPITOLUL 26. ONI 2012 26.3. ZIGZAG 338
FILE *fin;
ofstream fout("zigzag.out");
int main()
{
fin=fopen("zigzag.in","r");
fscanf(fin,"%d%d",&c,&n);
fscanf(fin,"%c",&chr);
for(i=1;i<=n;i++)
{
fscanf(fin,"%c",&chr);
a[i]=chr;
}
for(i=n+1;i<=m;i++)
s[i]=’X’;
k=1;
//rand 1
for(x=0;x<=nr-1;x++)
if(s[x*(2*c-2)+1]!=’X’)
s[x*(2*c-2)+1]=a[k++];
//randuri de la 2 la c-1
for(p=2;p<=c-1;p++)
CAPITOLUL 26. ONI 2012 26.3. ZIGZAG 339
for(x=0;x<=nr-1;x++)
{
if(s[x*(2*c-2)+p]!=’X’)
s[x*(2*c-2)+p]=a[k++];
if(s[x*(2*c-2)+2*c-p]!=’X’)
s[x*(2*c-2)+2*c-p]=a[k++];
}
//rand c
for(x=0;x<=nr-1;x++)
if(s[x*(2*c-2)+c]!=’X’)
s[x*(2*c-2)+c]=a[k++];
for(i=1;i<=n;i++)
fout<<s[i];
fout<<’\n’;
fout.close();
return 0;
}
ONI 2011
27.1 joc
Problema 1 - joc 100 de puncte
Georgel şi Ionel au inventat un joc. Georgel scrie ı̂n fiecare pătrăţel pe o foaie de matematică,
de forma unui tablou bidimensional cu n linii şi m coloane, valori de 0 sau 1. Ionel stabileşte 3
forme distincte pe care Georgel trebuie să le identifice pe foaia de matematică ı̂n poziţia dată sau
rotite ca ı̂n figura 1, 2 sau 3. Cele trei forme propuse sunt:
Pentru un joc, Georgel trebuie să le identifice pe foaie sub forma de pătrăţele pline cu 1.
Cerinţe
Scrieţi un program care să identifice numărul de apariţii pentru toate formele precizate.
Date de intrare
Fişierul joc.in conţine pe prima linie valorile lui n şi m separate printr-un spaţiu, pe
următoarele n linii fiind valorile din pătrăţelele de pe foaie (neseparate prin spaţii).
Date de ieşire
Fişierul joc.out va conţine pe prima linie numărul total de forme identificate, de oricare din
cele trei tipuri.
a 0 $ m, n $ 100
a Un pătrăţel se poate regăsi ı̂n una sau mai multe forme.
340
CAPITOLUL 27. ONI 2011 27.2. MESAJ 341
Exemple
joc.in joc.out Explicaţii
55 7 Există 2 forme de primul tip, 3 forme de tipul al doilea şi 2 de al treilea tip,
00100 ca ı̂n desen.
00110
01111
00100
00100
27.2 mesaj
Problema 2 - mesaj 100 de puncte
Maria şi Ionuţ doresc să comunice ı̂ntre ei prin bileţele. Pentru ca mesajele lor să nu fie
ı̂nţelese şi de ceilalţi colegi, ei se hotărăsc să le codifice. Pentru a codifica un mesaj, Maria şi Ionuţ
procedează astfel:
a aleg ı̂mpreună un cuvânt s numit cheie format din p litere diferite două câte două;
a ı̂mpart mesajul pe care doresc să-l transmită ı̂ntre ei ı̂n secvenţe de caractere alăturate de
lungime p, cu excepţia ultimei secvenţe care poate avea mai puţin de p caractere;
a scriu pe foaie cuvântul cheie ales;
a sub cuvântul cheie ales se scriu secvenţele de lungime p determinate anterior, ı̂n ordinea
obţinerii lor;
a mesajul codificat se obţine astfel:
` se parcurge tabelul obţinut anterior, pe coloane, de sus ı̂n jos;
` ordinea de parcurgere a coloanelor este ordinea alfabetică a literelor din cuvântul cheie;
Cerinţe
Scrieţi un program care să determine litera din mesajul codificat care apare de cele mai puţine
ori, iar dacă sunt mai multe astfel de litere, prima dintre acestea ı̂n ordine alfabetică şi să realizeze
decodificarea unui mesaj codificat ı̂n modul prezentat anterior.
Date de intrare
Fişierul de intrare mesaj.in conţine:
- pe prima linie numărul p de caractere din cheie;
- pe a doua linie cuvântul cheie ales de Maria şi Ionuţ;
- pe a treia linie numărul n de caractere din mesajul codificat;
- pe a patra linie mesajul codificat.
CAPITOLUL 27. ONI 2011 27.2. MESAJ 342
Date de ieşire
a Cuvântul cheie conţine numai litere mari ale alfabetului englez (A, B, C,...,Z) şi are maxim
26 de litere;
a Mesajul codificat conţine litere mari ale alfabetului englez, cuvintele sunt separate prin unul
sau mai multe spaţii;
a Lungimea mesajului codificat nu depăşeşte 2000 de caractere.
a Se acordă punctaje parţiale:
µ 20% pentru afişarea valorii corecte pe prima linie a fişierului mesaj.out (cerinţa a)
µ 80% pentru afişarea corectă a mesajului pe linia a doua a fişierului mesaj.out (cerinţa
b)
Exemple
mesaj.in mesaj.out
8 COMPUTER F
44 SUCCES LA OLIMPIADA NATIONALA DE INFORMATICA
SAAO T PTDMCOAANCU DNIICL LFALIIEASMA REINAO
Explicaţii:
Maria şi Ionuţ aleg cuvântul cheie COMPUTER
Mesajul pe care doresc să-l codifice este:
SUCCES LA OLIMPIADA NATIONALA DE INFORMATICA
Tabelul obţinut este următorul:
- Pentru determinarea literei care apare de cele mai puţine ori se construieşte un vector ı̂n care
se păstrează numărul de apariţii pentru fiecare literă. Se identifică apoi litera care apare ı̂n mesaj
şi are număr minim de apariţii.
- Se construieşte un vector v ı̂n care păstrează ordinea de parcurgere a coloanelor.
Se citeşte mesajul codificat şi, folosind vectorul v, determinat la pasul anterior, se construieşte
matricea necesară pentru decodificare.
Textul decodificat se obţine prin parcurgerea matricei pe linii.
27.3 zar
Problema 3 - zar 100 de puncte
Maria a primit cadou un joc. Jocul are o tablă sub formă de caroiaj dreptunghiular format
din pătrăţele de latură 1 dispuse ı̂n L linii şi C coloane. Pătrăţelele conţin primele L C numere
naturale nenule ı̂ncepând cu 1, reprezentând coduri.
Codificarea se face astfel: se ı̂ncepe cu valoarea 1 din pătrăţelul din 9 10 11 12
stânga-jos, se continuă cu valorile 2,3,...C de la stânga la dreapta, continuă 8 7 6 5
pe rândul următor de la dreapta la stânga şi aşa mai departe. ı̂n acest fel 1 2 3 4
ultimul pătrăţel va fi codificat ı̂ntotdeauna cu valoarea L*C, ca ı̂n exemplul din dreapta.
Jocul constă ı̂n plasarea unui jeton ı̂n colţul din stânga jos şi trebuie să se ducă jetonul dincolo
de pătrăţelul codificat cu valoarea L*C ı̂n urma mutărilor realizate. Pentru efectuarea unei mutări,
el aruncă mai ı̂ntâi un zar. Dacă acesta arată valoarea Z şi jetonul se află ı̂n pătrăţelul cu codul
P, jetonul va fi dus ı̂n pătrăţelul cu codul P+Z. Dacă P+Z¿L*C, jocul se termină. ı̂n caz contrar,
există situaţii ı̂n care jetonul nu va rămâne neapărat ı̂n noua poziţie, ı̂ntrucât ı̂n unele poziţii ale
caroiajului sunt indicatoare care precizează unde trebuie dus jetonul care tocmai a ajuns ı̂n acea
poziţie.
4 3 2
Un pătrăţel poate să conţină cel mult un indicator. Indicatoarele sunt de 9
tipuri: pentru primele 8 tipuri se precizează peste câte poziţii se va plasa jetonul 5 X 1
din poziţia curentă, respectiv: pe aceeaşi linie la dreapta(1), ı̂n diagonală pe 6 7 8
direcţia dreapta-sus(2), pe aceeaşi coloană ı̂n sus(3), pe diagonală pe direcţia stânga-sus(4), pe
aceeaşi linie la stânga(5), pe diagonală pe direcţia stânga-jos(6), pe aceeaşi coloană ı̂n jos(7), ı̂n
diagonală pe direcţia dreapta-jos(8). Indicatorul de tipul 9 precizează codul unui pătrăţel ı̂n care
va fi plasat jetonul.
La aplicarea unui indicator se respectă regulile:
a) dacă jetonul iese ı̂n afara tablei, acest indicator va fi neglijat, iar jetonul va rămâne pe loc
(jocul nu se poate termina astfel).
b) dacă se ajunge ı̂ntr-un pătrăţel care conţine un alt indicator, acesta nu va mai fi luat ı̂n
considerare.
Cerinţe
Cunoscând, ı̂n ordine, cele K valori obţinute ı̂n urma aruncărilor cu zarul, să se determine
dacă jocul se poate ı̂ncheia. ı̂n caz afirmativ se va afişa numărul de aruncări cu zarul după care
jocul se ı̂ncheie. ı̂n caz contrar, se va afişa poziţia jetonului după cele K mutări.
Date de intrare
Fişierul zar.in conţine pe prima linie două numere L şi C reprezentând numărul de linii,
respectiv numărul de coloane ale tablei de joc.
Pe linia a 2-a se găseşte un număr natural I reprezentând numărul de pătrăţele ı̂n care se
găsesc indicatoare.
Pe următoarele I linii se găsesc câte 3 numere naturale separate prin câte un spaţiu
reprezentând descrierea câte unui indicator. Primul număr este codul pătrăţelului ı̂n care este
pus indicatorul, al doilea număr este tipul de indicator. Dacă tipul de indicator este 9, al treilea
număr semnifică codul pătrăţelului unde va fi trimis jetonul. Dacă al doilea număr este din
mulţimea {1, 2, 3, 4, 5, 6, 7, 8}, al treilea număr reprezintă numărul de poziţii de pe tablă peste
care se va muta jetonul ı̂n direcţia precizată.
Pe linia următoare se află un număr natural K reprezentând numărul de aruncări cu zarul.
Pe următoarea linie sunt K numere naturale separate prin câte un spaţiu, reprezentând, ı̂n
ordine, valorile obţinute după fiecare aruncare.
Date de ieşire
Fişierul zar.out va conţine pe prima linie două numere naturale separate printr-un spaţiu.
Dacă jocul se termină, prima valoare va fi 1, iar a doua va reprezenta numărul de mutări după
care s-a terminat. Dacă jocul nu se termină, prima valoare va fi 2, iar a doua codul pătrăţelului
unde a rămas jetonul.
CAPITOLUL 27. ONI 2011 27.3. ZAR 344
Exemple
zar.in zar.out Explicaţii
34 2 11 Iniţial jetonul este ı̂n pătrăţelul 1. După prima mutare el ajunge ı̂n
4 pătrăţelul 5 (zarul arată 2 şi jetonul ar ajunge ı̂n pătrăţelul 3 dar
321 indicatorul de acolo ı̂n trimite ı̂n pătrăţelul 5). După mutarea a doua
811 jetonul ajunge ı̂n pătrăţelul 6 (acolo ı̂l trimite zarul şi nu este ı̂ntâlnit
712 un indicator). După mutarea a treia, jetonul ajunge ı̂n pătrăţelul 7
9 9 11 (zarul ı̂l trimite ı̂n 8, iar indicatorul de acolo ı̂n 7 acum nu se tine cont
4 de indicatorul din 7). După mutarea 4 jetonul ajunge la pătrăţelul
2122 11 (după aruncarea cu zarul trebuia dus ı̂n 9 iar indicatorul de acolo
ı̂l trimite ı̂n 11).
Se simulează mutările conform regulilor din enunţ. Probabilitatea de a greşi tratând multi-
tudinea de cazuri ce pot apărea poate fi scăzută printr-o codificare eficientă a datelor. Astfel, se
pot pastra structuri de date care să permită determinarea poziţiei pe tabla de joc pentru un cod
dat (un vector de structuri, V k .i şi V k .j sunt poziţiile pe tabla de joc ale pătrăţelului cu codul
k), respectiv pentru determinatea codului pătrăţelului aflat pe poziţia i, j pe tabla de joc (o
matrice, M ij = codul pătrăţelului de pe poziţia i, j ).
Aceste structuri se construiesc la citirea datelor. Se poate renunţa la utilizarea structurilor
scriind funcţii care să facă trecerea de la cod la coordonate şi invers. Se pot utilize 2 vectori de
direcţii, di şi dj , deplasarea cu x paşi din poziţia i, j pe direcţia k putându-se face prin construcţii
de forma i x di k , j x dj k .
ONI 2010
28.1 char
Problema 1 - char 100 de puncte
Alex a primit de la Moş Crăciun un joc foarte interesant. Jocul este format dintr-un text cu
n litere mici ale alfabetului englez. Fiecare literă are o anumită putere, dată printr-un număr
natural. Puterea k a unei litere c constă ı̂n faptul că, dacă aceasta este atinsă atunci toate literele
din secvenţa de k litere, din stânga şi din dreapta se transformă ı̂n c. Spre exemplu, dacă litera x
are puterea 2, atunci după atingere, textul abcbxpbrr se transformă ı̂n abxxxxxrr. Cunoscând
puterea fiecărei litere, jocul constă ı̂n determinarea numărului maxim m de litere, care după
atingere să transforme orice literă din text cel mult o dată.
Cerinţe
Scrieţi un program care să citească un text cu n litere, puterea fiecărei litere şi să afişeze
numărul de litere din text cu puterea maximă, notat cu q precum şi numărul m.
Date de intrare
În fişierul char.in se dau:
- pe prima linie: numărul natural n
- pe a doua linie: cele n litere ale textului fără spaţiu ı̂ntre ele
- pe a treia linie: numărul h de litere distincte din text
- pe a patra linie: h numere naturale separate ı̂ntre ele prin câte un spaţiu reprezentând puterea
literelor din text ı̂n ordine alfabetică.
Date de ieşire
Fişierul char.out va conţine pe prima linie numărul q şi pe a doua linie numărul m.
Restricţii şi precizări
a 1 & n & 10000,
a 1 & putere literă & 100
a Dacă ı̂n stânga sau dreapta unei litere sunt mai puţine litere decât puterea, atunci atingerea
ei conduce la transformarea tuturor literelor din stânga, respectiv dreapta.
a Se acordă 30% din punctaj pentru determinarea numărului q şi 70% din punctaj pentru
determinarea numărului m.
a Prima literă din text este pe poziţia 1, a doua literă pe poziţia 2, şi aşa mai departe.
Exemple
char.in char.out Explicaţii
12 6 Litera a are puterea 2, litera b puterea 5, litera c puterea 3,
acbbxacbbbxb 3 respectiv litera x are puterea 2.
4 Litera cu puterea maximă este b şi apare ı̂n secvenţă de 6 ori.
2532 Numărul maxim de litere, care pot fi atinse astfel ı̂ncât oricare
literă a textului să se transforme cel mult o dată este 3 (de
exemplu se pot atinge literele de pe poziţiile 1, 6, 11).
Timp maxim de executare/test: 1.0 secunde
345
CAPITOLUL 28. ONI 2010 28.1. CHAR 346
1. Se construieşte un vector v v 1, v 2, ..., v h cu literele distincte din text, astfel fiecărei
litere v i ı̂i corespunde o putere pi, i 1, ..., h.
2. Se determină ı̂n max puterea maximă şi apoi poziţiile literelor cu puterea egală cu max ı̂n
text. Pentru fiecare astfel de literă determinată anterior, se incrementează variabila q.
3. Pentru a doua cerinţă se observă faptul că fiecărei litere ı̂i corespunde o porţiune continuă de
litere din text. O astfel de porţiune este caracterizată prin capătul din stânga, respectiv dreapta.
Determinăm ı̂n doi vectori st st1, ..., stn, dr dr1, ..., drn aceste capete de porţiuni.
4. Acum problema se reduce la determinarea unui număr maxim de porţiuni disjuncte. Acest
număr este numărul căutat m.
char x[10003],y[100];
int s[10003],d[10003],i,h,p[100],n,k,nr,t,j,aux,m,maxx,i1,j1;
void afis()
{
ofstream fout("char.out");
fout<<nr<<’\n’<<m;
fout.close();
}
void cit()
{
int i,j,sw;
char aux;
ifstream fin("char.in");
fin>>n;
fin.get();
for (i=1;i<=n;i++)
x[i]=fin.get();
fin.get();
fin>>h;
for (i=1;i<=h;i++)
fin>>p[i];
fin.close();
if (sw)
{
k++;
y[k]=x[i];
}
CAPITOLUL 28. ONI 2010 28.1. CHAR 347
for (i=1;i<k;i++)
for (j=i+1;j<=k;j++)
if (y[i]>y[j])
{
aux=y[i];
y[i]=y[j];
y[j]=aux;
}
int putere(char c)
{
int i;
for (i=1;i<=h;i++)
if (y[i]==c)
return p[i];
return 0;
}
int main()
{
cit();
//prima parte
maxx=0;
for (i=1;i<=h;i++)
if (p[i]>maxx)
maxx=p[i];
nr=0;
for (i=1;i<=n;i++)
if (maxx==putere(x[i]))
nr++;
for (i=1;i<n;i++)
for (j=i+1;j<=n;j++)
if (d[i]>d[j])
{
aux=s[i];
s[i]=s[j];
s[j]=aux;
aux=d[i];
d[i]=d[j];
d[j]=aux;
}
i=1;
m=1;
//cout<<s[1]<<" "<<d[1]<<’\n’;
for (j=2;j<=n;j++)
if (s[j]>d[i])
{
m++;
i=j;
// cout<<s[i]<<" "<<d[i]<<’\n’;
}
afis();
return 0;
CAPITOLUL 28. ONI 2010 28.2. MARATON 348
28.2 maraton
Problema 2 - maraton 100 de puncte
Pentru desfăşurarea probei de maraton a poştaşilor, organizatorii au plasat pe traseu n 2
semafoare, la distanţe egale unul de celălalt. Primul semafor e plasat pe linia de start, iar ultimul
semafor este plasat pe linia de sosire şi ambele vor avea aprinsă culoarea verde din momentul ı̂n
care se dă startul şi până la sfârşitul cursei.
Pentru fiecare semafor ı̂ntâlnit pe traseu,
cele trei culori ale sale: roşu, galben şi verde
se aprind succesiv astfel: ı̂ntotdeuna după roşu
se face galben, după galben se face verde, iar
după verde urmează roşu, şi aşa mai departe.
Culoarea roşie a fiecărui semafor se schimbă ı̂n
galben după 5 secunde, galbenul se schimbă ı̂n Figura 28.1: maraton
verde după 3 secunde, iar verdele ı̂n roşu după
2 secunde.
În momentul ı̂n care se dă startul şi se porneşte cronometrul toate cele n semafoare de pe traseu
se aprind. La unele va fi culoarea roşie, la altele galben, iar la altele verde, nefiind sincronizate la
acest moment.
Fiecare poştaş ı̂nscris la maraton trebuie să parcurgă traseul de la linia de start până la linia de
sosire şi să treacă pe rând de cele n semafoare, doar pe culoarea verde a fiecăruia dintre ele. Dacă
un concurent ajunge ı̂n dreptul semaforului şi acesta este verde va trece obligatoriu mai departe.
Dacă ajunge ı̂n dreptul unui semafor chiar ı̂n secunda ı̂n care se schimbă culoarea acestuia, atunci
concurentul poate trece mai departe doar dacă această schimbare s-a facut de la galben la verde,
nu şi de la verde la roşu sau de la roşu la galben.
Cerinţe
Ştiind că poştaşul Andrei parcurge distanţa dintre două semafoare succesive ı̂n k secunde, să
se scrie un program care să determine numărul minim de secunde necesar pentru ca el să treacă
linia de sosire.
Date de intrare
Date de ieşire
Fişierul maraton.out va conţine o singură linie pe care se va scrie numărul natural s, care
reprezintă numărul minim de secunde necesar pentru ca Andrei să treacă de linia de sosire.
Exemple
maraton.in maraton.out Explicaţii
32 25 Se dă startul şi după 2 secunde poştaşul ajunge ı̂n dreptul
0 0 -1 primului semafor. La acesta tocmai se schimbă culoarea din
verde ı̂n roşu şi ca urmare poştaşul nu poate trece. Aşteaptă
8 secunde, se face verde iar după alte 2 secunde ajunge ı̂n
dreptul celui de-al doilea semafor (au trecut 12 secunde de la
start). Aici mai aşteaptă 8 secunde, se face verde şi poate
trece. Parcurge ı̂n 2 secunde distanţa până ı̂n dreptul celui
de-al treilea semafor. Când ajunge ı̂n dreptul acestui semafor
(după 22 secunde de la start) mai aşteaptă o secundă (1), se
face verde şi peste 2 secunde trece linia de sosire (22+1+2=25
secunde).
ifstream f("maraton.in");
ofstream g("maraton.out");
int main()
{
long n,k,i,t,culoare,mai_sta;
long timp=0;
f>>n>>k;
for(i=1;i<=n;i++)
{
f>>culoare;
timp=timp+k;
t=(timp%10);
switch(culoare)
{
case -2:
if(t==8 || t==9)
mai_sta=0;
else
if(t==10)
mai_sta=8;
else
CAPITOLUL 28. ONI 2010 28.2. MARATON 350
mai_sta=8-t;
break;
case -1:
if (t==4)
mai_sta=0;
else
if (t<=3)
mai_sta=3-t;
else
mai_sta=3+(10-t);
break;
case 0:
if(t==0 || t==1)
mai_sta=0;
else
if(t==2)
mai_sta=8;
else
mai_sta=10-t;
break;
}
timp=timp+mai_sta;
}
g<<(timp+k);
return 0;
}
ifstream f("maraton.in");
ofstream g("maraton.out");
int a[6000],n,k;
long s=0;
void citire();
void blabla()
{
for (int i=1;i<=n;i++)
{
s=s+k;
actualizare(i,k);
if(a[i]<8)
{
int v=8-a[i];
actualizare(i,v);
s=s+v;
}
}
}
int main()
{
citire();
blabla();
s+=k;
g<<s;
g.close();
return 0;
}
CAPITOLUL 28. ONI 2010 28.3. ROBOTI 351
void citire()
{
f>>n>>k;
int x;
for(int i=1;i<=n;i++)
{
f>>x ;
if(x==-2)
a[i]=0;
else
if(x==-1)
a[i]=5;
else
a[i]=8;
}
}
28.3 roboti
Problema 3 - roboti 100 de puncte
Într-o zonă dreptunghiulară cu p linii şi q coloane se află n roboţi. Celula din stânga sus se
află pe linia 1 şi coloana 1.
Pentru fiecare robot se cunoaşte linia şi coloana pe care se află, precum şi orientarea lui.
Un robot poate fi orientat ı̂n una din cele patru direcţii: nord, sud, est sau vest, codificate cu
caracterele N, S, E, respectiv V. Fiecare robot execută m comenzi. O comandă este codificată
printr-un caracter L, R sau F. La o comandă de tip L, robotul se ı̂ntoarce cu 90 de grade spre
stânga, ı̂n sensul invers acelor de ceasornic. La o comandă de tip R, robotul se ı̂ntoarce cu 90 de
grade spre dreapta, ı̂n sensul acelor de ceasornic. La o comandă de tip F, robotul se deplasează
cu o poziţie ı̂n sensul ı̂n care este orientat robotul.
Roboţii execută simultan prima comandă din şirul lor de comenzi, apoi a doua comandă, etc.
Dacă la un moment dat, doi sau mai mulţi roboţi ajung ı̂n aceeaşi poziţie, aceasta va conduce
la dispariţia lor, iar celula din care dispar se consideră traversată de toţi cei care au dispărut.
Dacă un robot se deplasează ı̂n afara suprafeţei la execuţia unei comenzi, robotul dispare.
Se consideră trecere printr-o celulă vizitarea rezultată ı̂n urma executării unei comenzi de tip
F. Dacă un robot trece de mai multe ori printr-o celulă, se contorizează fiecare trecere a sa. Celula
din care pleacă fiecare robot se consideră trecere pentru robotul respectiv.
Cerinţe
Date de intrare
Date de ieşire
a 1 & p, q, m & 50
a 2 & n & 50
a Caracterele cu care se codifică orientările pot fi doar N, S, E, V, iar cele pentru comenzi L,
R sau F (litere mari).
a Iniţial, nu există doi sau mai mulţi roboţi ı̂n aceeaşi celulă.
a Se acordă 50% din punctaj pentru rezolvarea cerinţei a) şi 50% pentru cerinţa b).
Exemple
roboti.in roboti.out Explicaţii
44 0 După prima comandă, roboţii 1 şi 2 ar trebui să ajungă ı̂n aceeaşi
3 122 celulă, deci dispar. Al treilea robot conform primei deplasări va
11E părăsi zona, deci dispare. ı̂n final vor fi 0 roboţi. Doi roboţi au
13V ajuns ı̂n celula de pe linia 1 şi coloana 2, după care au dispărut.
44S Prin celelalte celule s-a trecut maxim o singură dată.
2
FL
FF
FF
Se execută mai ı̂ntâi prima comandă de către toţi roboţii, identificând mai ı̂ntâi situaţiile ı̂n
care aceştia părăsesc zona (se verifică dacă după o deplasare de tip F indicele de linie pentru noua
poziţie nu se află ı̂n intervalul 1, p, sau indicele de coloană nu se află ı̂n intervalul 1, q .
Se identifică apoi situaţiile ı̂n care ajung ı̂n aceeaşi celulă mai mulţi roboţi, ţinând cont că cei
care fac comenzi de tip L sau R nu părăsesc zona, iar cei cu comenzi F se vor deplasa ı̂ntr-o nouă
celulă.
Se continuă ı̂n acelaşi mod cu toate comenzile. Se contorizează numărul de roboţi dispăruţi,
pentru a se preciza numărul celor rămaşi ı̂n final, conform cerinţei a).
Trecerea printr-o celulă se marchează ı̂ntr-o nouă matrice care va avea ı̂n final numărul de
treceri prin fiecare celulă. Se determină apoi cel mai mare element din matrice şi poziţia primului
element din matrice egal cu acesta (dacă există mai multe elemente se va scrie poziţia celui cu
indicele de linie cel mai mic, iar la egalitate, cel cu indicele de coloană cel mai mic)
int m, n, nr, l, c;
int x[MAX], y[MAX], tr[MAX][MAX];
char ori[MAX], depl[MAX][MAX];
bool exista[MAX];
void date()
{
int i;
scanf("%d\n", &m);
for (i = 1; i <= n; i++)
fgets(depl[i] + 1, MAX , stdin);
}
*l_nou = l - 1;
break ;
}
}
void deplasare()
{
int i, j, vechil, vechic;
short a[MAX][MAX], b[MAX][MAX], p, q;
n = 0;
for (i = 1; i <= nr; i++)
if ( exista[i] ) ++n;
}
void afisare()
{
int i, j, max, p, q;
printf("%d\n", n);
max = tr[1][1];
p = q = 1;
for (i = 1; i <= l; i++)
for (j = 1; j <= c; j++)
if (tr[i][j] > max)
max = tr[i][j], p = i, q = j;
int main()
{
freopen(FIN,"r",stdin);
freopen(FOU,"w",stdout);
return 0;
}
CAPITOLUL 28. ONI 2010 28.3. ROBOTI 355
357
APPENDIX A. PROGRAMA OLIMPIADEI - GIMNAZIU A.3. CLASA A VII-A 358
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
– Permutări
– Combinări
– Aranjamente
– Utilizarea funcţiilor din biblioteca STL pentru permutări
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
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ă
30
lizibilitate a programelor! Şi oricum ... participanţii la olimpiadă citesc mai mult decât este
31
prevăzut ı̂n programa olimpiadei! Vom folosi modelul de la funcţia main().
int calcul()
{
// instructiuni
return 0;
}
29
https://sepi.ro/page/oni2022
30
https://ro.wikipedia.org/wiki/Lizibilitate
31
tot ce nu este interzis, este permis!
360
APPENDIX B. MAIN(), CIN, COUT, FIN, FOUT B.1. FUNCŢIA MAIN() 361
int main()
{
fin>>c;
fin>>n;
calcul();
return 0;
}
Appendix C
”Instalare” C++
Instalarea este foarte uşoară (este de tipul ”next -> next -> ... -> next”) iar pe in-
ternet sunt multe site-uri de ajutor. De exemplu:
https://www.pbinfo.ro/?pagina=intrebari-afisare&id=26
https://www.youtube.com/watch?v=CLkWRvAwLO8
https://infoas.ro/lectie/112/tutorial-instalare-codeblocks-usor-introducere-in-in
https://www.competentedigitale.ro/c/oji2019/Kit_OJI_2017.rar
362
APPENDIX C. ”INSTALARE” C++ C.1. KIT OJI 2017 363
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
32
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
33
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 364
http://www.codeblocks.org/downloads/source/5
Mai precis:
https://sourceforge.net/projects/codeblocks/files/Binaries/20.03/
http://sourceforge.net/projects/codeblocks/files/Binaries/17.12
http://sourceforge.net/projects/codeblocks/files/Binaries/16.01
De preferat este să avem cel puţin două partiţii: C:¯, D:¯, ... şi să “lăsăm ı̂n pace” partiţia C:¯
pentru sistemul de operare şi programele instalate!
În figura de mai sus se poate observa că pe D:¯ există un folder de lucru pentru programele ı̂n
C++, folder care se numeşte Programe C++. Aici vom salva toate programele C++ pe care
le vom scrie, eventual organizate pe mai multe subfoldere.
Click-dreapta cu mouse-ul şi selectăm “New -¿ Text document” ca ı̂n figura următoare.
APPENDIX C. ”INSTALARE” C++ C.1. KIT OJI 2017 365
Dacă vom executa două click-uri pe numele fşierului p01.cpp sau un click pentru a marca
fişierul şi apoi un ¡Enter¿, se va declanşa Code::Blocks cu p01.cpp ı̂n fereastra de editare şi, ce
este şi mai important, cu Programe C++ ca folder curent de lucru pentru Code::Blocks.
Adică, aici vor apărea toate fişiere generate de Code::Blocks pentru p01.cpp.
Figura C.9: Pregătit pentru a scrie cod de program C++ ı̂n Code::Blocks
APPENDIX C. ”INSTALARE” C++ C.1. KIT OJI 2017 367
Dacă avem fişierele p01.cpp, ..., p05.cpp, ı̂n folderul nostru de lucru, şi facem dublu-click pe
fiecare ... vor apărea toate ...
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
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 373
Se selecteaza “Path” şi click pe “Edit”. Apare fereastra “Edit Environment Variables”
C:¯path
Dacă totul este OK atunci se trece la instalarea IDE-ului preferat (Integrated Development
34
Environment ), de exemplu Code::Blocks 20.03 (sau Eclipse, Visual Studio Code, Dev C++,
NetBeans, şi altele).
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!).
34
https://en.wikipedia.org/wiki/Integrated_development_environment
https://ro.wikipedia.org/wiki/Mediu_de_dezvoltare
APPENDIX C. ”INSTALARE” C++ C.2. WINLIBS 376
Exponenţiere rapidă
Î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)
385
APPENDIX D. EXPONENŢIERE RAPIDĂ D.2. NOTAŢII, RELAŢII ŞI FORMULE 386
2 2 2 4 2 8 2 16
a0 a a1 a0 a a2 a1 a a3 a2 a a4 a3 a
2 32 2 64 2 128
a5 a4 a a6 a5 a a7 a6 a
Dacă notăm ek ”exponentul (puterea)” la care apare ak ı̂n produs, atunci putem observa
uşor că şirul e0 , e1 , e2 , e3 , ... se obţine prin ı̂mpărţiri succesive ale lui n prin 2 şi preluı̂nd restul
rezultatului. Pentru a folmaliza acest lucru vom considera şirul n0 , n1 , n2 , n3 , ... definit astfel:
n0 n,
w
nk nk1 ©2 (câtul ı̂mpărţirii!) k '1
Folosind aceste notaţii, putem scrie:
~
n0 n;
a0 a;
e n0 %2 " r0, 1x;
0
1 a0 , dacă e0 1;
p0
e
a00 sau, altfel scris: p0 w
1, dacă e0 0;
(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.4 Codul
Codul pentru relaţiile (D.2.1) devine:
Observaţia 2. În acest cod actualizarea lui p se face după actualizările pentru a şi n.
Observaţia 3. În codul următor actualizarea lui p se face ı̂naintea actualizărilor pentru a şi n,
corespunzător relaţiilor (D.4.2).
APPENDIX D. EXPONENŢIERE RAPIDĂ D.4. CODUL 388
~
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 389
Observaţia 4. Instrucţiunile care sunt ”ı̂n plus” se pot elimina. Codul următor arată acest lucru:
Observaţia 5. Produsul poate deveni foarte mare şi din cauza asta se cere rezultatul modulo un
număr prim. Codul următor arată acest lucru:
14 a = (a * a)%MOD;
15 n = n / 2;
16 nropr=nropr+6; // n%2, p*a, a*a, (a * a)%MOD si n/2
17 }
18 return p;
19 }
20
21 int main()
22 {
23 int a=1234;
24 int n=1e+9; // 10ˆ9
25 int rezn; // rezultat exponentiere naiva
26
27 rezn=exponentiere_rapida(a,n);
28
29 cout<<"rezr = "<<rezn<<" nropr = "<<nropr<<"\n";
30
31 return 0;
32 }
33 /*
34 rezr = 376 nropr = 180
35
36 Process returned 0 (0x0) execution time : 0.021 s
37 Press any key to continue.
38 */
Numărul de operaţii:
cu metoda naivă acest număr este 2 000 000 000
cu metoda rapidă este 180.
Iar ca număr de operaţii ... una este să faci 2 miliarde de operaţii şi alta este să faci
numai 180 de operaţii de acelaşi tip (de fapt sunt numai 30 de paşi dar la fiecare pas se fac 5
sau 6 operaţii aritmetice)!
35
şi nu mai trebuie ”atâtea formule matematice”!
35
Este o glumă!
Appendix E
Căutare binară
E.1 Mijlocul = ?
Care este poziţia (indicele) ”mijlocului” unei zone dintr-un 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.
393
APPENDIX E. CĂUTARE BINARĂ E.2. POZIŢIE OARECARE 394
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 }
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 }
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 }
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 400
”Vecini” ...
F.1 Direcţiile N, E, S, V
Î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!).
401
APPENDIX F. ”VECINI” ... F.1. DIRECŢIILE N, E, S, V 402
403
INDEX INDEX 404
[1] Aho, A., Hopcroft, J., Ullman, J.D.; Data strutures and algorithms, Addison Wesley, 1983
[2] Andreica M.I.; Elemente de algoritmică - probleme şi soluţii, Cibernetica MC, 2011
[3] Andonie R., Gârbacea I.; Algoritmi fundamentali, o perspectivă C++, Ed. Libris, 1995
[4] Atanasiu, A.; Concursuri de informatică. Editura Petrion, 1995
[5] Bell D., Perr M.; Java for Students, Second Edition, Prentice Hall, 1999
[21] Knuth, D.E.; The art of computer programming, vol. 4A: Combinatorial algorithms, Part
1, Addison Wesley, 2011.
[22] Lambert,K. A., Osborne,M.; Java. A Framework for Programming and Problem Solving,
PWS Publishing, 1999
[23] Laaksonen A.; Guide to competitive programming, Springer, 2017
[24] Livovschi, L.; Georgescu H.; Analiza şi sinteza algoritmilor. Ed. Enciclopedică, Bucureşti,
1986.
[25] Niemeyer, P., Peck J.; Exploring Java, O’Reilly, 1997.
405
BIBLIOGRAFIE BIBLIOGRAFIE 406
[26] Odăgescu, I., Smeureanu, I., Ştefănescu, I.; Programarea avansată a calculatoarelor person-
ale, 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
408
What’s the next?
ORNL’s Frontier First to Break the Exaflop Ceiling
Over time
the following steps
will lead you to the value
you seek for yourself
now!