Documente Academic
Documente Profesional
Documente Cultură
date la olimpiade în
la clasa a 9-a
3 aprilie 2020
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 ecare 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!.
Îmi doresc s prezint elemente simple ³i desene bune care s ajute la descoperirea unei rezolv ri
optime sau care s obµin cât mai multe puncte la olimpiad .
Sunt convins c este util s studiem cu atenµie cât mai multe probleme rezolvate! Din aceast
cauz cred c sunt utile ³i primele versiuni în care sunt prezentate chiar ³i numai enunµurile ³i
indicaµiile "ociale" de rezolvare. Acestea se g sesc în multe locuri; aici încerc s le pun pe toate
la un loc !
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
de rezolvare!).
Am început câteva c rµi (pentru clasele de liceu) cu mai mulµi ani în urm , pentru perioada
2000-2007 ([28] - [32]), 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 ([44] - [49])! Încerc acum
s ajung acolo unde am r mas ... plecând mereu din prezent ... pân când nu va mai posibil ...
a³a c , de aceast dat , anii sunt în ordine ... descresc toare! :-)
Acum voi continua ... cu Enunµuri , Indicaµii de rezolvare ³i Coduri surs ale problemelor
date la olimpiadele judeµene ³i naµionale.
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
disponibil ³i, oricum, calculatoarele folosite la olimpiade înainte de 2010 erau ceva mai 'slabe' ³i
... restricµiile de memorie, din enunµurile problemelor, par 'ciudate' acum!).
Mai departe, va urma 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!). Totu³i, vor prezentate ³i Rezolv ri
detaliate ale problemelor de liceu (pe care le-am considerat în mod subiectiv!) interesante ³i utile.
Vom încerca ³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!
1
IOI2019 a permis utilizarea limbajelor de programare C++ ³i Java (https://ioi2019.az/en-content-14.
html#CompetitionEquipment)
2
IOI2015 a permis utilizarea limbajelor de programare C++, Java, Pascal, Python ³i Rubi (http://ioi2015.
kz/content/view/1/265)
(asta a³a, ca s vedem cum sunt problemele la acest nivel!). Cei care ajung acolo sau vor s ajung
acolo (la IOI) nu au nevoie de ajutorul meu! Se descurc singuri! La Indicaµii de rezolvare voi
prezenta numai ... numele algoritmilor clasici folosiµi în rezolvare.
i un ultim gând: ce am strâns ³i am scris în aceste c rµi se adreseaz celor interesaµi de aceste
teme! Nu cârcota³ilor! Sunt evidente sursele de pe net (³i locurile în care au fost folosite). Nu
sunt necesare preciz ri suplimentare!
Adrese utile:
https://stats.ioinformatics.org/halloffame/
https://stats.ioinformatics.org/tasks/
http://stats.ioinformatics.org/results/ROU
http://www.cplusplus.com/
http://www.info1cup.com/
https://www.infoarena.ro/
https://www.infogim.ro/
http://www.olimpiada.info/
https://www.pbinfo.ro/
http://www.usaco.org/
http://algopedia.ro/
http://campion.edu.ro/
https://codeforces.com/
https://cpbook.net/
https://csacademy.com/
https://gazeta.info.ro/revigoram-ginfo/
https://oj.uz/problems/source/22
https://profs.info.uaic.ro/~infogim/2019/index.html
http://varena.ro/
https://wandbox.org/
https://en.cppreference.com/w/cpp/language/operator_alternative
Despre ...
Despre ...
http://adrianrabaea.scienceontheweb.net/
https://www.scribd.com/user/243528817/Adrian-Rabaea
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
2 OJI 2018 29
2.1 Cuf r . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.1.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.1.2 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.1.3 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.2 fadema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.2.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2.2 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2.3 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.3 tnia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.3.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.3.2 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.3.3 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3 OJI 2017 43
3.1 Ace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.1.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.1.2 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.1.3 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.2 Admitere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.2.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.2.2 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.2.3 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.3 Roboµi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.3.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.3.2 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
iv
3.3.3 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4 OJI 2016 71
4.1 Cifre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.1.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4.1.2 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4.1.3 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4.2 pic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.2.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.2.2 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.2.3 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
5 OJI 2015 83
5.1 arc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5.1.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
5.1.2 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
5.1.3 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
5.2 defrag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
5.2.1 Indicaµii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5.2.2 *Rezolvare detaliat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
5.2.3 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Index 865
Bibliograe 867
Lista gurilor
1.1 deminare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2 deminareIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.1 Cifre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.2 pic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
5.1 defrag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
xviii
32.2 Pereµi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677
32.3 Zumzi1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689
32.4 Zumzi2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 690
32.5 Zumzi3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
32.6 Zumzi4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
xx
Lista programelor
1.1.1 abx_EN_90.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.2 abx_LB_90.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.3 abx_LB_hybrid.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.1.4 abx_LB_hybrid_fast.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.1.5 abx_LB_stable.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.1.6 abx_NM.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.1 deminare_CC3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.2.2 deminare_EN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.2.3 deminare_GM.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2.4 deminare_LB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.2.5 deminare_MP.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.3.1 mostenire_LB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.3.2 mostenire_MLT.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.3.3 mostenire_MP.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.1.1 cufar-100p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.1.2 cufar-dani-100p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2.1 fadema_n6.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.2.2 fadema_n4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.2.3 fadema_n3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.2.4 fadema_n2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.3.1 bruteQN2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.3.2 bruteN2+Q.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.3.3 bruteQN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.3.4 sursa-dani-NlogN.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.1.1 ace_LS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.1.2 ace_MirelaM.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.1.3 ace_priv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.1.4 ace_prmc.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.1.5 ace_tavi.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.2.1 mihai100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.2.2 mihai100comments.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.2.3 priv100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.3.1 roboti_luci.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.3.2 roboti_luci_wosort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.3.3 roboti_priv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.3.4 roboti_prmc.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
4.1.1 CC1_cifre.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4.1.2 CP_cifre.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4.1.3 MLT_cifre.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.2.1 pic_CP1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
4.2.2 picMD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4.2.3 picMLT1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
5.1.1 arc1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
5.1.2 arc2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
5.1.3 arc3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
5.1.4 arc4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
5.2.1 defrag1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
5.2.2 defrag2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
5.2.3 defrag3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
xxi
5.2.4 defrag4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
5.2.5 defrag5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
5.2.6 defrag6.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
6.1.1 CC2_cool.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
6.1.2 cool_eugen_fs.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
6.1.3 cool_eugen_std.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
6.1.4 cool_n2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
6.2.1 pseudobil.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
6.2.2 pseudobil_EN_100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
6.2.3 pseudobil_LS_100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
6.2.4 pseudobil2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
7.1.1 beta_CM1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
7.1.2 beta_CM2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
7.1.3 beta_CM3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
7.1.4 beta_GB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
7.1.5 beta_ZS.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
7.2.1 CC_clepsidru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
7.2.2 MR_clepsidru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
7.2.3 PD_clepsidru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
7.2.4 ZS_clepsidru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
8.1.1 elicopCC.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
8.1.2 elicopDPA.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
8.1.3 elicopGB.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
8.2.1 roataCC.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
8.2.2 roataPC.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
9.1.1 v1_vase.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
9.1.2 v2_vase.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
9.1.3 v3_vase.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
9.2.1 cri_fstream-100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
9.2.2 cricpp1-100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
9.2.3 cricpp2-100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
9.2.4 cricpp3-100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
10.1.1 livada.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
10.1.2 livada_v2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
10.2.1 numar_v1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
12.1.1 concurs.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
12.2.1 pluricex.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
13.1.1 carteleC.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
13.1.2 cartele1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
13.1.3 cartele2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
13.1.4 cartele3.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
13.2.1 PARITATE.C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
13.2.2 Paritate.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
14.1.1 FLORI.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
14.1.2 ori1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
14.1.3 ori2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
14.2.1 PLUTONC.C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
14.2.2 PLUTCARM.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
14.2.3 PLUTRADU.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
14.2.4 pluton1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
14.2.5 pluton2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
15.1.1 numere.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
15.1.2 numere.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
15.2.1 MaxD1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
15.2.2 MaxD2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
16.1.1 EXP.PAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
16.1.2 Expresie1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
16.1.3 Expresie2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
16.1.4 Expresie3.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
16.2.1 REACT_QS.PAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
16.2.2 REACTIVI.C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
16.2.3 reactivp.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
16.2.4 reactivi.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
17.1.1 TEXT.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
17.1.2 text.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
17.2.1 numere.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
17.2.2 numere.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
18.1.1 poarta.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
18.2.1 mouce.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
19.1.1 alex-nnlog.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
19.1.2 alex-nqlog.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
19.1.3 amat_eugen.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
19.1.4 brut.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
19.1.5 brut_IQ_9000 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
19.1.6 chiorean_amat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
19.1.7 solution.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
19.1.8 sursa_test.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
19.2.1 comun_back.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
19.2.2 comun_chiorean.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
19.2.3 comun_eugen.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
19.2.4 comun_io.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
19.2.5 comun_nlog_sub.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
19.2.6 comun_sol.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
19.2.7 sol_nlog.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
19.3.1 pro3_AT1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
19.3.2 pro3_CC1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
19.3.3 pro3_CC2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
19.3.4 pro3_LB1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
19.4.1 cub_chiorean.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
19.4.2 cub_chiorean_brut.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
19.4.3 cub_chiorean_n3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
19.4.4 cub100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
19.4.5 cub100_int.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
19.5.1 bofrac_CC1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
19.5.2 bofrac_CC2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
19.5.3 bofrac_CC3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
19.5.4 bofrac_CC4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
19.5.5 bofrac_CC5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
19.5.6 bofrac_TC1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
19.6.1 alex.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
19.6.2 telefon-adrian-100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
19.6.3 telefon-bicsi-100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
19.6.4 tudor_telefon_v2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
20.1.1 1_bazaf.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
20.1.2 2_bazaf.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
20.1.3 3_bazaf.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
20.1.4 4_bazaf.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
20.2.1 mexitate1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
20.2.2 mexitate2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
20.3.1 plaja_N+K.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
20.3.2 plaja_ternara.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
20.3.3 plaja1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
20.3.4 plaja2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
20.3.5 plaja3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
20.3.6 plaja4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
20.4.1 bsrec.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
20.4.2 bsrec2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
20.5.1 1_numinum_100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
20.5.2 2_numinum_100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
20.6.1 rosiimici.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
20.6.2 rosiimici2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
21.1.1 arhipelag_100p_1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
21.1.2 arhipelag_100p_2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
21.2.1 mirror_100p_1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
21.2.2 mirror_100p_2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
21.2.3 mirror_100p_3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
21.2.4 mirror_100p_4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
21.2.5 mirror_100p_5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
21.2.6 mirror_100p_6.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
21.3.1 okcpp_97p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
21.3.2 okcpp_100p_1_doar_linux.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 362
21.3.3 okcpp_100p_2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
21.4.1 adlic_100p_1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
21.4.2 adlic_100p_2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
21.4.3 adlic_100p_3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
21.5.1 bomboane_100p_1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
21.5.2 bomboane_100p_2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
21.5.3 bomboane_100p_3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
21.6.1 orase_100p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
22.1.1 civilizatie_BICSI.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
22.1.2 civilizatie100p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
22.2.1 cmmdc_BICSI.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
22.3.1 livada_dan.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
22.3.2 Livada100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
22.4.1 dif2_bicsi.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
22.4.2 dif2_eric.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
22.4.3 dif2_N_log2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
22.5.1 leduri_bicsi.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
22.5.2 leduri_eric.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
22.6.1 omogene_eric.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
22.6.2 omogene_n_4.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
22.6.3 omogeneMG.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
23.1.1 cubul_cp1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
23.1.2 cubul_cp2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
23.1.3 cubul_gcc_2matrici.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
23.1.4 cubul_gcc_umplere_ciur.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
23.1.5 cubul_mot_e.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
23.2.1 risc.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
23.2.2 risc_n2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
23.2.3 risc_nlogn.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
23.3.1 roboti_aib.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
23.3.2 roboti_dp.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
23.3.3 roboti_greedy.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
23.4.1 casa.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
23.4.2 casa_slow.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
23.4.3 casa2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
23.5.1 lenes.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
23.5.2 lenes2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
23.5.3 lenes3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
23.6.1 sipet.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
24.1.1 harta.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
24.1.2 harta_Adriana.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464
24.1.3 harta_brut_1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466
24.1.4 harta_brut_2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468
24.1.5 harta_eugen.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470
24.1.6 harta_pit.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471
24.1.7 harta1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
24.2.1 qvect_eugen_bf.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
24.2.2 qvect_eugen_fs.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 477
24.2.3 qvect_eugen_std.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478
24.2.4 qvect_inter.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480
24.2.5 qvect_mink.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
24.2.6 qvect_qsort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483
24.2.7 qvect_qsortscanf.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484
24.2.8 qvect_vs.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
24.3.1 tg_100p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
24.3.2 tg_on.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491
24.3.3 tg_on_v2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491
24.3.4 tg_on2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492
24.3.5 tg_onsqrtn.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492
24.4.1 CC2_progresie.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
24.4.2 CC3_progresie.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
24.4.3 CM_progresie.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496
24.4.4 EN_progresie.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496
24.4.5 PIT_progresie.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497
24.4.6 SP_progresie.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497
24.5.1 reex_eugen.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 500
24.5.2 reex_LS_brut.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501
24.5.3 reex_LS_Euclid_100p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
24.5.4 reex_LS_med.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
24.5.5 reex_LS_Sr_100p.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504
24.5.6 reex_vs.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505
24.6.1 traseu_carmen_nerec.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508
24.6.2 traseu_carmen_rec.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510
24.6.3 traseu_eugen.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
24.6.4 traseu_vspit.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513
25.1.1 aranjare.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516
25.2.1 gradina.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518
25.3.1 split.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520
25.4.1 momente.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524
25.5.1 secvente.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527
25.6.1 spider.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530
26.1.1 PIT_7segmente.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534
26.1.2 CC_7segmente.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535
26.1.3 RH_7segmente.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536
26.2.1 PIT_copaci.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539
26.2.2 RH_copaci.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540
26.2.3 VI_copaci.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540
26.3.1 PIT1_intersectii.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543
26.3.2 PIT2_intersectii.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544
26.3.3 brut_intersectii.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
26.3.4 GM_intersectii.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
26.3.5 VI_intersectii.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
26.4.1 CTpalindrom.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549
26.4.2 RHpalindrom.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551
26.4.3 VIpalindrom.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553
26.5.1 PRIVsstabil_1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557
26.5.2 PRIVsstabil_2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557
26.5.3 VI_sstabil.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558
26.6.1 GMunuab_100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 560
26.6.2 GMunuab_back.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
26.6.3 GMunuab_n patrat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
26.6.4 VI_unuzero.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 562
27.1.1 poligon.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565
27.2.1 stalpi.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568
27.3.1 tort.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572
27.4.1 ape.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574
27.5.1 ec.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 576
27.6.1 furnici.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 580
28.1.1 cern100v1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584
28.1.2 cern100v2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585
28.2.1 cmmmc60.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 588
28.2.2 cmmmc100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590
28.3.1 simetric20.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
28.3.2 simetric40.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
28.3.3 simetric100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595
28.4.1 pesti.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597
28.5.1 plaja.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600
28.6.1 tango.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
29.1.1 joc.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
29.2.1 perspic.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 609
29.3.1 rafturi.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612
29.4.1 br.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615
29.5.1 origami.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
29.6.1 patrate.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
30.1.1 ab.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 623
30.2.1 iepuras.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 626
30.3.1 palind.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 629
30.3.2 palindvxn.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630
30.3.3 palindvxv.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 631
30.4.1 auto.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633
30.4.2 autonk.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634
30.5.1 div_rares.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636
30.6.1 teatru.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639
30.6.2 teatru_n2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639
30.6.3 teatru_n3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640
31.1.1 agitatie.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
31.2.1 coduri.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 646
31.3.1 lacuri.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 650
31.4.1 secv.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
31.5.1 sotron.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656
31.6.1 triunghi.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 659
32.1.1 fact.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662
32.1.2 factok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663
32.1.3 fact.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664
32.2.1 limbaj.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666
32.2.2 limbaj1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 668
32.2.3 limbaj2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 670
32.3.1 panouri.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673
32.3.2 panouri1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674
32.3.3 panouri2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675
32.4.1 pereti.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678
32.4.2 peretiok.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679
32.4.3 pereti.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680
32.5.1 sant.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 683
32.5.2 sant1.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 685
32.5.3 sant.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 687
32.6.1 zumzi.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
32.6.2 zumzi1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694
32.6.3 zumzi2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696
33.1.1 bifo0.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
33.1.2 bifo1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702
33.1.3 bifo2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703
33.2.1 romeo.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708
33.3.1 seceta1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 710
33.3.2 seceta2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712
33.3.3 seceta3.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 714
33.3.4 seceta4.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715
33.4.1 biblos1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 719
33.4.2 biblos2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 719
33.4.3 biblos3.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720
33.5.1 joc.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 723
33.6.1 pal.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 728
34.1.1 COD_OK.PAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 732
34.1.2 CODURI.PAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 734
34.1.3 coduri.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 734
34.2.1 logic.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736
34.2.2 logic0.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 738
34.2.3 logic1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 738
34.2.4 logic2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 740
34.3.1 poligon.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 742
34.3.2 poligon.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 744
34.4.1 sablon.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 748
34.4.2 sablon0.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 749
34.4.3 sablon1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 750
34.5.1 sir.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752
34.5.2 sir.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752
34.6.1 snipers.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 754
34.6.2 snipers.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 755
35.1.1 seti.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758
35.1.2 seti0java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 759
35.1.3 seti1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 760
35.2.1 scaune.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 762
35.2.2 scaune1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 763
35.2.3 scaune2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 764
35.3.1 ALLCIRC.C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 767
35.3.2 Circback.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 768
35.3.3 CIRCULAR.C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769
35.3.4 circular1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 771
35.3.5 circular2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 771
35.4.1 criptare.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 774
35.4.2 criptare1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775
35.4.3 criptare2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 776
35.5.1 masina.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 778
35.6.1 operatii.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 780
36.1.1 pentagon.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 782
36.1.2 pentagon.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783
36.2.1 PODBACK.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 786
36.2.2 PODDBIG.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787
36.2.3 PODIN.CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 789
36.2.4 pod1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 790
36.2.5 pod2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791
36.2.6 pod3.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 792
36.3.1 suma.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796
36.3.2 suma.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796
36.3.3 becuri1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801
36.3.4 becuri2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802
36.3.5 becuri3.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803
36.4.1 discuri.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807
36.4.2 discuri.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 808
36.5.1 cod.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 810
36.5.2 codcomb.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811
36.5.3 cod.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 812
37.1.1 ferma1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 815
37.1.2 ferma2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 816
37.2.1 fractii.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 818
37.3.1 tablou1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 819
37.3.2 tablou2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 820
37.4.1 competitie.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 822
37.5.1 cuvinte.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824
37.6.1 grup.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 826
38.1.1 Algoritm-oc.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 830
38.1.2 algoritm1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 832
38.1.3 algoritm.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 833
38.2.1 cod2.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835
38.2.2 cod-oc.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836
38.2.3 cod1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837
38.2.4 cod2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837
38.2.5 cod3.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838
38.3.1 comoara-oc.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
38.3.2 comoara.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 842
38.4.1 cuburi-oc.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 845
38.4.2 cuburi.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847
38.5.1 sb.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 848
38.5.2 sbmare.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 849
38.5.3 bo.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851
38.6.1 KMIHAI.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854
38.6.2 KOM_MEU.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 855
38.6.3 Kommando-oc.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 856
38.6.4 VERKOMM.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 857
38.6.5 kommando1.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858
38.6.6 kommando2.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859
38.6.7 kommando3.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 861
38.6.8 kommando4.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863
Partea I
1
Capitolul 1
OJI 2019
1.1 abx
Problema 1 - abx 90 de puncte
Un num r natural n se nume³te putere dac exist dou numere naturale a, b, a ' 1, b ' 2
b 5 2 2
astfel încât n a . De exemplu, numerele 32, 169, 1 sunt puteri (32 2 , 169 13 , 1 1 ), iar
72, 2000 ³i 31 nu sunt puteri. Se citesc numerele naturale N , M ³i un ³ir de N numere naturale
x1 , x2 , ..., xN din intervalul 1, M .
Cerinµe
Pentru ecare din cele N numere xi determinaµi câte un num r natural ri din intervalul 1, M ,
cu proprietatea c ri este o putere ³i pentru orice alt putere p din intervalul 1, M este îndeplinit
condiµia ¶xi ri ¶ & ¶xi p¶, unde ¶x¶ reprezint valoarea absolut a lui x (modulul).
Dac exist dou puteri egal dep rtate de xi se va alege puterea cea mai mic . De exemplu
pentru num rul 26, dintre puterile 25 ³i 27 va ales num rul 25.
Date de intrare
Fi³ierul de intrare abx.in conµine pe prima linie dou numere N ³i M , iar pe ecare dintre
urm toarele N linii se g se³te câte un num r natural xi (1 & i & N ), cu semnicaµia de mai sus.
Numerele aate pe aceea³i linie a ³ierului sunt separate prin câte un spaµiu.
Date de ie³ire
Fi³ierul de ie³ire abx.out va conµine N linii, pe ecare linie i (1 & i & N ) aându-se num rul
natural ri cu semnicaµia din enunµ.
Restricµii ³i preciz ri
a 1 & N & 5000
10 & M & 10
18
a
a Pentru teste valorând 40 de puncte M & 5000
a Pentru teste valorând 70 de puncte M & 109
Exemple
abx.in abx.out Explicaµii
3
8 1000 343 343 7
2
345 100 100 10
3
99 1000 1000 10
9
999 512 512 2
2
500 121 121 11
3
123 125 125 5
2
124 100 100 10
8
99 256 256 2
256
Timp maxim de executare/test: 1.0 secunde
Memorie: total 32 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 10 KB
Sursa: abx.cpp, abx.c sau abx.pas va salvat în folderul care are drept nume ID-ul t u.
2
CAPITOLUL 1. OJI 2019 3
Soluµie 40p:
Pentru ecare num r x din ³irul dat trebuie s c ut m cea mai apropiat putere, deci vom
avea de efectuat N c ut ri. Pentru a c uta r spunsul pentru un num r dat x, vom avansa în cele
dou direcµii (dreapta, stânga) pân num rul de la pasul curent este putere. Mai apoi, îl vom
a³a pe cel mai apropiat dintre cele dou .
Pentru a verica dac un num r y este putere , o variant este descompunerea lui y în factori
primi. Dac cel mai mare divizor comun al exponenµilor este mai mare decât 1, y este o putere.
Este esenµial observaµia c nu are rost s veric m de mai multe ori dac un num r este
putere sau nu. În acest context, putem precalcula pentru ecare num r din intervalul 1, M dac
acesta este putere ³i stoca acest lucru într-un vector caracteristic.
O soluµie care rezolv problema în complexitate O M N M ar trebui s obµin cel puµin
40 de puncte.
Soluµie 70p:
Vom considera o variant diferit de a genera toate puterile din intervalul 1, M consider m
b b
ecare baz posibil a ³i ad ug m a pornind cu b de la valoarea 2 ³i incrementându-l cât timp a
nu dep ³e³te M . Se observ c ³irul rezultat va avea mai puµin de 50.000 de puteri (eliminând du-
plicatele). Pentru a g si cele dou puteri apropiate de x, vom sorta vectorul, eliminând duplicatele
³i vom efectua o c utare binar pe acest vector sortat.
Se poate demonstra c complexitatea acestei soluµii este O sqrt M N log M . O astfel
de soluµie ar trebui s obµin cel puµin 70 de puncte.
Soluµie 90p:
Pentru subtask-ul M & 10 se poate observa c soluµia de 70 de puncte nu se mai încadreaz în
18
limitele de timp ³i de memorie. Pentru a rezolva problema în acest caz, exist mai multe abord ri;
toate aceste abord ri ar trebui s obµin punctajul maxim, dac sunt implementate cu atenµie:
C utare binar : Pentru un exponent b xat, se poate aa baza maxim a pentru care ab & x.
b b
Mai apoi, singurii candidaµi pentru r spuns sunt a sau a 1 . Complexitatea algoritmului de
c utare binar este O b log M (exponenµiere iterativ ) sau O log b log M (exponenµiere
logaritmic ). O soluµie care caut binar cele dou puteri pentru ecare exponent posibil (2 & b &
60) folosind exponenµierea iterativ are complexitate O N log2 M ³i ar trebui s obµin 90 de
puncte. În continuare vom prezenta optimiz ri extra, care îmbun t µesc ³i mai mult timpul de
execuµie.
Considerarea doar a exponenµilor primi: O optimizare substanµial a soluµiei anterioare
o constituie observaµia c , pentru a considera toate puterile posibile, este sucient s consider m
b b b d
doar exponenµii care sunt primi, deoarece dac n a , cu b d , atunci n a , deci orice
putere de exponent b va considerat în cadrul exponentului d. În intervalul 2, 60 sunt doar 17
numere prime.
Abordare hibrid : O alt soluµie o reprezint precalcularea puterilor pentru b ' 4 într-o
manier similar soluµiei de 70 de puncte ³i folosirea c ut rii binare pentru cazul b 2 sau b 3.
Aceast soluµie are complexitate O sqrt sqrt M N log M . Menµion m c o astfel de
soluµie va obµine un timp de execuµie foarte bun, nedep ³ind 0.1 secunde pe un test maximal.
Posibile gre³eli:
Erori de precizie: Menµion m c folosirea unei abord ri oating-point (folosirea funcµiei
pow) este înceat ³i poate conduce la erori substanµiale de precizie; astfel, nu este recomandat
s e folosit în cadrul soluµiei, dar cu puµin atenµie poate folosit cu succes, mai ales pentru
valori mici de-ale lui M .
Erori de overow: În abordarea de 90 de puncte, ne vom întâmpina de problema overow-
ului, care trebuie tratat cu grij . O variant simpl de a evita astfel de erori este ca, la ecare
înmulµire a b s veric m mai întâi dac a b & M . Cum a b poate da rezultate eronate, vom
verica ca a & M ©b. O soluµie care nu trateaz corect overow-ul va putea obµine între 70 90
de puncte în funcµie de alte detalii de implementare.
8
9 using namespace std;
10
11 const long long kInf = 2e18 + 10;
12 long long max_base[80];
13
14 long long Power(long long b, int e)
15 {
16 long long r = 1;
17 for (int i = 0; i < e; ++i)
18 {
19 if (1.0L * r * b > 6e18)
20 return kInf;
21 r *= b;
22 }
23 return r;
24 }
25
26 long long Root(long long x, int ex)
27 {
28 long long b = 1, e = max_base[ex], ans = 1;
29
30 while (b <= e)
31 {
32 long long m = (b + e) / 2;
33 if (Power(m, ex) <= x)
34 {
35 ans = m;
36 b = m + 1;
37 } else e = m - 1;
38 }
39
40 return ans;
41 }
42
43 int main()
44 {
45 ifstream cin("abx.in");
46 ofstream cout("abx.out");
47
48 int n; long long m; cin >> n >> m;
49 assert(1 <= n && n <= 1e5);
50 assert(10 <= m && m <= 1e18);
51
52 for (int ex = 2; ex <= 64; ++ex)
53 {
54 max_base[ex] = kInf;
55 max_base[ex] = Root(m, ex);
56 }
57
58
59 long long max_diff = 0;
60 for (int i = 0; i < n; ++i)
61 {
62 long long x; cin >> x;
63 long long ans = 1;
64 assert(1 <= x && x <= m);
65
66 for (int ex = 2; ex <= 64; ++ex)
67 {
68 long long root = Root(x, ex);
69 long long c1 = Power(root, ex), c2 = Power(root + 1, ex);
70
71 if (c1 <= m && make_pair(abs(c1 - x), c1) <
72 make_pair(abs(ans - x), ans))
73 ans = c1;
74
75 if (c2 <= m && make_pair(abs(c2 - x), c2) <
76 make_pair(abs(ans - x), ans))
77 ans = c2;
78 }
79
80 cout << ans << ’\n’;
81 max_diff = max(max_diff, abs(ans - x));
82 }
83
CAPITOLUL 1. OJI 2019 6
71
72 auto it = lower_bound(cands.begin(), cands.end(), x);
73 upd( *it);
74
75
76 if (it != cands.begin())
77 upd( * prev(it));
78
79 long long sqrt = Sqrt(x);
80 upd(sqrt * sqrt);
81 upd((sqrt + 1) * (sqrt + 1));
82
83 cout << ans << ’\n’;
84 }
85
86
87 return 0;
88 }
55 {
56 aux /= i;
57 if (aux)
58 {
59 cand *= i;
60 cands.push_back(cand);
61 }
62 else
63 break;
64 }
65 }
66
67 sort(cands.begin(), cands.end());
68
69 cands.erase(unique(cands.begin(), cands.end()), cands.end());
70
71 for (int i = 0; i < n; ++i)
72 {
73 long long x; cin >> x;
74 long long ans = 1;
75
76 auto upd = [&](long long now)
77 {
78 if (now > m) return;
79 if (abs(now - x) < abs(ans - x) ||
80 (abs(now - x) == abs(ans - x) && now < ans))
81 ans = now;
82 };
83
84 auto it = lower_bound(cands.begin(), cands.end(), x);
85
86 upd( *it);
87 if (it != cands.begin())
88 upd( *prev(it));
89
90 long long a2 = Solve2(x);
91
92 upd(a2 * a2);
93 upd((a2 + 1) * (a2 + 1));
94
95 long long a3 = Solve3(x);
96
97 upd(a3 * a3 * a3);
98 upd((a3 + 1) * (a3 + 1) * (a3 + 1));
99
100 cout << ans << ’\n’;
101 }
102
103 return 0;
104 }
47 break;
48 }
49
50 q=putere(k,pr[j]);
51 if (q>v[i])
52 {
53 q1=q;
54 q=putere(k-1,pr[j]);
55 }
56 else
57 {
58 q1=putere(k+1,pr[j]);
59 if (q1<=v[i])
60 {
61 q=q1;
62 q1=putere(k+2,pr[j]);
63 }
64 }
65
66 if (v[i]-q<=dif)
67 {
68 p=q;
69 dif=v[i]-q;
70 }
71
72 if (q1<=m && q1-v[i]<dif)
73 {
74 p=q1;
75 dif=q1-v[i];
76 }
77 }
78
79 fo<<p<<"\n";
80 }
81
82 return 0;
83 }
1.2 deminare
Problema 2 - deminare 90 de puncte
Pe un teren de form dreptunghiular format din L linii ³i C coloane sunt plantate M mine.
Liniile sunt numerotate de sus în jos cu valori de la 1 la L iar coloanele sunt numerotate de la
stânga la dreapta cu valori de la 1 la C .
Deoarece r zboiul s-a terminat, speciali³tii vor s demineze terenul ³i s -l redea utiliz rii pu-
blice.
Mutarea unei mine reprezint operaµia de transfer a unei mine de la linia x1 ³i coloana y1 la
o poziµie liber , dat de linia x2 ³i coloana y2 , unde 1 & x1 , x2 & L ³i 1 & y1 , y2 & C .
Deoarece mutarea unei mine este periculoas , trebuie determinat num rul minim de mine care
trebuie mutate din poziµia iniµial astfel încât toate minele de pe teren s e a³ezate unele lâng
altele într-o zon compact dreptunghiular , oriunde în cadrul terenului dat, pentru ca apoi s e
detonate împreun .
Spre exemplu: dac L 4, C 5, M 8 ³i minele sunt a³ezate iniµial conform gurii de mai
jos (zonele colorate cu negru arat poziµiile minelor), pentru a se ajunge la o a³ezare a minelor
într-o zon compact de form dreptunghiular num rul minim de mine mutate este 3.
CAPITOLUL 1. OJI 2019 11
Cerinµe
Cunoscând num rul de linii L ³i de coloane C ale terenului minat, num rul de mine M , precum
³i poziµia ec rei mine, s se scrie un program care determin :
1. linia sau liniile pe care se g sesc cele mai multe mine;
2. num rul minim de mine mutate, pentru ca toate minele de pe teren s e a³ezate într-o
zon compact cu form dreptunghiular .
Date de intrare
Fi³ierul de intrare este deminare.in ³i conµine:
- pe prima linie num rul natural V a c rui valoare poate doar 1 sau 2;
- pe a doua linie dou numere naturale L ³i C , cu semnicaµia din enunµ;
- pe a treia linie num rul natural M , cu semnicaµia din enunµ;
- pe ecare din urm toarele M linii, câte o pereche de valori xi ³i yi , 1 & i & M , reprezentând
linia, respectiv coloana, unde se a o min ;
Numerele aate pe aceea³i linie a ³ierului sunt separate prin câte un spaµiu.
Date de ie³ire
Fi³ierul de ie³ire este deminare.out.
Dac valoarea lui V este 1 atunci prima linie a ³ierului de ie³ire va conµine num rul liniei pe
care se g sesc cele mai multe mine.
Dac exist dou sau mai multe astfel de linii, se vor a³a toate numerele acestora, în ordine
cresc toare, separate prin câte un spaµiu.
Dac valoarea lui V este 2 atunci ³ierul de ie³ire va conµine pe prima linie num rul minim cerut
de mine mutate. Dac minele nu pot a³ezate într-o zon compact de form dreptunghiular ,
în ³ierul de ie³ire se va scrie valoarea 1.
Restricµii ³i preciz ri
a 1 & L, C & 500
a 1&M &L C
a O zon în care se a mine a³ezate pe coloane consecutive, pe aceea³i linie sau a³ezate pe
linii consecutive, pe aceea³i coloan se consider c formeaz o zon compact de form dreptun-
ghiular .
a O zon compact de form dreptunghiular poate avea num rul de linii ocupate egal cu
num rul de coloane ocupate.
a Pentru teste valorând 20 de puncte, avem V 1
a Pentru teste valorând 70 de puncte, avem V 2
a Pentru teste valorând 20 de puncte, avem V 2 ³i L C & 10000
a Pentru teste valorând 32 de puncte, avem V 2 ³i L C & 100000
Exemple
deminare.in deminare.out Explicaµii
CAPITOLUL 1. OJI 2019 12
Consideraµii preliminare
Rezolvarea problemei necesit utilizarea structurilor de date de tip tablou.
Cerinµa 1
Se utilizeaz un tablou bidimensional cu L linii ³i C coloane pentru memorarea poziµiei minelor
din problem .
Se poate calcula num rul de mine de pe ecare linie ³i rezultatul îl putem reµine într-un tablou
unidimensional.
Se determin apoi maximul dintre valorile obµinute anterior ³i se parcurge înc o dat vectorul
num rului de mine ³i dac exist mai multe linii ce reµin un num r egal cu valoarea maxim
anterior determinat se a³eaz indicele liniei respective.
Cerinµa 2
Soluµia I (brute force)
Se descompune num rul de mine M în produs de 2 numere naturale, M a b. Pentru ecare
dintre perechile a ³i b anterior determinate cu proprietatea (1 & a & L ³i 1 & b & C ) se scaneaz
matricea terenului cu zone dreptunghiulare de dimensiuni a b ³i se determin num rul maxim
de valori de 1 dintr-o astfel de zon sau num rul minim de valori de 0.
Este mai ecient s determin m num rul de valori de 1 pentru c acest lucru se poate face
prin însumare, decât num rul de valori de 0, operaµie ce presupune utilizarea repetat a unei
instrucµiuni de decizie.
Nu ne intereseaz unde este a³ezat aceast zon în interiorul terenului. Zona astfel determi-
nat corespunde acelei zone pentru care se vor face cele mai puµine mut ri, având în vedere c
num rul de mine este M (M a b) ³i c aceast zon are cele mai puµine elemente nule.
Este posibil s nu existe o astfel de zon , dac descompunerea lui M nu conµine nici m car o
pereche de numere a ³i b cu 1 & a & L ³i 1 & b & C . În acest caz în ³ierul de ie³ire se a³eaz 1.
Soluµia anterior prezentat obµine aproximativ 50 puncte.
Soluµia II (Sume parµiale pe matrice)
CAPITOLUL 1. OJI 2019 13
Num rul de 1 din zona galben este egal cu num rul de 1 din toate zonele colorate - num rul
de 1 din zona albastr - num rul de 1 din zona maronie + num rul de 1 din zona colorat
în ambele culori.
O astfel de soluµie obµine 90 puncte.
Observaµii:
a Are mare importanµ cum se construie³te matricea sumelor parµiale. Acest subalgoritm se
2 2
poate realiza în O L C sau O L C L C sau O L C . Prima varianta conduce la punctaje
mai mici chiar ³i decât cele obµinute cu brute force!
a O modalitate ecient de construcµie a acestei matrice folose³te tot algoritmul descris ante-
rior. Fiecare valoare din poziµia i, j se determin pe baza valorilor din poziµiile i 1, j , i, j 1
³i i 1, j 1 cât ³i a valorii din matricea iniµial de pe poziµia i, j .
6 #include <cassert>
7
8 using namespace std;
9
10 int a[501][501];
11 int w[501],mat[501][501];
12
13 int main()
14 {
15 int l,c,i,j,k,m,x,y,maxl,s,v,maxm,ls,cs,ok,i1,j1;
16
17 /* l = linii
18 c = coloane
19 m = numar de mine
20 x,y = coordonate mina
21 v = varianta
22 maxm = numarul maxim de mine dintr-o zona de scanare
23 maxl = numarul maxim de mine de pe o linie
24 k = contorul pentru numararea minelor dintr-o zona de scanare
25 ok = indicator pentru a determina daca problema are solutie
26 ls, cs = numarul de linii si coloane al zonei de scanare
27 */
28 ifstream f("deminare.in");
29 ofstream g("deminare.out");
30
31 // citire date de intrare
32 f >> v;
33 assert(v>=1 && v <=2);
34
35 f >> l >> c;
36 assert(l>=1 && l<=500);
37 assert(c>=1 && c<=500);
38
39 f >> m;
40 assert(m>=1 && m<=l*c);
41
42 int perechi = 0;
43 while(f>>x>>y)
44 {
45 assert(x>=1 && x<=l);
46 assert(y>=1 && y<=c);
47 perechi++;
48 a[x][y]=1;
49 }
50
51 // prima cerinta
52 if (v == 1)
53 {
54 // cerinta = care este linia pe care se gasesc cele mai multe mine
55 // daca sunt mai multe linii se afiseaza toate in ordine crescatoare
56 // cu spatiu intre ele
57
58 // aflu numarul de mine pe linii
59 for(i=1;i<=l;i++)
60 {
61 s=0;
62 for(j=1;j<=c;j++)
63 if(a[i][j]==1) s++;
64 w[i]=s;
65 }
66
67 // aflu maximul de mine de pe o linie
68 maxl=w[1];
69 for(i=1;i<=l;i++)
70 if (w[i]>maxl) maxl=w[i];
71
72 // afisez linia(iile)
73 for(i=1;i<=l;i++)
74 if (w[i]==maxl) g << i << " ";
75 g << "\n";
76 }
77
78
79 // cerinta a doua
80 if(v == 2)
81 {
CAPITOLUL 1. OJI 2019 15
11
12 int main()
13 {
14 int i, j, k;
15 freopen("deminare.in", "r", stdin);
16 freopen("deminare.out","w", stdout);
17
18 scanf("%d", &v);
19 scanf("%d%d", &L, &C);
20 scanf("%d", &m);
21
22 for(k=1; k<=m; ++k)
23 {
24 scanf("%d%d", &i, &j);
25 a[i][j] = 1;
26 nL[i]++;
27 }
28
29 if (v == 1)
30 {
31 for(i=1; i<=L; ++i)
32 if (nL[i] > Max) Max = nL[i];
33 for(i=1; i<=L; ++i)
34 if (nL[i] == Max) printf("%d ", i);
35 return 0;
36 }
37 else
38 {
39 for(i=1; i<=L; ++i)
40 for(j=1; j<=C; ++j)
41 Nr[i][j] = Nr[i-1][j] + Nr[i][j-1] - Nr[i-1][j-1] + a[i][j];
42
43 for(int d=1; d*d<=m; ++d)
44 if (m % d == 0)
45 {
46 int lx = d, ly = m / d;
47
48 ///parcurgem toate submatricile
49 for(i=lx; i<=L; ++i)
50 {
51 int i1 = i - lx;
52 for (j=ly; j<=C; ++j)
53 {
54 int j1 = j - ly;
55 int w = Nr[i][j] - Nr[i][j1] - Nr[i1][j] + Nr[i1][j1];
56 if (w > Max) Max = w;
57 }
58 }
59
60 lx = m/d, ly = d;
61 for(i=lx; i<=L; ++i)
62 {
63 int i1 = i - lx;
64 for (j=ly; j<=C; ++j)
65 {
66 int j1 = j - ly;
67 int w = Nr[i][j] - Nr[i][j1] - Nr[i1][j] + Nr[i1][j1];
68 if (w > Max) Max = w;
69 }
70 }
71 }
72
73 if (Max)
74 printf("%d", m - Max);
75 else
76 printf("-1\n");
77 }
78
79 return 0;
80 }
3 #include <bits/stdc++.h>
4
5 using namespace std;
6
7 ifstream in("deminare.in");
8 ofstream out("deminare.out");
9
10 int ma[510][510],a[510][510],v[510],t,lin,col,dim,np,z,mx;
11
12 int main()
13 {
14 in>>t>>lin>>col>>dim;
15 int x,y;
16
17 while(in>>x>>y)
18 np++, ma[x][y]=1;
19
20 if(t==1)
21 {
22 for(int i=1;i<=lin;++i)
23 {
24 int w=0;
25 for(int k=1;k<=col;++k)
26 w+=ma[i][k];
27 v[i]=w;
28 }
29
30 mx=v[1];
31 for(int i=1;i<=lin;++i)
32 if(v[i]>mx)
33 mx=v[i];
34
35 for(int i=1;i<=lin;++i)
36 if(v[i]==mx)
37 out<<i<<’ ’;
38
39 out<<’\n’;
40 }
41 else
42 {
43 for(int i=1;i<=lin;++i)
44 for(int j=1;j<=col;++j)
45 a[i][j]=ma[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1];
46
47 z=0,mx=0;
48 for(int i=1;i*i<=dim;++i)
49 if(dim%i==0)
50 {
51 int l1=i,c1=dim/i;
52 if(l1<=lin && c1<=col)
53 {
54 z=1;
55 for(int ii=1;ii<=lin-l1+1;++ii)
56 for(int jj=1;jj<=col-c1+1;++jj)
57 {
58 int p=a[ii+l1-1][jj+c1-1]-a[ii+l1-1][jj-1];
59 p=p-a[ii-1][jj+c1-1]+a[ii-1][jj-1];
60 if(p>mx)
61 mx=p;
62 }
63 }
64 //====================================
65
66 l1=dim/i,c1=i;
67 if(l1<=lin && c1<=col)
68 {
69 z=1;
70 for(int ii=1;ii<=lin-l1+1;++ii)
71 for(int jj=1;jj<=col-c1+1;++jj)
72 {
73 int p=a[ii+l1-1][jj+c1-1]-a[ii+l1-1][jj-1];
74 p=p-a[ii-1][jj+c1-1]+a[ii-1][jj-1];
75 if(p>mx)
76 mx=p;
77 }
78 }
CAPITOLUL 1. OJI 2019 18
79 }
80
81 if(z==0)
82 out<<"-1\n";
83 else
84 out<<dim-mx<<"\n";
85 }
86
87 out.close();
88 return 0;
89 }
62 {
63 int x, y; cin >> x >> y;
64 cnt[x - 1] += 1;
65 best = max(best, cnt[x - 1]);
66 }
67
68 for (int i = 0; i < n; ++i)
69 if (cnt[i] == best)
70 cout << i + 1 << " ";
71 cout << endl;
72 }
73 else
74 {
75 vector<pair<int, int>> v;
76
77 for (int i = 0; i < k; ++i)
78 {
79 int x, y; cin >> x >> y;
80 v.emplace_back(x, y);
81 }
82
83 sort(v.begin(), v.end());
84
85 int best = -1;
86 for (int d = 1; d <= k; ++d)
87 {
88 if (k % d) continue;
89 if (d > m || k / d > n) continue;
90
91 SegmTree st(m + d + 1);
92
93 int j = 0;
94 for (int i = 0; i < k; ++i)
95 {
96 st.Update(v[i].second, v[i].second + d, 1);
97 while (v[j].first == v[i].first - k / d)
98 {
99 st.Update(v[j].second, v[j].second + d, -1);
100 ++j;
101 }
102
103 best = max(best, st.Query());
104 }
105 }
106
107 if (best == -1)
108 cout << -1 << endl;
109 else
110 cout << k - best << endl;
111 }
112 }
98 }
1.3 mostenire
Problema 3 - mostenire 90 de puncte
Împ ratul cel b trân vrea s împart sacii cu galbeni din vistieria palatului celor K feciori
ai s i, numerotaµi de la 1 la K în ordinea vârstei. Feciorul cu num rul 1 este cel mai mare, iar
mezinul are num rul K .
În vistierie sunt N saci plini cu galbeni, a³ezaµi în linie, atât de grei încât nu li se poate schimba
ordinea, iar pe ecare sac este scris num rul de galbeni pe care îi conµine.
Împ ratul îl cheam pe unul dintre feciori ³i îi spune: Fiule, a ta este averea primilor x1
saci! . Feciorul ia sacii ³i pleac fericit. Apoi, împ ratul cheam alt fecior ³i îi spune: Fiule, a ta
este averea primilor x2 saci dintre cei r ma³i! . ³i a³a mai departe, pân ajunge la ultimul fecior
chemat, c ruia îi d toµi sacii r ma³i.
El nu are o ordine anume în care î³i cheam feciorii dar are grij s cheme ecare fecior exact o
dat . Totodat , pentru a evita certurile între ei, este atent ca ecare fecior s primeasc cel puµin
un sac cu galbeni, dar s NU primeasc în total mai mulµi galbeni ca un frate mai mare decât el.
Cel mai mic dintre feciorii împ ratului este ³i cel mai viteaz, a³a c împ ratul ar vrea s îi dea lui
o sum de bani cât mai mare, f r a-i sup ra pe ceilalµi feciori ai s i.
Cerinµe
Cum ar putea împ rµi împ ratul sacii?
Date de intrare
Fi³ierul de intrare mostenire.in conµine pe prima linie numerele naturale N , K , separate de
un spaµiu, cu semnicaµia din enunµ. Pe urm toarele N linii se g se³te câte un num r natural,
reprezentând num rul de galbeni din ecare sac, în ordinea în care ace³tia urmeaz s e distribuiµi
ilor.
Date de ie³ire
Fi³ierul de ie³ire mostenire.out va conµine pe prima linie suma de galbeni pe care o va primi
ul cel mic de la împ rat. Pe urm toarele K linii se vor aa câte dou numere naturale ce
reprezint num rul de ordine al feciorului, respectiv num rul de saci xi pe care îi prime³te acesta,
în ordinea în care au fost chemaµi de împ rat.
Restricµii ³i preciz ri
a2 & K & 100
aK & N & 100000
a 1 & Num rul de galbeni din ecare sac & 100000
a Galbenii din oricare dintre saci nu pot împ rµiµi mai multor fraµi
9
a Num rul total de galbeni aaµi în vistierie este mai mic sau egal cu 10
a Împ ratul cel b trân nu are doi feciori cu aceea³i vârst
a Puteµi a³a orice soluµie în care mezinul prime³te num rul maxim posibil de galbeni
a Pentru ecare test, a³area corect a num rului maxim de galbeni primiµi de mezin este
notat cu 40% din punctajul alocat testului
a Pentru teste valorând 10 puncte N K , N & 100
a Pentru teste valorând 30 de puncte 2 & K $ N & 15
a Pentru teste valorând 50 de puncte 2 & K $ N & 100
Exemple
mostenire.in mostenire.outExplicaµii
CAPITOLUL 1. OJI 2019 22
Soluµia I - N K - 10p
În acest caz, ecare fecior va lua cate un sac din cei N . Vom împ rµii sacii astfel: feciorul 1 va
lua sacul cu cei mai mulµi galbeni, feciorul 2 pe urm torul ³.a.m.d. pân când feciorul cel mai mic
ia sacul cu cei mai puµini galbeni. În caz de egalitate nu trebuie s facem nimic special pentru c
un fecior mai mare poate primi aceea³i sum de galbeni ca un fecior mai mic.
Construim 3 vectori:
ai - num rul de galbeni al ec rui sac i în ordinea din ³ierul de intrare;
indi - indicele sacului (iniµial indi i);
f iui - indicele ului ce va lua sacul respectiv (necompletat iniµial).
Sort m descresc tor vectorul a modicând ³i vectorul ind corespunz tor. Pe prima line putem
a³ valoarea celui mai mic sac, aN .
Apoi, vom completa vectorul u printr-o parcurgere de la stânga la dreapta: f iui i.
În acest moment un grup ai, indi, f iui reprezint nr de galbeni din sac, indicele iniµial
al sacului ³i indicele ului ce va primi acel sac. Pentru a reconstrui împ rµirea, sort m cresc tor
vectorul ind modicând ³i vectorul f iu corespunz tor. Acum în vectorul f iu avem ordinea în care
trebuie chemaµi feciorii de împart.
Pentru c avem de sortat vectorii, complexitatea timp a acestei soluµii este O N log N sau
2
O N , în funcµie de algoritmul de sortare ales.
Pentru ecare împ rµire posibil , calcul m cât ia ecare u ³i ordinea în care feciorii sunt
chemaµi folosind un raµionament similar cu cel de la Soluµia I: calculam toate cele K sume de
galbeni într-un vector pe care îl sort m descresc tor.
Atribuim ului cu indicele 1 cea mai mare sum de galbeni, apoi ului 2 urm toarea cea mai
mare sum de galbeni (NU uit m ca poate egal cu cea precedent ), ³.a.m.d. Mezinul va lua
cea mai mic sum de galbeni. Pentru a³area împ rµirii este necesar înc o sortare a ilor dup
indicii sacilor luaµi.
N
Complexitatea acestei soluµii este exponenµial , O 2 . O soluµie de aceast complexitate ar
trebui s primeasc cel puµin 30 de puncte.
Reconstrucµia împ rµirii
Se poate adapta soluµia de mai sus pentru a a³a ³i cele K subsecvenµe alese, în cazurile valide.
Pentru a asigna cele K subsecvenµe celor K i, trebuie s ne asigur m c averile vor atribuite
ilor în ordinea vârstei sale. Acest lucru se va realiza prin doi pa³i:
Pasul 1: A m ecare subsecvenµ c rui u îi aparµine. Pentru aceasta, atribuim ec rei
subsecvenµe numere de la 1 la K , în ordinea descresc toare a num rului de galbeni. Acest lucru
se poate realiza printr-o sortare.
Pasul 2: A³ m lungimea subsecvenµei ³i ul corespunz tor, în ordinea de la stânga la dreapta.
O atenµie special trebuie acordat cazului în care soluµia de mai sus va a³a mai mult de
K subsecvenµe, caz în care unele subsecvenµe vecine vor trebui contopite. Din fericire, îns , se
poate observa c putem alege s contopim oricare dou subsecvenµe vecine, soluµia r mânând
valid .
2
Complexitatea reconstrucµiei este O N sau O N log N , în funcµie de algoritmul de sortare
ales.
71 assert(ans != -1);
72 cout << ans << endl;
73
74 auto sol = Solve(v, k, ans);
75
76 sort(sol.rbegin(), sol.rend());
77
78 vector<tuple<int, int, int>> new_sol;
79
80 for (int i = 0; i < k; ++i)
81 {
82 int b, e; tie(ignore, b, e) = sol[i];
83 new_sol.emplace_back(b, i, e - b);
84 }
85
86 sort(new_sol.begin(), new_sol.end());
87
88 for (auto itr : new_sol)
89 {
90 int i, cnt; tie(ignore, i, cnt) = itr;
91 cout << i + 1 << " " << cnt << ’\n’;
92 }
93
94 return 0;
95 }
48 {
49 int Mid = (Left + Right) / 2;
50 if(Check(Mid))
51 {
52 Sol = Mid;
53 Left = Mid + 1;
54 }
55 else
56 Right = Mid - 1;
57 }
58 }
59
60 bool Compare(int A, int B)
61 {
62 return Sum[A] > Sum[B];
63 }
64
65 void Print()
66 {
67 int j = 0;
68 fout << Sol << "\n";
69 Sum[1] = Bags[1] = 0;
70 j = 1;
71 for(int i = 1; i<= N; ++i)
72 {
73 Sum[j] += X[i];
74 Bags[j]++;
75 if(Sum[j] >= Sol)
76 {
77 Sum[++j] = 0;
78 Bags[j] = 0;
79 }
80 }
81
82 Sum[K] += Sum[K+1];
83 Bags[K] += Bags[K+1];
84
85 for(int i = 1; i <= K; ++i)
86 Index[i] = i;
87
88 sort(Index + 1, Index + K + 1, Compare);
89
90 for(int i = 1; i <= K; ++i)
91 Sum[Index[i]] = i;
92
93 for(int i = 1; i <= K; ++i)
94 fout << Sum[i] << " " << Bags[i] << "\n";
95 }
96
97 int main()
98 {
99 Read();
100 Solve();
101 Print();
102 return 0;
103 }
17 int s;
18 int st; int dr;
19 };
20
21 bool solve(int s_mezin, std::vector<int>& a, int& k)
22 {
23 int cnt = 0, s = 0;
24
25 for (int i = 0; i < a.size(); ++i)
26 {
27 s += a[i];
28 if (s >= s_mezin) {
29 ++cnt;
30 if (cnt == k) {
31 break;
32 }
33 s = 0;
34 }
35 }
36 if (cnt == k) {
37 return true;
38 }
39 return false;
40 }
41
42 void imparte(const int& s_mezin, std::vector<int>& a,
43 const int& k, std::vector<Fiu>& sol)
44 {
45 int cnt = -1, last = -1, s = 0;
46
47 for (int i = 0; i < a.size(); ++i) {
48 s += a[i];
49 if (s >= s_mezin) {
50 ++cnt;
51 sol[cnt].st = last + 2;
52 sol[cnt].dr = i + 1;
53 sol[cnt].s = s;
54 if (cnt == k - 1) {
55 sol[cnt].dr = a.size();
56 for (int j = i + 1; j < a.size(); ++j) {
57 s += a[j];
58 }
59 sol[cnt].s = s;
60 break;
61 }
62 last = i;
63 s = 0;
64 }
65 }
66
67 sort(sol.begin(), sol.end(), [](const Fiu& A, const Fiu& B) -> bool {
68 return A.s > B.s;
69 });
70
71 for (int i = 0; i < sol.size(); ++i) {
72 sol[i].ind = i + 1;
73 }
74
75 sort(sol.begin(), sol.end(), [](const Fiu& A, const Fiu& B) -> bool {
76 return A.st < B.st;
77 });
78 }
79
80 int main()
81 {
82 std::ifstream cin("mostenire.in");
83 std::ofstream cout("mostenire.out");
84
85 int n, k;
86 cin >> n >> k;
87 assert(k <= n && n <= N);
88 assert(2 <= k && k <= K);
89
90 std::vector<int> a(n);
91 long long stotal = 0;
92 for (int i = 0; i < n; ++i) {
CAPITOLUL 1. OJI 2019 28
OJI 2018
2.1 Cuf r
Problema 1 - Cuf r 100 de puncte
Vr jitoarea cea bun are un cuf r în care este închis piatra magic de c tre piticii l zii cu
ajutorul unui cifru digital. Piticii i-au dat vr jitoarei o cutie în care sunt n cartona³e. Pe ecare
cartona³ este scris un num r natural pe care vr jitoarea îl va folosi s deschid lada. Valorile
scrise pe cartona³e sunt distincte între ele.
Pentru a aa cifrul trebuie s procedeze astfel: extrage ecare cartona³ din cutie ³i apoi
determin valoarea magic asociat num rului natural scris pe cartona³. Pentru ecare cartona³
valoarea magic este dat de al k -lea divizor prim al num rului înscris pe acesta. Vr jitoarea
trebuie s adune valorile magice obµinute pentru cele n cartona³e ³i apoi s introduc în ordine
cifrele valorii obµinute, pentru a descuia lada.
Cerinµe
Deoarece vr jitoarea nu are timp la dispoziµie v roag pe voi s o ajutaµi s rezolve urm toarele
probleme:
1. S ae valoarea magic pentru un cartona³ dat;
2. S ae cifrul cuf rului.
Date de intrare
Fi³ierul de intrare este cufar.in.
Pe prima linie a ³ierului de intrare se g sesc o valoare p care poate doar 1 sau 2 ³i num rul
n de cartona³e desp rµite prin câte un spaµiu.
Dac p este 1 pe linia a doua a ³ierului de intrare se g sesc dou valori reprezentând num rul
de pe cartona³ul dat ³i valoarea k , separate printr-un spaµiu, cu semnicaµia de mai sus.
Dac p este 2 pe urm toarele n linii ale ³ierului de intrare se g sesc câte dou valori, separate
prin câte un spaµiu, reprezentând num rul de pe cartona³ ³i valoarea lui k pentru ecare din cele
n cartona³e.
Date de ie³ire
Fi³ierul de ie³ire este cufar.out.
Dac valoarea lui p este 1, atunci se va rezolva doar cerinµa 1 ³i ³ierul de ie³ire va conµine pe
prima linie valoarea magic asociat cartona³ului dat.
Dac valoarea lui p este 2, atunci se va rezolva doar cerinµa 2 ³i ³ierul de ie³ire va conµine pe
prima linie cifrul necesar deschiderii cuf rului.
Restricµii ³i preciz ri
a 1 & n $ 1000000
a 2 & valoarea înscris pe un cartona³ & 1000000
a Se garanteaz c pentru ecare pereche (num r, k ), num r are cel puµin k divizori primi.
a Pentru rezolvarea corect a cerinµei 1 se acord 18 puncte
a Pentru rezolvarea corect a cerinµei 2 se acord 72 de puncte
a Pentru rezultate corecte la cerinµa a doua respectând restricµiile problemei ³i n & 1000 se
acord 18 puncte
29
CAPITOLUL 2. OJI 2018 30
a Pentru rezultate corecte la cerinµa a doua respectând restricµiile problemei ³i n & 500000 se
acord 43 de puncte
a Din ociu se acord 10 puncte.
Exemple
cufar.in cufar.out Explicaµii
11 5 p = 1, n = 1
30 3 Se rezolv doar prima cerinµ
Al 3-lea divizor prim al num rului 30 este 5
25 48 p = 2, n = 5
30 3 Se rezolv doar a doua cerinµ
64 1 Al 3-lea divizor prim al num rului 30 este 5
105 2 Primul divizor prim al num rului 64 este 2
1001 3 Al 2-lea divizor prim al num rului 105 este 5
5474 4 Al 3-lea divizor prim al num rului 1001 este 13
Al 4-lea divizor prim al num rului 5474 este 23
Suma c utat va S = 5 + 2 + 5 + 13 + 23,
de unde rezult cifrul 48
Se num r cu ajutorul ciurului lui Eratostene câµi divizori primi are ecare din numerele
naturale mai mici sau egale cu 1000000. În momentul când pentru unul din numerele scrise pe
cartona³e se ajunge la numarul de divizori c utat se adaug la sum valoarea num rului prim ce
a condus la atingerea num rului de divizori c utat.
26 }
27
28 }
29 else
30 {
31 for(i=1;i<=n;i++)
32 {
33 scanf("%d%d",&j,&c);
34 k[j]=c;
35 }
36
37 for(i=2;i<=1000000;i++)
38 if(a[i]==0)
39 for(j=1;j<=1000000/i;j++)
40 {
41 a[i*j]++;
42 if(a[i*j]==k[i*j])
43 {
44 s=s+i;
45 }
46 }
47
48 printf("%lld",s);
49 }
50
51 fclose(stdin);
52 fclose(stdout);
53 return 0;
54 }
2.2 fadema
Problema 2 - fadema 100 de puncte
Corina a cump rat de la magazin un material din pânz colorat , de form dreptunghiular
pentru a decupa din el o faµ de mas pentru masa din buc t rie. Fiindc este pasionat de ³ah,
Corina a ales un material format din n m p trate de aceea³i dimensiune colorate cu alb sau
negru. P tratele sunt lipite ³i sunt dispuse pe linii ³i coloane paralele cu laturile dreptunghiului din
pânz care a fost cump rat. Dou p trate se numesc vecine dac au în comun o latur . Materialul
din pânz nu respect neap rat structura unei table de ³ah, adic p tratele vecine pe aceea³i linie
sau pe aceea³i coloan nu sunt în mod necesar colorate în mod alternativ.
Corina î³i propune prin urmare s decupeze un dreptunghi cu un num r maxim de p trate,
paralel cu laturile dreptunghiului din pânz care a fost cump rat, care s respecte alternanµa
culorilor pe o tabl de ³ah.
Cerinµe
Sa se determine num rul maxim de p trate întregi ale unui dreptunghi cu laturile paralele cu
cele ale materialului cump rat, care poate decupat astfel încât s nu existe dou p trate vecine
având aceea³i culoare.
Date de intrare
Fi³ierul fadema.in conµine pe prima linie dou numere naturale n ³i m reprezentând num rul
de linii, respectiv num rul de coloane ale materialului din pânz care a fost cump rat.
Pe ecare dintre urm toarele n linii se a câte m cifre 0 sau 1 desp rµite prin câte un spaµiu,
reprezentând culorile p tratelor materialului. Cifra 0 codic culoarea alb , iar cifra 1 codic
culoarea neagr .
Date de ie³ire
Fi³ierul fadema.out va conµine pe prima linie un singur num r natural A, reprezentând nu-
m rul maxim de p trate ale unui dreptunghi care poate decupat astfel încât s respecte cerinµa
din enunµ. Dac nu exist dreptunghiuri cu cel puµin dou p trate având culori alternante, se va
scrie valoarea 1.
Restricµii ³i preciz ri
2 & N & 1000
a
2 & M & 1000
a
a Pentru rezolvarea corect a cerinµei respectând restricµiile problemei se acord 90 de puncte
a Pentru rezultate corecte respectând restricµiile problemei ³i n, m & 100 se acord 20 de
puncte
a Pentru rezultate corecte respectând restricµiile problemei ³i n, m & 200 se acord 40 de
puncte
a Pentru rezultate corecte respectând restricµiile problemei ³i n, m & 400 se acord 65 de
puncte
a Din ociu se acord 10 puncte
Exemple
fadema.in fadema.out Explicaµii
3 4 6 Dreptunghiul delimitat de liniile 1 ³i 3, respectiv coloanele 2 ³i
0 0 10 3 are 6 p trate (fundal de culoare gri)
1 1 00
1 0 10
4 5 5 Dreptunghiul delimitat de linia 2, respectiv coloanele 1 ³i 5 are
0 1 1 0 1 5 p trate (fundal de culoare gri)
1 0 1 0 1
0 0 1 1 0
1 1 0 1 1
Complexitate O n6 - 20 de puncte
4
Se genereaz în O n toate submatricile cuprinse între liniile i1 ³i i2, respectiv coloanele j1
2
³i j2. Fiecare asemenea submatrice se parcurge în O n ³i se veric validitatea sa.
Complexitate O n4 - 40 de puncte
Se construie³te ³irul r1, r2, ..., rn cu valori 0, 1 sau 2. rk (1 & k & n) va 0 dac
ak i este 0, rk 1 dac ak i 1 ³i rk 2 dac linia k a submatricei nu respect
condiµia de alternanµ . În continuare, se va c uta în ³irul r cea mai lung secvenµ alternant .
Fie L lungimea acesteia. Atunci num rul de elemente a submatricei alternante este L j i 1.
Soluµia va maximul acestor valori:
Complexitate O n3 - 65 de puncte
Se procedeaz ca mai sus, doar c validitatea liniei k se veric pe m sur ce se modic
lungimea liniei, adic odat cu cre³terea valorii j . Aceasta duce la eliminarea unei parcurgeri de
linie, iar complexitatea algoritmului scade cu un ordin de m rime.
Complexitate O n2 - 90 puncte
Calcul m submatricea de dimensiune maxim ce s-ar putea obµine pornind spre dreapta ³i în
jos de la ecare element al matricei ³i respect cerinµa din enunµ. Facem apoi acela³i calcul spre
sânga ³i în jos.
Realiz m suma dimensiunilor celor dou submatrici pentru ecare element al matricei ³i ma-
ximul dintre aceste sume este valoarea c utat .
Pentru a calcula submatricea de dimensiune maxima ce s-ar putea obµine pornind spre dreapta
³i în jos de la ecare element al matricei avem nevoie de:
a) Lungimea maxim lStij a unui ³ir de elemente cu proprietatea din enunµ pornind de la
2
ecare element aij al matricei spre stânga. Aceste lungimi pot calculate în O n parcurgân
matricea de la dreapta spre stânga. Pentru ecare element
aij ! aij 1 avem lStij lStij 1 1 ³i
Stij 1 pentru elementele cu aij aij 1 ³i pentru j m.
b) Lungimea maxim lJosij a unui ³ir de elemente cu proprietatea din enunµ pornind de
2
la ecare element aij al matricei în jos. Aceste lungimi pot calculate în O n parcurgând
matricea de jos în sus analog punctului a).
c) Produsul dintre lungimea maxim lJosij ³i minimul lungimilor maxime lSt al elemen-
telor care aparµin sub³irului lJosij (adic minimul valorilor lStk j al elementrlor ak j
pentru k i, i 1, ..., i lJosij reprezint dimensiunea submatricei. Aceste minime pot
2
calculate în O n pentru toat matricea parcurgând-o de jos în sus ³i p strând minimul dintre
lStij ³i lStij 1 pentru toate elementele aij ! aij 1 iar pentru elementele cu
aij aij 1 ³i pentru j m p stram lStij .
Analog se procedeaz ³i pentru submatricea de dimensiune maxima ce s-ar putea obµine por-
nind spre stânga ³i în jos de la ecare element al matricei.
Observaµie: la punctajele de mai sus se adaug 10 puncte din ociu
19 int main()
20 {
21 fin >> n >> m;
22 for (int i = 0; i < n; ++i)
23 for (int j = 0; j < m; ++j)
24 fin >> a[i][j];
25
26 for (int i = 0; i < m; i++)
27 for (int j = i; j < m; j++)
28 {
29 for (int k = 0; k < n; k++)
30 {
31 bool ok = true;
32 for (int c = i + 1; c <= j && ok; c++)
33 if ( a[k][c] == a[k][c - 1])
34 ok = false;
35
36 if (ok)
37 L[k] = a[k][i];
38 else
39 L[k] = 2;
40 }
41
42 int hmax = 0, h = 0;
43 for (int k = 0; k < n; k++)
44 {
45 if ( L[k] == 2 )
46 h = 0;
47 else
48 {
49 if ( h > 0 && L[k - 1] != L[k] )
50 h++;
51 else
52 h = 1;
53 }
54
55 hmax = max(hmax, h);
56 }
57
58 nmax = max(nmax, hmax * (j - i + 1));
59 }
60
61 fout << nmax;
62 fin.close();
63 fout.close();
64 }
37 }
38 else
39 {
40 mr2[i][j]=1;
41 }
42 }
43 }
44 }
45
46 for(int i=1;i<=n;i++)
47 {
48 for(int j=1;j<=m;j++)
49 {
50 if(j==1)
51 {
52 mr1[i][j]=1;
53 }
54 else
55 {
56 if(a[i][j]+a[i][j-1]==1)
57 {
58 mr1[i][j]=mr1[i][j-1]+1;
59 }
60 else
61 {
62 mr1[i][j]=1;
63 }
64 }
65 }
66 }
67
68 for(int i=1;i<=n;i++)
69 {
70 for(int j=1;j<=m;j++)
71 {
72 if(i==1)
73 {
74 mc1[i][j]=mr1[i][j];
75 mc2[i][j]=mr2[i][j];
76 mc[i][j]=1;
77 }
78 else
79 {
80 if(a[i][j]+a[i-1][j]==1)
81 {
82 mc1[i][j]=min(mc1[i-1][j],mr1[i][j]);
83 mc2[i][j]=min(mc2[i-1][j],mr2[i][j]);
84 mc[i][j]=mc[i-1][j]+1;
85 }
86 else
87 {
88 mc1[i][j]=mr1[i][j];
89 mc2[i][j]=mr2[i][j];
90 mc[i][j]=1;
91 }
92 }
93 }
94 }
95
96 int M=1;
97 for(int i=1;i<=n;i++)
98 {
99 for(int j=1;j<=m;j++)
100 {
101 if(M<mc[i][j]*(mc1[i][j]+mc2[i][j]-1))
102 M=mc[i][j]*(mc1[i][j]+mc2[i][j]-1);
103 }
104 }
105
106 out << M << endl;
107 return 0;
108 }
CAPITOLUL 2. OJI 2018 38
2.3 tnia
Problema 3 - tnia 100 de puncte
Se d o matrice binar cu n coloane ³i m linii. Coloanele sunt numerotate de la stânga la
dreapta cu valori de la 1 la n, iar liniile sunt numerotate de jos în sus cu valori de la 1 la m.
Matricea dat are o form particular , astfel c pentru ecare coloan i de la 1 la n toate
elementele matricei de pe coloana respectiv au valoarea 1 pentru toate liniile cuprinse în intervalul
1, hi ³i în rest valoarea 0. Valorile hi sunt numere naturale date în ordine cresc toare
(hi 1 & hi, 1 & i & n).
Cerinµe
S se r spund la q întreb ri de forma: dându-se numerele A, B , C , D se cere suma elementelor
din submatricea determinat de zona dreptunghiular având colµul stânga-jos în coloana A ³i linia
B , iar colµul dreapta-sus în coloana C ³i linia D.
Date de intrare
Fi³ierul de intrare este tnia.in.
pe prima linie se g sesc dou numere naturale n ³i m desp rµite printr-un spaµiu, cu semni-
a
caµia de mai sus;
a pe a doua linie sunt cele n elemente hi ale vectorului desp rµite prin câte un spaµiu;
a pe a treia linie este un num r natural q ce reprezint num rul de întreb ri;
a pe urm toarele q linii se g sesc câte 4 numere A, B , C , D cu semnicaµia de mai sus,
desp rµite prin câte un spaµiu.
Date de ie³ire
Fi³ierul de ie³ire tnia.out va conµine q linii reprezentând r spunsul pentru ecare întrebare.
Restricµii ³i preciz ri
a 0 & hi & m, 1 & n & 100000
a 1 & q & 100000, 1 & m & 1000000000
a Pentru 15 puncte: n, m, q & 100
a Pentru alte 16 puncte: n, m, q & 3000
a Pentru alte 16 puncte: n & 100000, m & 1000000000, q & 100
a Pentru rezolvarea corect a cerinµei se acord 90 de puncte
a Din ociu se acord 10 puncte.
Exemple
tnia.in tnia.out Explicaµii
5 10 30 Zona dreptunghiular având colµul stânga-jos la coloana 1 ³i
2 3 7 8 10 6 linia 1 ³i colµul dreapta-sus la coloana 5 ³i linia 10 are suma
5 5 elementelor 30.
1 1 5 10 0 Analog, pentru celelalte patru întreb ri, r spunsurile corecte
2 5 4 7 6 sunt: 6, 5, 0 ³i 6
3 2 3 6
3 8 3 10
3 2 3 10
Putem construi iniµial întreaga matrice. Pentru ecare query (întrebare), parcurgem subma-
tricea ³i facem suma elementelor.
2
Complexitate: O N Q
51 }
52
53 return 0;
54 }
25 answer = mid;
26 left = mid + 1;
27 }
28 else
29 right = mid - 1;
30 }
31 return answer;
32 }
33
34 int main ()
35 {
36
37 freopen("tnia.in","r",stdin);
38 freopen("tnia.out","w",stdout);
39
40 scanf("%d%d",&n,&m);
41 for(int i = 1; i <= n; i++)
42 scanf("%d",&height[i]);
43
44 for(int i = 1; i <= n; i++)
45 partial_sums[i] = partial_sums[i - 1] + height[i];
46
47 scanf("%d",&q);
48 for(int i = 1; i <= q; i++)
49 {
50 scanf("%d%d%d%d", &downL.x, &downL.y, &topR.x, &topR.y);
51
52 int poz1 = binarySearch(downL.x, topR.x, downL.y);
53 int poz2 = binarySearch(downL.x, topR.x, topR.y);
54
55 // printf("am obtinut %d %d\n", poz1, poz2);
56
57 printf("%lld\n", partial_sums[poz2] -
58 partial_sums[poz1] -
59 ((long long)poz2 - poz1) * (downL.y - 1) +
60 ((long long)topR.x - poz2) * (topR.y - downL.y + 1));
61 }
62
63 return 0;
64 }
Capitolul 3
OJI 2017
3.1 Ace
Problema 1 - Ace 100 de puncte
Pe o zon în form de dreptunghi cu laturile de lungimi N ³i M se g sesc N M p trate de
latur 1. În centrul ec rui p trat se g se³te înpt câte un ac de grosime neglijabil . Fiecare
ac este descris de în lµimea sa. Aceast zon se poate reprezenta ca un tablou bidimensional de
dimensiuni N ³i M , iar ecare element din matrice reprezint în lµimea (num r natural nenul)
ec rui ac. În centrul p tratului N, M exist o camer de luat vederi de ultim generaµie,
o
mobil , care se poate roti cu 360 în orice plan, situat la nivelul solului. Dimensiunile camerei
sunt neglijabile. De exemplu, dac avem zona sub forma:
Cerinµe
1. Câte ace vede camera de luat vederi dac se poate roti în plan vertical, doar în direcµiile N
³i V ?
2. Câte ace vede camera de luat vederi dac se poate roti în orice plan ³i în orice direcµii?
Date de intrare
Fi³ierul de intrare ace.in conµine pe prima linie num rul P care poate 1 sau 2, pentru prima,
respectiv a doua cerinµ . Pe a doua linie se g sesc numerele N , M reprezentând dimensiunile
tabloului, apoi pe urm toarele N linii câte M numere naturale, desp rµite prin câte un spaµiu,
reprezentând în lµimile acelor.
43
CAPITOLUL 3. OJI 2017 44
Date de ie³ire
Fi³ierul de ie³ire ace.out va conµine pe prima linie num rul de ace v zute pentru cerinµ
indicat de valoarea num rului P .
Restricµii ³i preciz ri
a2 & N & 1000
a2 & M & 1000
a Elementele matricei sunt numere naturale nenule mai mici decât 1000, cu excepµia num rului
de pe linia N ³i coloana M care este 0.
a Pentru rezolvarea corect a cerinµei 1 se acord 20 puncte, pentru rezolvarea corect a cerinµei
2 se acord 70 de puncte, iar din ociu se acord 10 de puncte.
a Pentru cerinµa 2 exist teste în valoare de 20 puncte cu N, M & 50.
a Pentru cerinµa 2 exist teste în valoare de 45 puncte cu N, M & 100.
Exemple
ace.in ace.out Explicaµii
1 3 Pentru cerinµa 1 avem direcµiile N ³i V:
4 4 Pentru direcµia N, camera va vedea acul de coordonatele (3,4) -
8 5 4 7 în totalitate, iar acul (2,4) se va vedea doar parµial. Acul (1,4)
2 7 4 6 nu se va vedea pentru c este acoperit total de (2,4).
5 5 3 2 în direcµia V, camera va vedea doar acul (4,3), deoarece acele
6 6 3 0 (4,2) ³i (4,1) sunt acoperite total de acul (4,3).
2 11 Pentru cerinµa 2 camera va vedea cele 3 ace din direcµiile N
4 4 ³i V(vezi mai sus) ³i 8 pentru celelalte direcµii se vor vedea
8 5 4 7 parµial sau în totalitate acele (3,3), (3,2), (3,1), (2,3), (1,3),
2 7 4 6 (2,2), (2,1),(1,2). Acul (1,1) nu se vede din cauza celui de pe
5 5 3 2 (2,2) care il acoper total. Acul (2,2) se vede doar parµial, pentru
6 6 3 0 c o parte din el este acoperit de acul (3,3).
2 8 Pentru cerinµa 2 camera va vedea în N (3,3), (2,3), în V va
4 3 vedea (4,2). în celelalte direcµii camera va vedea parµial sau în
5 4 7 totalitate acele (3,2), (3,1), (2,2), (1,2), (1,1).
6 4 6
5 3 2
6 3 0
32 //VEST
33 xmax=1;
34 ymax=a[n][m-1];
35 for(i=m-2,j=2;i>=1;i--,j++)
36 mai_mare(j,a[n][i]);
37
38 return k;
39 }
40
41 void rezolva_2()
42 {
43 //parcurg matricea din coltul dreapta_jos spre 1,1
44 // si merg pe "diagonale"
45 int i,j,difx,dify,l,c;
46 for(i=n-1;i>=1;i--)
47 for(j=m-1;j>=1;j--)
48 if(a[i][j]!=-1)
49 {
50 xmax=m-j;
51 ymax=a[i][j];
52 k++;
53 difx=n-i;
54 dify=m-j;
55 a[i][j]=-1;
56 for(l=i-difx,c=j-dify;l>=1&&c>=1;l-=difx,c-=dify)
57 if(a[l][c]!=-1)
58 {
59 mai_mare(m-c,a[l][c]);
60 a[l][c]=-1;
61 }
62 }
63
64 fout<<k<<’\n’;
65 }
66
67 void citire()
68 {
69 int i,j;
70 fscanf(fin,"%d",&ct);
71 fscanf(fin,"%d",&n);
72 fscanf(fin,"%d",&m);
73
74 for(i=1;i<=n;i++)
75 for(j=1;j<=m;j++)
76 fscanf(fin,"%d",&a[i][j]);
77
78 rez_a=rezolva_1();
79 if(ct==1)
80 {
81 fout<<rez_a<<’\n’;
82 return;
83 }
84
85 rezolva_2();
86 }
87
88 int main()
89 {
90 citire();
91 return 0;
92 }
12 int main()
13 {
14 int i,j,r,i1,j1,i2,j2,ii,jj,l1,k1;
15 fin>>P>>N>>M;
16
17 for(i=N;i>=1;i--)
18 {
19 for(j=M;j>=1;j--)
20 {
21 fin>>a[i][j];
22 }
23 }
24
25 if(P==1)
26 {
27 r=1;
28 i=2;
29 for(j=i+1;j<=M;j++)
30 {
31 if(a[1][j]*(i-1)>a[1][i]*(j-1))
32 {
33 r++;
34 i=j;
35 }
36 }
37
38 r++;
39 j=2;
40 for(i=j+1;i<=N;i++)
41 {
42 if(a[i][1]*(j-1)>a[j][1]*(i-1))
43 {
44 r++;
45 j=i;
46 }
47 }
48
49 fout<<r;
50 }
51
52 if(P==2)
53 {
54 r=0;
55 for(i=1;i<=N;i++)
56 {
57 for(j=1;j<=M;j++)
58 {
59 if(i>1 || j>1)
60 {
61 if(b[i][j]==0)
62 {
63 b[i][j]=1; r++;
64 i1=i;j1=j;
65 ii=i;jj=j;
66 l1=i1-1;k1=j1-1;
67 while(ii+l1<=N && jj+k1<=M)
68 {
69 i2=ii+l1; j2=jj+k1;
70 long long v1=(long long)a[i2][j2]*a[i2][j2]*
71 ((i1-1)*(i1-1)+(j1-1)*(j1-1));
72 long long v2=(long long)a[i1][j1]*a[i1][j1]*
73 ((i2-1)*(i2-1)+(j2-1)*(j2-1));
74 if(v1>v2)
75 {
76 r++;
77 i1=i2;j1=j2;
78 b[i2][j2]=1;
79 }
80 else
81 {
82 b[i2][j2]=2;
83 }
84
85 ii=i2;jj=j2;
86 }
87 }
CAPITOLUL 3. OJI 2017 49
88 }
89 }
90 }
91
92 fout<<r;
93 }
94
95 fout.close();
96 return 0;
97 }
75 h = 0;
76 p = x;
77 q = y;
78 nr = 0;
79 for (i = 1; i*l < x&& i*c <y ; i++)
80 {
81 if (b[p-i*l][q-i*c]==0)
82 {
83 b[p-i*l][q-i*c]=1;
84 if (nr==0)
85 {
86 hmax = a[p-i*l][q-i*c];
87 pozl = i;
88 vede++;
89 b[p-i*l][q-i*c]=2;
90 nr++;
91 }
92 else
93 if ((a[p-i*l][q-i*c]-h) * (pozl) > i * (hmax -h))
94 {
95 pozl = i;
96 hmax = a[p - i*l][q - i*c];
97 vede++;
98 b[p-i*l][q-i*c]=2;
99 }
100 }
101 }
102 }
103
104 printf("%d\n",vede);
105 return 0;
106 }
3.2 Admitere
Problema 2 - Admitere 100 de puncte
S ne imagin m faptul c la un anumit liceu exist doar dou clase per generaµie: una de Real
³i una de Uman. În prezent au loc înscrierile pentru clasa a IX-a. Cele dou clase au ecare câte
M locuri disponibile, atât la Real, cât ³i la Uman. Dac lista de elevi înscri³i la o anumit clas
conµine mai mult de M elevi, vor admi³i acei M elevi care au notele cele mai mari. Ambele clase
au deja M elevi înscri³i, iar pentru ecare se ³tie nota cu care a fost înscris la clasa respectiv .
Mai exist îns N elevi, singurii înc neînscri³i, care sunt privilegiaµi în acest proces (indc
au terminat gimnaziul la acest liceu). Privilegiul lor const în urm torul fapt: ei se pot înscrie
acum, dup ce înscrierile publice au fost încheiate, ³i se cunosc notele de înscriere la ambele clase.
Fiecare din cei N elevi are câte dou note: nota cu care ar înscris la Real ³i nota cu care ar
înscris la Uman (acestea pot diferite, deoarece examenele de admitere de la cele dou clase
difer ). Fiecare din cei N elevi va alege s se înscrie în maxim o clas . Ei î³i vor coordona alegerile
astfel încât s maximizeze num rul de elevi admi³i. Deoarece calculele devin destul de complicate,
ace³tia s-ar putea folosi de ajutorul vostru. Ei doresc r spunsul la urm toarele dou întreb ri:
Cerinµe
(1) Care este num rul maxim de elevi privilegiaµi care pot admi³i dac se pune restricµia
suplimentar ca toµi elevii privilegiaµi admi³i s e admi³i la aceea³i clas ?
(2) Care este num rul maxim de elevi privilegiaµi care pot admi³i dac ace³tia se pot înscrie
la clase diferite?
Date de intrare
Fi³ierul de intrare admitere.in conµine pe primul rând o valoare egal cu 1 sau 2, reprezentând
cerinµa ce urmeaz a rezolvat . Urm toarea linie conµine cele dou numere N ³i M . Pe al treilea
rând se a M numere, separate prin câte un spaµiu, reprezentând notele cu care au fost înscri³i
elevii care formeaz momentan clasa de Real. Pe al patrulea rând se a M numere, separate
prin câte un spaµiu, reprezentând notele cu care au fost înscri³i elevii care formeaz momentan
clasa de Uman. Urm toarele N linii vor conµine câte o pereche de numere Ri, U i, separate
prin câte un spaµiu, reprezentând nota cu care al i-lea elev privilegiat s-ar înscrie la clasa de Real,
respectiv la clasa de Uman.
CAPITOLUL 3. OJI 2017 52
Date de ie³ire
Fi³ierul de ie³ire admitere.out va conµine pe prima linie valoarea M AX : num rul maxim de
¬ ¬ ¬ ¬ ¬ ¬
elevi privilegiaµi admi³i. A doua linie va conµine un ³ir de N caractere din mulµimea r R , U , X x,
care va descrie scenariul optim. Dac al i-lea elev va înscris la Real, al i-lea caracter va egal
¬ ¬ ¬ ¬
cu R . Dac al i-lea elev va înscris la Uman, al i-lea caracter va egal cu U . Dac acesta nu
¬ ¬
va înscris nic ieri, al i-lea caracter va egal cu X .
Deoarece elevii nu vor s depun efort inutil, un elev privilegiat care nu va admis în scenariul
optim nu se va înscrie la nicio clas . Cu alte cuvinte, pentru ca scenariul descris s e considerat
¬ ¬
corect este necesar ca exact M AX caractere din ³ir s e diferite de X .
Restricµii ³i preciz ri
a 1 & N, M & 2000
a Teste în valoare total de 25 de puncte vor solicita rezolvarea cerinµei (1), iar restul de 65
de puncte vor solicita rezolvarea cerinµei 2. Din ociu sunt acordate 10 puncte.
a Pentru cerinµa 2, teste în valoare total de 45 de puncte vor avea 1 & N, M & 150
a Toate cele N M note pentru clasa de Real sunt distincte dou câte dou . Acela³i lucru
este valabil ³i în cazul notelor pentru clasa de Uman.
a Toate notele sunt numere naturale din intervalul 1, 4000.
a Notele elevilor deja înscri³i de la clasa de Real, respectiv Uman vor date în ordine cresc -
toare.
a în cazul în care exist mai multe soluµii corecte, este acceptat oricare dintre acestea.
Exemple
admitere.in admitere.out Explicaµii
1 1 Nu este posibil ca ambii elevi s e admi³i la aceea³i clas .
23 XR Exist mai multe soluµii în care un singur elev este admis:
246 XR, XU, RX. Oricare din acestea este corect .
678
35
12 14
2 2 Deoarece acum rezolv m cerinµa (2), ne este permis s
23 RU înscriem elevii la clase diferite. Exist o soluµie în care
246 ambii elevi sunt admi³i, iar aceasta este unic : cea în care
678 elevul 1 este înscris la Real (el nu putea admis la Uman
35 indiferent de decizia celui de-al doilea elev), iar cel de-al
12 14 doilea elev este înscris la Uman.
Cerinµa 2
CAPITOLUL 3. OJI 2017 53
În primul rând, s not m c prima cerinµ trebuie luat în calcul în soluµia celei de a doua.
Astfel, în continuare vom presupune c exist cel puµin un elev privilegiat admis în ambele clase.
La modul informal, dicultatea problemei const în faptul c avem de f cut multe alegeri,
iar acestea se inuenµeaz reciproc. în asemenea situaµii poate util s ne restrângem opµiunile,
încercând s rezolv m o problem mai particular . S analiz m, spre exemplu, cum putem rezolva
urm toarea variant a problemei:
(1) Este posibil s -i admitem pe toµi cei N elevi privilegiaµi?
Este clar c soluµia problemei originale trebuie s trateze implicit sau explicit aceast întrebare
(r psunsul pozitiv ar indica o soluµie clar optim ).
În ce fel este mai u³oar aceast problem ? în problema original exista un factor de nesigu-
ranµ în îns ³i decizia de a încerca s admitem un anumit elev (f r a decide ³i clasa la care am
face acest lucru). Poate c în toate soluµiile optime respectivul elev ar r mas înafara liceului.
în aceast variant trebuie s -i admitem pe toµi, iar acest lucru ne reduce din opµiuni.
Acum putem intui, în termeni informali, c dicultatea în a-i admite pe toµi cei N elevi st în
a-i admite pe cei mai slabi dintre ei. Ce ar însemna totu³i ca un elev s e mai slab decât altul?
Putem argumenta credibil c elevul cu notele (4, 4) este mai slab decât elevul cu notele (10, 10),
dar se pot compara elevii cu notele (4, 10), respectiv (10, 4)? Faptul c elevii sunt bidimensionali
pare s ne pun dicult µi, a³a c poate o idee bun s restrângem din nou problema.
(2) Este posibil s -i admitem pe toµi cei N elevi privilegiaµi ³tiind c ecare dintre ace³tia are
nota de înscriere de la Uman egal cu cea de la Real?
Beneciul acestei constrângeri este c acum avem un cel mai slab elev! Este clar c indiferent
de clasa la care va admis, el va ultimul elev privilegiat admis la clasa respectiv . Vom încerca
pe rând s -l admitem la Real, respectiv Uman.
S presupunem c el va admis la Real. Analizând cele M note care exist deja la Real,
not m c exist P note mai mari decât a sa. Dac P M , el nu poate admis la Real indiferent
de alegerile celorlalµi privilegiaµi. Dac P $ M , el poate admis la Real ³i, mai important, putem
admite înc M P 1 elevi privilegiaµi la Real f r a-l elimina pe elevul cel mai slab. S numim
valoarea M P 1 SPATIU_REAL.
Este optim s aducem cât mai mulµi elevi la Real, respectând acest limit de SPATIU_REAL,
deoarece astfel u³ur m situaµia elevilor r ma³i care vor încerca s e admi³i la Uman. întreba-
rea este acum pe care SPATIU_REAL dintre cei N 1 elevi este optim s -i admitem la Real?
Urm rind din nou s u³ur m situaµia celor care vor r mâne la Uman, îi vom admite la Real pe
cei SPATIU_REAL cu cele mai mici note. Pentru a argumenta c aceast decizie cre³te ³ansele
elevilor care se vor înscrie la Uman ne amintim de la cerinµa 1 c dac exist în general o soluµie
cu K elevi admi³i la o clas , exist ³i una în care ace³ti K sunt cei cu cele mai mari note dintre
cei disponibili. în acela³i timp, nu risc m nimic prin a aduce elevi cu note mici la Real, deoarece
³tim c am avut grij s r mân admis acolo cel mai slab elev, fapt care ne asigur c orice alt
elev înscris la Real va de-asemenea admis.
Dac acest algoritm nu reu³e³te s admit toµi elevii, vom încerca s admitem elevul cel mai
slab la clasa de Uman. Dac nici în acest fel nu se g se³te soluµie, ea nu exist (cel mai slab
elev trebuie s e admis undeva, iar în ambele scenarii am luat decizii optime care s faciliteze
admiterea celorlalµi).
Ce complexitate are acest algoritm? Detaliile variaz , dar exist implement ri simple cu
complexitate O N M N N . Este util (dar nu strict necesar ) o sortare a celor N elevi,
care poate f cut în complexitate O N N . Este de-asemenea util s ³tim pentru ecare elev
³i ecare clas câte dintre cele M note deja înscrise sunt mai mari decât nota elevului respectiv.
Acest lucru se poate calcula u³or în O N M . Simularea algoritmului descris mai sus ³i vericarea
faptului c toµi elevii sunt admi³i poate f cut combinând aceste dou informaµii precalculate.
Astfel, avem o rezolvare satisf c toare ca timp de execuµie pentru subproblema (2). Vom
încerca acum s folosim ideile de la (2) pentru a rezolva subproblema (1). Dicultatea este
bineînµeles c nu mai avem neaparat un cel mai slab elev. Totu³i, vom avea înc un ultim elev
privilegiat admis în clasa de Real. Cine va acesta în soluµia optim ? Nu ³tim, dar putem
presupune, pe rând, despre ecare dintre cei N elevi c va lua aceast poziµie. Având elevul X
xat ca ind ultimul privilegiat admis la Real, suntem prezentati cu un scenariu similar celui din
(2). ³tim c mai putem admite SPATIU_REAL(X ) (aceast valoare variaz în funcµie de X ) elevi
la clasa de Real f r s -l elimin m pe X . Din nou, este de dorit s admitem cât mai mulµi elevi
la Real (luând în calcul aceast limit ). Trebuie îns s m mai atenµi în a analiza pe care din cei
N 1 elevi s -i admitem. în primul rând, ace³tia trebuie s aib nota de la Real strict mai mare
decât nota lui X , indc altfel invalid m poziµia sa de ultim admis. Filtrând dup acest criteriu,
are sens în continuare s alegem elevii cu notele cele mai mici la Uman, din acela³i raµionament
CAPITOLUL 3. OJI 2017 54
33 }
34
35 for(int c = 0; c < 2; ++c)
36 for(int i = 0; i < n; ++i)
37 for(int j = 0; j < m; ++j)
38 if(fixedGrades[c][j] > currGrades[i][c])
39 frontAlready[c][i]++;
40
41 int bestAns = 0;
42 string bestConfig(n, ’X’);
43 string label = "RU";
44
45 auto realityCheck = [&] (string config) -> string {
46 for(int c = 0; c < 2; ++c)
47 {
48 int greaterFriends = 0;
49 for(int i = n - 1; i >= 0; --i)
50 {
51 if(config[p[c][i]] != label[c])
52 continue;
53 if(greaterFriends + frontAlready[c][p[c][i]] >= m)
54 config[p[c][i]] = ’X’;
55 greaterFriends++;
56 }
57 }
58
59 return config;
60 };
61
62 for(int c = 0; c < 2; ++c)
63 {
64 string config(n, label[c]);
65 config = realityCheck(config);
66
67 int temp = 0;
68 for(int i = 0; i < n; ++i)
69 if(config[i] != ’X’)
70 ++temp;
71
72 if(temp > bestAns)
73 {
74 bestAns = temp;
75 bestConfig = config;
76 }
77 }
78
79 if(tip == 1)
80 {
81 cout << bestAns << "\n";
82 cout << bestConfig << "\n";
83 return 0;
84 }
85
86 const int REAL = 0, UMAN = 1;
87
88 for(int minFirst = 0; minFirst < n; ++minFirst)
89 {
90 string config(n, ’X’);
91 config[minFirst] = label[REAL];
92
93 int space = m - 1;
94 for(int i = 0; i < m; ++i)
95 if(fixedGrades[REAL][i] > currGrades[minFirst][REAL])
96 space--;
97
98 for(int i = 0; i < n; ++i)
99 {
100 if(p[UMAN][i] == minFirst)
101 continue;
102 if(currGrades[p[UMAN][i]][REAL] > currGrades[minFirst][REAL] &&
103 space > 0)
104 {
105 config[p[UMAN][i]] = label[REAL];
106 space--;
107 }
108 else
CAPITOLUL 3. OJI 2017 56
109 {
110 config[p[UMAN][i]] = label[UMAN];
111 }
112 }
113
114 config = realityCheck(config);
115 int temp = 0;
116 for(int i = 0; i < n; ++i)
117 if(config[i] != ’X’)
118 temp++;
119
120 if(temp > bestAns)
121 {
122 bestAns = temp;
123 bestConfig = config;
124 }
125 }
126
127 cout << bestAns << "\n";
128 cout << bestConfig << "\n";
129 }
52 //la clasa C
53 // sunt mai mari decat nota elevului privilegiat cu numarul E la clasa C
54
55 for(int c = 0; c < 2; ++c)
56 for(int i = 0; i < n; ++i)
57 for(int j = 0; j < m; ++j)
58 if(fixedGrades[c][j] > currGrades[i][c])
59 frontAlready[c][i]++;
60
61 int bestAns = 0;
62 string bestConfig(n, ’X’);
63 string label = "RU";
64
65 // Functia realityCheck preia un string cu optiunile de inscriere
66 // ale celor N elevi
67 // si il "aduce la realitate", punand ’X’ in dreptul elevilor care
68 // nu sunt admisi
69 // la clasa aleasa. Complexitatea functiei este O(N).
70
71 auto realityCheck = [&] (string config) -> string {
72 for(int c = 0; c < 2; ++c)
73 {
74 int greaterFriends = 0;
75 for(int i = n - 1; i >= 0; --i)
76 { // parcurgem elevii privilegiati inscrisi la clasa c
77 // in ordine descrescatoare dupa nota
78 if(config[p[c][i]] != label[c])
79 continue;
80
81 // greaterFriends = cati elevi privilegiati inscrisi
82 // la clasa c au fost admisi deja
83 // frontAlready[..] = cati elevi din cei M initiali
84 // aveau note mai mari decat cel curent
85 // pozitia elevului curent este data de suma acestor
86 // doua valori + 1
87 // daca este >= m, elevul este respins
88
89 if(greaterFriends + frontAlready[c][p[c][i]] >= m)
90 config[p[c][i]] = ’X’;
91 greaterFriends++;
92 }
93 }
94 return config;
95 };
96
97 // Cerinta 1
98
99 for(int c = 0; c < 2; ++c)
100 {
101 string config(n, label[c]); // toti elevii se inscriu la clasa c
102 config = realityCheck(config); // config ne spune acum care elevi
103 // au ramas efectiv admisi la clasa c
104
105 int temp = 0;
106 for(int i = 0; i < n; ++i)
107 if(config[i] != ’X’)
108 ++temp;
109
110 if(temp > bestAns)
111 { // actualizam raspunsul cel mai bun
112 bestAns = temp;
113 bestConfig = config;
114 }
115 }
116
117 if(tip == 1)
118 {
119 cout << bestAns << "\n";
120 cout << bestConfig << "\n";
121 return 0;
122 }
123
124
125 //Cerinta 2
126
127 const int REAL = 0, UMAN = 1;
CAPITOLUL 3. OJI 2017 58
128
129 for(int minReal = 0; minReal < n; ++minReal)
130 { // fixam ultimul privilegiat admis la Real
131 string config(n, ’X’);
132 config[minReal] = label[REAL];
133
134 int space = m - 1;
135 for(int i = 0; i < m; ++i)
136 if(fixedGrades[REAL][i] > currGrades[minReal][REAL])
137 // mai putem pune maxim "space" privilegiati la Real
138 space--;
139
140 for(int i = 0; i < n; ++i)
141 { // parcurgem ceilalti N - 1 elevi in ordine crescatoare
142 // dupa nota de la UMAN
143 if(p[UMAN][i] == minReal)
144 continue;
145 if(currGrades[p[UMAN][i]][REAL] > currGrades[minReal][REAL] &&
146 space > 0)
147 { // daca elevul are nota de Real > minimul fixat
148 // si mai avem loc, il punem la real.
149 config[p[UMAN][i]] = label[REAL];
150 space--;
151 }
152 else
153 { // altfel se inscrie la uman
154 config[p[UMAN][i]] = label[UMAN];
155 }
156 }
157
158 config = realityCheck(config); // aducem configuratia la realitate
159
160 int temp = 0;
161 for(int i = 0; i < n; ++i)
162 if(config[i] != ’X’)
163 temp++;
164
165 if(temp > bestAns)
166 {
167 bestAns = temp;
168 bestConfig = config;
169 }
170 }
171
172 cout << bestAns << "\n";
173 cout << bestConfig << "\n";
174 }
26
27 void citire_sort(int a[], int n)
28 {
29 for(int i=1;i<=n;i++)
30 fin>>a[i];
31
32 sort(a+1,a+n+1);
33 }
34
35 int V, M, N, u[4005], r[4005], sr[4005], su[4005],
36 pozu[4005], upoz[4005], pozr[4005], rpoz[4005], vr, vu;
37
38 char x[4005], y[4005];
39
40 int main()
41 {
42 int i,j,k,l,p,rez,aux,c,cr,cu;
43
44 fin>>V>>N>>M;
45
46 citire_sort(r,M);
47 citire_sort(u,M);
48
49 vr=2000000000;
50 vu=2000000000;
51 for(i=1;i<=N;i++)
52 {
53 fin>>sr[i]>>su[i];
54 vr=min(vr,sr[i]);
55 vu=min(vu,su[i]);
56 pozu[i]=i;
57 pozr[i]=i;
58 x[i]=’X’;
59 y[i]=’X’;
60 }
61
62 for(i=1;i<=N-1;i++)
63 for(j=i+1;j<=N;j++)
64 if(sr[pozr[i]]>sr[pozr[j]])
65 {
66 aux=pozr[i];
67 pozr[i]=pozr[j];
68 pozr[j]=aux;
69 }
70 ///for(i=1;i<=N;i++) rpoz[pozr[i]]=i;
71
72 for(i=1;i<=N-1;i++)
73 for(j=i+1;j<=N;j++)
74 if(su[pozu[i]]>su[pozu[j]])
75 {
76 aux=pozu[i];
77 pozu[i]=pozu[j];
78 pozu[j]=aux;
79 }
80
81 for(i=1;i<=N;i++)
82 upoz[pozu[i]]=i;
83
84 for(i=1;i<=N;i++)
85 y[i]=’X’;
86
87 i=N;
88 j=M;
89 k=0;
90 cr=0;
91 pozr[0]=0;
92 sr[0]=0;
93 r[0]=0;
94
95 for(k=M;k>=1;k--)
96 {
97 if(sr[pozr[i]]>r[j])
98 {
99 y[pozr[i]]=’R’;
100 cr++; i--;
101 }
CAPITOLUL 3. OJI 2017 60
102 else
103 {
104 j--;
105 }
106 }
107
108 rez=cr;
109
110 for(i=1;i<=N;i++)
111 x[i]=’X’;
112
113 i=N;
114 j=M;
115 k=0;
116 cu=0;
117 pozu[0]=0;
118 su[0]=0;
119 u[0]=0;
120 for(k=M;k>=1;k--)
121 {
122 if(su[pozu[i]]>u[j])
123 {
124 x[pozu[i]]=’U’;
125 cu++; i--;
126 }
127 else
128 {
129 j--;
130 }
131 }
132
133 if(cu>rez)
134 {
135 rez=cu;
136 for(i=1;i<=N;i++)y[i]=x[i];
137 }
138
139 if(V==1)
140 {
141 fout<<rez<<"\n";
142 fout<<y+1;
143 }
144
145 for(i=1;i<=N;i++)
146 {///O(N)
147 p=pozmin(u,M,su[i]);///log(M)
148 if(p>=1)
149 {
150 for(j=1;j<=N;j++)
151 x[j]=’X’;///O(N)
152
153 c=1;
154 x[i]=’U’;
155 for(j=1;j<=N;j++)///O(N)
156 if(upoz[pozr[j]]>upoz[i] && c<p)
157 {
158 x[pozr[j]]=’U’;
159 c++;
160 }
161
162 l=N;
163 j=M;
164 k=0;
165 pozr[0]=0;
166 sr[0]=0;
167 r[0]=0;
168 for(k=M;k>=1;k--)
169 {///O(M)
170 while(l>0 && x[pozr[l]]!=’X’)
171 l--;
172
173 if(sr[pozr[l]]>r[j])
174 {
175 x[pozr[l]]=’R’;
176 c++; l--;
177 }
CAPITOLUL 3. OJI 2017 61
178 else
179 {
180 j--;
181 }
182 }
183
184 if(c>rez)
185 {
186 rez=c;
187 for(j=1;j<=N;j++)
188 {
189 y[j]=x[j];
190 }
191 }
192 }
193 }
194
195 if(V==2)
196 {
197 fout<<rez<<"\n";
198 fout<<y+1;
199 }
200
201 fin.close();
202 fout.close();
203 return 0;
204 }
3.3 Roboµi
Problema 3 - Roboµi 100 de puncte
tefan a împlinit 15 ani. Fiind un pasionat membru al Clubului de Robotic , familia i-a d ruit
de ziua lui foarte mulµi roboµi, ecare dotat cu o arm de o anumit putere. El a a³ezat toµi roboµii
în jurul s u, pe circumferinµa unui cerc imaginar, în sensul acelor de ceasornic. Aceste dispozitive
inteligente pot comunica între ele, unindu-³i puterile armelor.
Cerinµe
Cunoscând num rul de roboµi, precum ³i puterea ec ruia, s se scrie un program care deter-
min :
1. Dimensiunea celei mai lungi secvenµe de roboµi pentru care puterile armelor lor formeaz
un ³ir strict cresc tor.
2. O aranjare a roboµilor pe cerc, astfel încât suma produselor de câte dou puteri vecine s
e maxim . Dac exist mai multe modalit µi de aranjare astfel încât s se obµin aceea³i sum
maxim , se va determina cea minim din punct de vedere lexicograc.
Date de intrare
Pe prima linie a ³ierului de intrare roboti.in se g se³te un num r natural v a c rui valoare
poate doar 1 sau 2.
Pe a doua linie a ³ierului de intrare se g se³te un singur num r natural n reprezentând
num rul de roboµi.
Pe a treia linie a ³ierului de intrare se g sesc n numere naturale p1 , p2 , ..., pn , separate prin
câte un spaµiu, pi reprezentând puterea armei robotului i.
Date de ie³ire
Dac valoarea lui v este 1, atunci ³ierul de ie³ire roboti.out va conµine pe prima linie un
singur num r natural reprezentând dimensiunea celei mai lungi secvenµe de roboµi pentru care
puterile armelor lor formeaz un ³ir strict cresc tor.
Dac valoarea lui v este 2, atunci ³ierul de ie³ire va conµine pe prima linie n numere naturale
separate prin câte un spaµiu, reprezentând puterile celor n roboµi a³ezaµi pe cerc astfel încât suma
produselor de câte dou puteri vecine s e maxim , iar a³ezarea s e minim din punct de
vedere lexicograc.
Restricµii ³i preciz ri
CAPITOLUL 3. OJI 2017 62
Exemple
roboti.in roboti.out Explicaµii
1 4 v = 1, deci se va rezolva DOAR prima cerinµ .
7 4726513
4726513 Cea mai lung secvenµ strict cresc toare este 1 3 4 7 ³i are
lungimea 4.
2 1 3 9 12 5 v = 2, deci se va rezolva DOAR a doua cerinµ .
5 1*3+3*9+9*12+12*5+5*1=203,
3 9 1 12 5 ³i este suma maxim care se poate obµine.
Aceast aranjare nu este singura pentru care se obµine suma
maxim , dar este cea mai mic lexicograc.
2 1112 v = 2, deci se va rezolva DOAR a doua cerinµ .
4 1*1+1*1+1*2+2*1=6,
1211 ³i este suma maxim care se poate obµine.
Aceast aranjare nu este singura pentru care se obµine suma
maxim , dar este cea mai mic lexicograc.
(2) dac num rul de apariµii pentru r[i] este 1, atunci putem presupune c avem o secvenµ
1=f[i]=f[i-1]=...=f[j] de valori unicat (cu num rul de apariµii egal cu 1)
(a) dac avem capete egale q[m]==q[M], atunci toate valorile unicat trebuie ad ugate alter-
nativ la cele dou capete astfel încât ultima (cea mai mic ) s e adaugat la cap tul m (din
stânga), pentru suma maxim de produse ³i conservarea ordinii lexiograce minime
(b) dac avem capete cu valori diferite , atunci valorile unicat trebuie ad ugate alternativ la
cele dou capete începand cu cap tul unde se a cea mai mare, deoarece suma maxim este
obiectivul principal de urm rit
(3) La nal valoarea minim se va ad uga la cap tul m, conform cu num rul ei de apariµii.
Se va a³a apoi secvenµa q[m], q[m+1],...,q[M]
52 sort(p, p+n);
53
54 //aranjare
55 a[0]=p[0];
56 s=0; d=n;
57 serie=0;
58 ns=0;nd=0;
59 antdr=0;
60 for(i=1;i<=n-1;i++)
61 {
62 // daca este cap de serie,
63 // adica primuldintr-o serie de nr. care se repeta
64 if(i<n-1 && p[i]==p[i+1] && p[i-1]!=p[i])
65 cs=1;
66 else
67 cs=0;
68
69 //daca am pus mai putini sau egal in st si dr sau
70 // este intr-o serie de egale sau
71 // cel dinaintealui l-am pus in dreapta dar nu a fost cap de serie
72 if(ns<=nd || serie || (antdr && !cs) )//merge stanga
73 {
74 s++;
75 a[s]=p[i];
76 ns++;
77 antdr=0;
78 }
79 else //merge dreapta
80 {
81 d--;
82 a[d]=p[i];
83 nd++;
84 antdr=1;
85 }
86
87 if(p[i]==p[i-1])
88 serie++;
89 else
90 serie=0;
91 }
92
93 for(i=0;i<n;i++)
94 out<<a[i]<<’ ’;
95 }
96
97 in.close();
98 out.close();
99 return 0;
100 }
24 x=a[0];
25 ok=0;
26 while(i<n && ok<2)
27 {
28 if(a[i]>a[i-1])
29 ls++;
30 else
31 {
32 if(ls>max)
33 max=ls;
34 ls=1;
35 }
36
37 i++;
38 //ciclarea cautarii
39 if(i==n)
40 {
41 if(x>a[i-1])
42 {
43 ls++;
44 i=1;
45 }
46
47 ok++; //numai inca o ciclare
48 }
49 }
50
51 out<<max;
52 }
53 else //cerinta 2
54 {
55 for(i=0;i<n;i++)
56 {
57 in>>d;
58 p[d]++;
59 }
60
61 //aranjare
62 i=1;
63 s=0;
64 d=n;
65 ns=0;
66 nd=0;
67 while(p[i]==0)
68 i++;
69 //cout<<i<<":"<<p[i]<<endl;
70
71 a[0]=i;
72 p[i]--;
73 serie=0;
74 for(j=1;j<=p[i];j++)
75 {
76 s++;
77 a[s]=i;
78 ns++;
79 serie=1;
80 }
81
82 antdr=0;
83 i++;
84 do
85 {
86 while(p[i]==0 && i<=1000)
87 i++;
88
89 // daca este cap de serie,
90 // adica primul dintr-o serie de nr. care se repeta
91 // capul de serie merge dr restul din serie merg st
92 if(p[i]>1)
93 {
94 d--;
95 a[d]=i;
96 p[i]--;
97 nd++;
98 serie=1;
99 antdr=0;
CAPITOLUL 3. OJI 2017 67
100 for(j=1;j<=p[i];j++)
101 {
102 s++;
103 a[s]=i;
104 ns++;
105 }
106 }
107 else
108 {
109 if(ns<=nd || serie || antdr)
110 {
111 s++;
112 a[s]=i;
113 ns++;
114 serie=0;
115 antdr=0;
116 }
117 else
118 {
119 d--;
120 a[d]=i;
121 nd++;
122 antdr=1;
123 }
124 }
125
126 i++;
127 } while(ns+nd<n-1);
128
129 for(i=0;i<n;i++)
130 out<<a[i]<<’ ’;
131 }
132
133 in.close();
134 out.close();
135 return 0;
136 }
36 for(i=1;i<=1000;i++)
37 q[i]=0;
38
39 for(i=1;i<=n;i++)
40 q[p[i]]++;
41
42 nr=0;
43 for(i=1;i<=1000;i++)
44 {
45 if(q[i]>0)
46 {
47 nr++;
48 f[nr]=q[i];
49 r[nr]=i;
50 q[i]=0;
51 }
52 }
53
54 m=n+1;
55 for(i=1;i<=f[nr];i++)
56 q[--m]=r[nr];
57
58 M=n;
59 for(i=nr-1;i>=2;i--)
60 {
61 if(f[i]>1)
62 {
63 q[++M]=r[i];
64 for(j=1;j<f[i];j++)
65 q[--m]=r[i];
66 }
67 else
68 {
69 j=i;
70 while(j-1>=2 && f[j-1]==1)
71 j--;
72
73 if(q[m]==q[M])
74 {
75 if((i-j+1)%2==1)
76 q[--m]=r[i--];
77
78 for(k=i;k>=j;k=k-2)
79 {
80 q[++M]=r[k];
81 q[--m]=r[k-1];
82 }
83 }
84 else
85 {
86 if(q[m]>q[M])
87 {
88 for(k=0;k<=i-j;k++)
89 {
90 if(k%2==0)
91 q[--m]=r[i+k];
92 else
93 q[++M]=r[i+k];
94 }
95 }
96 else
97 {
98 for(k=0;k<=i-j;k++)
99 {
100 if(k%2==1)
101 q[--m]=r[i+k];
102 else
103 q[++M]=r[i+k];
104 }
105 }
106 }
107
108 i=j;
109 }
110 }
111
CAPITOLUL 3. OJI 2017 69
112 for(i=1;i<=f[1];i++)
113 q[--m]=r[1];
114
115 for(i=m;i<=M;i++)
116 fout<<q[i]<<" ";
117 }
118
119 fout.close();
120 return 0;
121 }
63 B[p++] = A[i];
64
65 for (int i = 0; i < N; i++)
66 g << B[i] << " ";
67 }
68
69 g.close();
70 return 0;
71 }
Capitolul 4
OJI 2016
4.1 Cifre
Problema 1 - Cifre 100 de puncte
Cerinµe
Cunoscând un num r natural N a³at cu ajutorul mai multor indicatoare numerice, s se scrie
un program care determin :
1. Num rul de segmente aprinse pentru a³area num rului N .
2. Num rul de numere distincte mai mari decât N ,ce se pot forma prin aprinderea a cel
puµin unui segment în plus, faµ de cele utilizate pentru a³area num rului N ,f r a folosi alte
indicatoare numerice, ³i f r a stinge nici un segment dintre cele deja aprinse.
Date de intrare
Fi³ierul de intrare este cifre.in
Pe prima linie a ³ierului de intrare se g se³te num rul natural V a c rui valoare poate doar
1 sau 2.
Pe a doua linie a ³ierului de intrare se g se³te num rul natural N .
Date de ie³ire
Fi³ierul de ie³ire este cifre.out
Dac valoarea lui V este 1 atunci ³ierul de ie³ire va conµine pe prima linie un singur num r
natural ce reprezint num rul de segmente aprinse pentru a³area num rului N .
Dac valoarea lui V este 2 atunci ³ierul de ie³ire va conµine pe prima linie un singur num r
natural reprezentând num rul de numere distincte mai mari decât N , ce se pot forma prin aprin-
derea a cel puµin unui segment în plus, faµ de cele utilizate pentru a³area num rului N , f r a
folosi alte indicatoare numerice.
Restricµii ³i preciz ri
a 10 & N & 1019
a 20% din teste vor avea valoarea V 1, iar 80% din teste vor avea valoarea V 2.
Exemple
71
CAPITOLUL 4. OJI 2016 72
Varianta 1
Pentru prima cerinµ trebuie determinate câte segmente sunt aprinse pentru a³area num rului
N.
Se prelucreaz num rul N cifr cu cifr ³i se calculeaz num rul segmentelor aprinse.
Num rul de segmente aprinse pentru a³area cifrelor este dat în tabelul de mai jos :
Cifr 0 1 2 3 4 5 6 7 8 9
Num r segmente aprinse 6 2 5 5 4 5 6 3 7 6
Pentru a doua cerinµ o variant mai puµin ecient este urm toarea :
a Se parcurg toate numerele de la N 1 pân la cel mai mare num r cu acela³i num r de cifre
ca N .
a Pentru ecare dintre numerele de mai sus, se determin pentru ecare cifr dac aceasta
poate construit din cifra lui N de pe aceea³i poziµie prin aprinderea suplimentar a unui sau
mai multor segmente.
a Dac pentru ecare cifr condiµia de mai sus este adevarat se contorizeaz înc o soluµie.
Aceast soluµie obµine aproximativ jum tate din punctaj ³i ordinul s u de complexitate este
nrcif re N
O 10 1 N .
Varianta 2 (optimizare matematic )
Pentru a determina un algoritm mai ecient folosim una din metodele de num rare prezentate
în manualul de clasa a IX-a de matematic ³i anume regula produsului. Aceast regul arm
c dac avem A1 , A2 , ...., Ak operaµii succesive, prima putând efectuat în n1 moduri, a doua
în n2 moduri, ..., ultima în nk moduri, atunci succesiunea celor k operaµii poate efectuat în
n1 n2 ... nk moduri.
În acest scop construim urm toarele structuri de date:
a) Num rul de cifre ce se pot forma dintr-o cifr dat prin ad ugarea de noi segmente (inclusiv
cifra curent ):
Cifr 0 1 2 3 4 5 6 7 8 9
Num rul cifrelor ce se pot realiza din cifra curent 2 7 2 3 3 4 2 5 1 2
prin ad ugare de noi segmente (inclusiv cifra curent )
b) Num rul de cifre, strict mai mari decât o cifr dat , ce se pot forma prin ad ugarea de noi
segmente:
Cifr 0 1 2 3 4 5 6 7 8 9
Num rul cifrelor strict mai mari decât cifra curent 1 5 1 2 2 3 1 2 0 0
ce se pot forma dintr-o cifr dat prin ad ugarea de
noi segmente:
Având în vedere aceste date vom parcurge cifrele lui N de la cifra cea mai semnicativ la cea
mai puµin semnicativ ³i la ecare cifr proced m astfel:
Calcul m produsul dintre numerele:
a câte cifre strict mai mari exist decât cifra curent ³i
CAPITOLUL 4. OJI 2016 73
a câte cifre se pot forma prin ad ugarea de noi segmente pentru ecare din cifrele urm toare,
nu neap rat mai mari, decât cifrele de pe poziµii similare ale lui N .
Num rul de numere distincte mai mari decât N reprezint suma produselor de mai sus.
2
Aceast soluµie obµine maximum de punctaj iar ordinul s u de complexitate este O nrcif re N .
60
61 S=0;
62 for(i=1;i<=k;i++)
63 {
64 if (a[w[i]])
65 {
66 P=a[w[i]];
67 for(j=i+1;j<=k;j++)
68 P=P*b[w[j]];
69 S=S+P;
70 }
71 }
72
73 g<<S<<"\n";
74 }
75
76
77 f.close();
78 g.close();
79
80 return 0;
81 }
51 p=c2[v[i]];
52 for (int j=i-1; j>=0 && p>0 ;j--)
53 p*=c1[v[j]];
54 s=s+p;
55 }
56
57 g<<s<<"\n";
58 }
59
60 return 0;
61 }
4.2 pic
Problema 2 - pic 100 de puncte
Cerinµe
Cunoscând num rul de pahare din rândul de la baza stivei ³i faptul c stiva este complet
(toate rândurile conµin num rul maxim de pahare ce se pot a³eza dup regula de mai sus, iar pe
cel mai de sus rând se g se³te un singur pahar), s se scrie un program care determin :
1. Care este nivelul minim (cel mai de sus) care are suma capacit µilor tuturor paharelor de
pe nivel maxim ?
2. Care este num rul minim de secunde necesar pentru a umple toate paharele folosind pro-
cedeul descris mai sus ³i câµi mililitri de ap se risipesc (se scurg pe mas ) în acest caz?
Date de intrare
Pe prima linie a ³ierului de intrare pic.in se g se³te un num r natural V a c rui valoare poate
doar 1 sau 2.
Pe a doua linie a ³ierului de intrare se g se³te un singur num r natural N reprezentând
num rul de pahare din rândul de la baza stivei.
Pe a treia linie a ³ierului de intrare se g sesc M N N 1©2 numere naturale C1 , C2 , ..., CM
separate prin câte un spaµiu, Ci reprezentând capacitatea (în mililitri) a paharului num rul i din
stiv .
Date de ie³ire
Dac valoarea lui V este 1 atunci ³ierul de ie³ire pic.out va conµine pe prima linie un singur
num r natural ce reprezint num rul de ordine al nivelului minim (cel mai de sus) care are suma
capacit µilor tuturor paharelor de pe nivel maxim .
Dac valoarea lui V este 2 atunci ³ierul de ie³ire va conµine pe prima linie dou numere
naturale separate printr-un singur spaµiu reprezentând num rul minim de secunde scurse pân
când toate paharele din stiv sunt pline ³i respectiv num rul de mililitri de ap risipiµi (ajun³i pe
mas ) în acel moment.
Restricµii ³i preciz ri
a 2 & N & 50
a 20% din teste vor avea valoarea V 1, iar 80% din teste vor avea valoarea V 2.
a 35% din teste vor avea N 17, iar 65% din teste vor avea N % 17.
a 1 & C1 , C2 , ..., CM & 25
Exemple
CAPITOLUL 4. OJI 2016 77
Pentru rezolvarea primei cerinµe se calculeaz , simultan cu citirea datelor, suma capacit µilor
de pe ecare nivel ³i se determin maximul acestor sume, reµinându-se ³i primul nivel pentru care
se atinge acest maxim.
Rezolvarea celei de-a doua cerinµe se bazeaz pe o simulare a curgerii picurilor.
75 p[n][j] -= c[n][j];
76 if (p[n][j]<0) k++;
77 }
78
79 if (k>0) // mai sunt pahare neumplute
80 s *= 2;
81 } while (k>0);
82
83 // s umple toate paharele,
84 // s/2 nu umple toate paharele
85
86 // numarul de picaturi necesare este in intervalul [s/2, s] facem
87 // o cautare binara a cantitatii necesare
88 // pt a ramane un singur pahar gol
89
90 long long l=s/2;
91 s=s-l/2; // s e jumatatea intervalului [s/2,s]
92
93 while (l>0)
94 {
95 for (i=1; i<=n; i++) // initializam nr de picaturi turnate
96 // in fiecare pahar
97 for (j=1; j<=n; j++)
98 p[i][j]=0;
99
100 i=1;
101 j=1;
102 p[1][1]=s;
103 for (i=1; i<n; i++)
104 for (j=1; j<=i; j++)
105 {
106 x = p[i][j]-c[i][j];
107 p[i][j] = x;
108 p[i+1][j] += (x+1)/2;
109 p[i+1][j+1] += x/2;
110 }
111
112 k=0;
113 for (j=1; j<=n; j++)
114 {
115 p[n][j] -= c[n][j];
116 if (p[n][j]<0) k++; // pahar neumplut
117 }
118
119 l=l/2;
120 if (k>0) // cel putin un pahar neumplut
121 s=s+l/2;
122 else
123 s=s-l/2;
124 }
125
126 if (k>0)
127 s++;
128
129 g<<s<<" "<<s-ctot<<"\n";
130 }
131
132 return 0;
133 }
90 {
91 p[i][j]=pTemp[i][j];
92 }
93 }
94 }
95
96 if(c==1)
97 p2++;
98
99 fo<<p2<<" "<<p2-pt<<"\n";
100 }
101
102 return 0;
103 }
OJI 2015
5.1 arc
Problema 1 - arc 100 de puncte
Irinuca a descoperit un nou joc pe calculator. Pe ecran sunt plasate pe o linie n bile colorate.
Culorile bilelor sunt codicate cu numere naturale. Un sub³ir de bile al turate având toate aceea³i
culoare se nume³te secvenµ . O secvenµ va conµine num rul maxim de bile al turate având aceea³i
culoare. Lungimea unei secvenµe este egal cu num rul de bile din care este compus .
Irinuca are la dispoziµie un arc special. Tr gând cu arcul asupra unei bile, dac aceasta face
parte dintr-o secvenµ de lungime cel puµin egal cu 3, întreaga secvenµ va eliminat , iar bilele
din dreapta secvenµei se vor deplasa spre stânga pentru a umple golul l sat de bilele eliminate.
Dac imediat în stânga ³i în dreapta secvenµei eliminate se g seau dou secvenµe având aceea³i
culoare ³i dac secvenµa obµinut din unirea acestora dup eliminare are o lungime cel puµin egal
cu 3, atunci va ³i ea eliminat la rândul ei. Procesul continu pân când secvenµele din stânga
³i dreapta unei secvenµe tocmai eliminate au culori diferite sau pân când lungimea secvenµei
obµinute prin al turare este mai mic decât 3 sau pân când în stânga ori în dreapta unei secvenµe
eliminate nu se mai g sesc bile sau pân sunt eliminate toate bilele de pe ecran.
Scopul jocului este de a elimina cât mai multe bile de pe ecran. Cum Irinuca înc nu se pricepe
prea bine la acest joc ³i-a stabilit o strategie. Va trage cu arcul întotdeauna asupra unei bile ce
face parte din secvenµa de lungime maxim de pe ecran. Dac sunt mai multe astfel de secvenµe,
ea va alege cea mai din stânga secvenµ de lungime maxim . Dac toate secvenµele de pe ecran
au lungimi mai mici decât 3, Irinuca nu va mai putea elimina nici una din ele ³i jocul se încheie.
De exemplu, dac ³irul iniµial de bile este
513322223115644447
Irinuca va acµiona asupra unei bile de culoare 2. Prin eliminare se obµine ³irul de bile
51333115644447
din care se elimin ³i secvenµa de bile de culoare 3 obµinându-se ³irul de bile
51115644447
din care se elimin ³i secvenµa de culoare 1.
55644447
Cum secvenµa de bile de culoare 5 nu este sucient de lung , aceasta nu se mai elimin . Acum
Irinuca trage asupra unei bile de culoare 4 ³i obµine
5567
dar cum în stânga ³i în dreapta secvenµei eliminate sunt secvenµe de culori diferite, nu se va
mai elimina nici o secvenµ . Jocul se încheie deoarece nu mai exist nici o secvenµ de lungime cel
puµin 3 asupra c reia s se poat trage.
Cerinµe
Cunoscând num rul de bile ³i culorile ec rei bile de pe ecran se cere s se determine:
1. num rul de secvenµe de bile care se aau iniµial pe ecran;
2. num rul de bile care r mân neeliminate de pe ecran ³i culorile bilelor r mase în ordine pe
ecran la nalul jocului.
Date de intrare
83
CAPITOLUL 5. OJI 2015 84
Fi³ierul de intrare arc.in conµine pe prima linie un num r natural V . Pentru toate testele de
intrare, num rul V poate avea doar valoarea 1 sau 2.
A doua linie conµine un num r natural n reprezentând num rul de bile, iar a treia linie conµine
n numere naturale c1 , c2 , ..., cn separate prin câte un spaµiu, reprezentând culorile celor n bile de
pe ecran.
Date de ie³ire
Dac valoarea lui V este 1, se va rezolva numai punctul 1 din cerinµ .
În acest caz, în ³ierul de ie³ire arc.out se va scrie un singur num r natural n1 , reprezentând
num rul de secvenµe de bile aate iniµial pe ecran.
Dac valoarea lui V este 2, se va rezolva numai punctul 2 din cerinµ .
În acest caz, în ³ierul de ie³ire arc.out se va scrie pe prima linie un singur num r natural
n2 , reprezentând num rul de bile care r mân neeliminate de pe ecran la nalul jocului, iar pe
urm toarele n2 linii se va scrie câte un num r natural reprezentând în ordine culorile bilelor
r mase neeliminate la nalul jocului.
Dac la nalul jocului nu mai r mâne nici o bil neeliminat , ³ierul de ie³ire va conµine pe
prima sa linie valoarea 0.
Restricµii ³i preciz ri
a 1 & n & 10000
a 1 & c1 , c2 , ..., cn & 100000
a Pentru rezolvarea corect a primei cerinµe se acord 20 de puncte, iar pentru cerinµa a doua
se acord 80 de puncte.
Exemple
arc.in arc.out Explicaµii
1 10 V=1
18 Atenµie!
513322223115644 Pentru acest test se rezolv doar cerinµa 1.
447 Secvenµele sunt (5), (1), (3, 3), (2,2,2,2), (3), (1,1),
(5), (6), (4,4,4,4), (7)
2 4 V=2
18 5 Atenµie!
513322223115644 5 Pentru acest test se rezolv doar cerinµa 2.
447 6
7
2 0 V=2
15 Atenµie!
122221133344443 Pentru acest test se rezolv doar cerinµa 2.
Cerinµa 1.
Practic la citirea unei noi valori din ³ier, dac aceasta este egal cu ultima valoare memorat
în x vom incrementa contorul c corespunz tor, altfel o vom memora în urm toarea component
din vectorul x iar contorul corespunzator îl iniµializ m cu 1.
Num rul efectiv de valori din cei doi vectori, m, este r spunsul la primul punct.
Cerinta 2.
Vom simula elimin rile. Determin m maximul din vectorul c, e acesta max cp.
CAPITOLUL 5. OJI 2015 85
52 {
53 n=n-x[k];
54 i=k-1;
55 j=k+1;
56 while (c[i]==c[j] && i>=1 && j<=m && x[i]+x[j]>2)
57 {
58 n=n-x[i]-x[j];
59 i--; j++;
60 }
61
62 if (j>m)
63 m=i;
64 else
65 {
66 if (i>=1 && j<=m && c[i]==c[j])
67 {
68 x[i]=x[i]+x[j];
69 j++;
70 }
71
72 m1=m-j+i+1;
73 i=i+1;
74 while (j<=m)
75 {
76 x[i]=x[j]; c[i]=c[j];
77 i++; j++;
78 }
79
80 m=m1;
81 }
82 }
83 }
84
85 int main()
86 {
87 int k;
88
89 citire();
90
91 if (p==1)
92 g<<m<<"\n";
93 else
94 {
95 k=maxim();
96 while (n>0 && x[k]>2)
97 {
98 elim(k);
99 if (k>0)
100 k=maxim();
101 }
102
103 if (n>0)
104 {
105 g<<n<<"\n";
106 for (int i=1;i<=m;i++)
107 for (int j=1;j<=x[i];j++)
108 g<<c[i]<<"\n";
109 }
110 else
111 g<<"0\n";
112 }
113
114 g.close();
115 return 0;
116 }
8
9 ifstream fin("arc.in");
10 ofstream fout("arc.out");
11
12 int p, n, n1, n2;
13
14 struct Secv
15 {
16 int v, cnt;
17 short pos, prev, next;
18 };
19
20 const int MaxN = 10001;
21 Secv s[MaxN];
22 int first, last;
23
24 void Add(int val);
25 void Print();
26 int GetMax();
27 void DelSecv(int p);
28
29 int main()
30 {
31 int x;
32 fin >> p >> n;
33
34 for (int i = 1; i <= n; ++i)
35 {
36 fin >> x;
37 Add(x);
38 }
39
40 if (p == 1)
41 fout << n1 << ’\n’;
42 else
43 {
44 n2 = n;
45 while (true)
46 {
47 int p = GetMax(), p1, p2;
48
49 if ( !p || s[p].cnt <= 2 )
50 break;
51
52 n2 -= s[p].cnt;
53 p1 = s[p].prev;
54 p2 = s[p].next;
55
56 DelSecv(p);
57
58 while ( (p1 && p2) && (s[p1].v == s[p2].v) )
59 {
60 s[p1].cnt += s[p2].cnt;
61 DelSecv(p2);
62
63 if ( s[p1].cnt > 2 )
64 {
65 n2 -= s[p1].cnt;
66 int q = p1;
67 p1 = s[p1].prev;
68 DelSecv(q);
69 }
70
71 if ( p1 )
72 p2 = s[p1].next;
73 }
74 }
75
76 Print();
77 }
78
79 fin.close();
80 fout.close();
81 }
82
83 void Add(int val)
CAPITOLUL 5. OJI 2015 88
84 {
85 if ( last && s[last].v == val )
86 {
87 s[last].cnt++;
88 return;
89 }
90
91 Secv s1 {0, 0, 0, 0, 0 };
92
93 s1.v = val;
94 s1.cnt++; n1++;
95
96 if ( !first )
97 {
98 s1.prev = s1.next = 0;
99 first = last = 1;
100 s[first] = s1;
101 }
102 else
103 {
104 s[last].next = last + 1;
105 s1.prev = last;
106 s1.next = 0;
107 last++;
108 s[last] = s1;
109 }
110 }
111
112 void DelSecv(int p)
113 {
114 if ( p == first )
115 {
116 if ( p == last )
117 {
118 first = last = 0;
119 return;
120 }
121
122 first = s[p].next;
123 s[first].prev = 0;
124
125 return;
126 }
127
128 if ( p == last )
129 {
130 last = s[p].prev;
131 s[last].next = 0;
132 return;
133 }
134
135 int p1 = s[p].prev, p2 = s[p].next;
136 s[p1].next = p2;
137 s[p2].prev = p1;
138 }
139
140 int GetMax()
141 {
142 int pMax(0);
143 int cntMax = 0;
144
145 for (int p = first; p; p = s[p].next)
146 if ( s[p].cnt > cntMax )
147 cntMax = s[p].cnt, pMax = p;
148
149 return pMax;
150 }
151
152 void Print()
153 {
154 if ( !first )
155 fout << "0\n";
156 else
157 {
158 fout << n2 << ’\n’;
159
CAPITOLUL 5. OJI 2015 89
68
69 for(j=poz+2;j<=nr;j++)
70 v[j-2]=v[j];
71
72 nr-=2;
73 poz--;
74 continue;
75 }
76
77 if(poz>1&& poz<nr && v[poz-1].c==v[poz+1].c)
78 {
79 v[poz-1].nr+=v[poz+1].nr;
80
81 for(j=poz+2;j<=nr;j++)
82 v[j-2]=v[j];
83
84 nr-=2;
85 }
86 else
87 {
88 for(j=poz+1;j<=nr;j++)
89 v[j-1]=v[j];
90
91 nr--;
92 }
93
94 Max=0;
95 poz=0;
96 t=0;
97 for(i=1;i<=nr;i++)
98 {
99 if(v[i].nr>=3&&v[i].nr>Max)
100 {
101 Max=v[i].nr;
102 poz=i;
103 }
104
105 t=t+v[i].nr;
106 }
107
108 }
109
110 g<<t<<’\n’;
111
112 for(i=1;i<=nr;i++)
113 for(j=1;j<=v[i].nr;j++)
114 g<<v[i].c<<"\n";
115
116 return 0;
117 }
23 secv++;
24 v[secv]=x;
25 f[secv]=1;
26 }
27 else
28 f[secv]++;
29
30 u=x;
31 }
32
33 if (caz==1)
34 fout<<secv<<endl;
35
36 if (caz==2)
37 {
38 l=0;u=0;
39 for(i=1;i<=secv;i++)
40 {
41 //fout<<v[i]<<" "<<f[i]<<endl;
42 if(f[i]>l) l=f[i],u=i;
43 }
44
45 i=u; /// plec de la cea mai lunga secventa...
46 while(l>=3)
47 {
48 if(f[i]>=3)
49 {
50 ///o pot elimina
51 v[i]=0;
52 n=n-f[i]; ///cate se sterg
53 f[i]=0;
54
55 st=i-1;
56 dr=i+1;
57 while(v[st]==0 && st>1)
58 st--;
59 while(v[dr]==0 && dr<secv)
60 dr++;
61
62 if (v[st]==v[dr]) ///verific lipirea
63 {
64 f[dr]=f[dr]+f[st];
65 f[st]=0;
66 v[st]=0;
67 i=dr;///ce incerc sa scot
68 cauta=0;
69 }
70 else
71 cauta=1;
72 }
73 else
74 cauta=1;
75
76 if (cauta)
77 {
78 ///caut noua secv maxima
79 l=0;
80 u=0;
81 for(i=1;i<=secv;i++)
82 {
83 //fout<<v[i]<<" "<<f[i]<<endl;
84 if(f[i]>l) l=f[i],u=i;
85 }
86
87 i=u; /// plec de la cea mai lunga secventa...
88 }
89 }
90
91 fout<<n<<endl;
92
93 for(i=1;i<=secv;i++)
94 for(x=1;x<=f[i];x++)
95 fout<<v[i]<<endl;
96 }
97
98 return 0;
CAPITOLUL 5. OJI 2015 92
99 }
5.2 defrag
Problema 2 - defrag 90 de puncte
Discul dur (hard disk) este un dispozitiv utilizat pentru stocarea datelor. Stocarea se face pe
o suprafaµ magnetic dispus pe platane rotunde metalice. Pe un platan, datele sunt organizate
în piste ³i sectoare, iar zona aat la intersecµia dintre o pist ³i un sector poart denumirea de
cluster.
Un cluster poate avea dou st ri: liber, dac nu conµine date, sau ocupat, atunci când conµine
date.
Un platan se nume³te defragmentat dac toµi clusterii ocupaµi de pe ecare pist sunt a³ezaµi
în ordine consecutiv . Defragmentarea se realizeaz prin mutarea unor clusteri ocupaµi ³i are rolul
de a mic³ora timpul de acces la date. Mutarea unui cluster reprezint transferul datelor de la un
cluster ocupat c tre un cluster liber de pe aceea³i pist .
Cerinµe
Cunoscând num rul de piste P ³i de sectoare S al unui platan, num rul ³i poziµia clusterilor
ocupaµi, s se scrie un program care determin :
1. num rul de piste care au toµi clusterii liberi;
2. num rul minim de mut ri de clusteri, pentru ecare pist în parte, astfel încât platanul s
devin defragmentat.
Date de intrare
Pe prima linie a ³ierului de intrare defrag.in se g se³te num rul natural V a c rui valoare
poate doar 1 sau 2.
Pe a doua linie a ³ierului de intrare se g sesc dou numere naturale P ³i S , separate printr-un
spaµiu, cu semnicaµia din enunµ.
A treia linie conµine un num r natural C reprezentând num rul total de clusteri ocupaµi de pe
platan, iar pe ecare din urm toarele C linii se g se³te câte o pereche de valori pi ³i si , 1 & i & C ,
separate printr-un spaµiu, reprezentând pista, respectiv sectorul unde se a ecare cluster ocupat.
Date de ie³ire
Fi³ierul de ie³ire este defrag.out.
Dac valoarea lui V este 1 atunci ³ierul de ie³ire va conµine pe prima linie un num r natural
ce reprezint num rul de piste care au toµi clusterii liberi.
Dac valoarea lui V este 2 atunci ³ierul de ie³ire va conµine pe prima linie P numere naturale
notate Mi , 1 & i & P , separate prin câte un singur spaµiu, unde Mi reprezint num rul minim de
mut ri de clusteri, dintre cei aaµi pe pista i, astfel încât pe pista i clusterii ocupaµi s se g seasc
într-o ordine consecutiv .
Restricµii ³i preciz ri
CAPITOLUL 5. OJI 2015 93
Exemple
defrag.in defrag.out Explicaµii
1 1 Datele corespund gurilor anterioare:
48 V = 1, deci se rezolv NUMAI prima cerinµ .
10 a Num rul de piste P = 4 , num rul de sectoare S = 8
11 a Num rul total de clusteri ocupaµi este C = 10 (cei marcaµi cu
13 negru)
15 a Pe prima pist sunt 4 clusteri ocupaµi, în sectoarele 1, 3, 5 si
17 7.
45 a Pe a doua pist sunt 2 clusteri ocupaµi, în sectoarele 2 ³i 4.
41 a Pe a treia pist nu sunt clusteri ocupaµi.
46 a Pe a patra pist sunt 4 clusteri ocupaµi, în sectoarele 1, 5, 6
48 ³i 8.
22 O singur pist are toµi clusterii liberi, pista num rul 3, deci
24 valoarea cerut este 1;
2 2101 Datele corespund gurilor anterioare:
48 V = 2, deci se rezolv NUMAI a doua cerinµ .
10 a Pe prima pist sunt necesare minim dou mut ri de clusteri
11 pentru ca toµi clusterii ocupaµi s se g seasc într-o ordine con-
13 secutiv , deci valoarea cerut este 2.
15 a Pe a doua pist este sucient o singur mutare de cluster,
17 pentru ca toµi clusterii ocupaµi s se g seasc într-o ordine con-
45 secutiv , deci valoarea cerut este 1.
41 a Pe a treia pist nu sunt clusteri ocupaµi, deci valoarea cerut
46 este 0.
48 a Pe a patra pist este sucient o singur mutare de cluster,
22 pentru ca toµi clusterii ocupaµi s se g seasc într-o ordine con-
24 secutiv , deci valoarea cerut este 1.
Pentru rezolvarea primei cerinµe se determin câµi clusteri sunt ocupaµi pe ecare pist . Se
poate utiliza în acest scop o matrice având num rul de linii egal cu num rul de piste ³i num rul
de coloane egal cu num rul de sectoare al platanului. La ecare citire de cluster ocupat se seteaz
în matrice poziµia dat de pista ³i sectorul clusterului pe 1 (iniµial ind pe 0). în acela³i timp se
contorizeaz în primul element de pe ecare linie num rul de clusteri ocupaµi. Prin parcurgerea
elementelor de pe prima coloan a matricei se determin valoarea cerut la prima cerinµ , prin
sc dere faµ de num rul total de sectoare.
Pentru a doua cerinµ se procedeaz astfel:
Imaginându-ne c s-a realizat mutarea unor clusteri ³i s-a obµinut o zon contigu , aceast
zon va avea lungimea egal cu num rul de clusteri ocupaµi pe ecare pist . Aceast zon poate
începe în orice poziµie a pistei (de la 1 la ns), îns numai unele dintre aceste secvenµe au un num r
minim de clusteri liberi.
A³adar se preia num rul de clusteri ocupaµi pe ecare linie, calculat anterior, pe care s -l
not m cu ncoi (num r clusteri ocupaµi pe pista i) ³i se analizeaz toate secvenµele de câte ncoi
elemente, începând cu poziµia 1 pân la o poziµie în care zona se termin pe ultimul sector, ³i se
CAPITOLUL 5. OJI 2015 94
determin num rul minim de clusteri de 0 pentru toate secvenµele. Aceast valoare este valoarea
cerut la cerinµa 2.
O soluµie care implementeaz algoritmul descris mai sus obµine aproximativ jumatate din
punctaj, deoarece nu µine cont de circularitatea a³ez rii clusterilor.
Pentru a rezolva ³i circularitatea a³ez rii clusterilor se realizeaz o copie a matricii clusterilor pe
âorizontal prin dublarea num rului de sectoare. în acest mod se poate testa ³i dac secvenµele
cu clusteri consecutivi pot începe chiar de pe ultimul sector, formând astfel o zon contigu cu
clusteri aaµi în primele sectoare.
Pentru optimizarea algoritmului descris anterior, se poate proceda astfel: se determin num rul
de clusteri liberi din secvenµa care începe pe primul sector ³i are lungimea ncoi, apoi la ecare
nou secvenµa de aceea³i lungime mutat cu o poziµie c tre dreapta (sau stânga),se adun sau
se scade câte un element în funcµie de ce se întâmpl la capete, deoarece celelalte elemente din
secvenµ nu se modic .
³i
Se observ c
bj bj 1 aij 1 aij k 1 pentru j 1, 2, ...., s k 1
³i
c1 bs k 1 ais k 1 ai1
cj cj 1 ais k j aij
pentru j 2, 3, ..., k 1
Se poate observa u³or c nu avem nevoie de vectorii b ³i c, ci doar de o variabila simpl în care
memor m suma curent ³i pe care o actualiz m la ecare pas.
R spunsul la a doua cerinµ este k - maximul dintre rb1, b2, ..., bs k 1, c1, c2, ..., ck 1x
3
4 #include <iostream>
5 #include <fstream>
6
7 #define pmax 101
8 #define smax 361
9
10 using namespace std;
11
12 short hdd[pmax][2*smax];
13
14 // ns = numar sectoare
15 // np = numar piste
16 // nso = numar sectoare ocupate
17 // xs = sector curent citit
18 // xp = pista curenta citita
19 // po = piste ocupate
20
21 int main()
22 {
23 int v,c,np,ns,xp,xs,i,j,k,po,min,s,nso;
24
25 ifstream f("defrag.in");
26 ofstream g("defrag.out");
27
28 // citesc configuratia HDD
29 f>>v>>np>>ns;
30
31 // citesc cate clustere sunt ocupate
32 f>>c;
33
34 // citesc clusterele ocupate
35 for(i=1;i<=c;i++)
36 {
37 f>>xp>>xs;
38 hdd[xp][xs]=1;
39
40 // extindere matrice
41 hdd[xp][xs+ns]=1;
42
43 hdd[xp][0]++;
44 }
45
46 if (v==1)
47 {
48 // cate piste nu au clustere ocupate
49 po=0;
50 for(i=1;i<=np;i++)
51 if (hdd[i][0])
52 po++;
53 g<<np-po;
54 }
55
56 if (v==2)
57 {
58 // determin numarul minim de mutari de clusteri, pe fiecare pista,
59 // pentru a obtine zone contigue
60 for(i=1;i<=np;i++)
61 {
62 min=ns;
63 nso=hdd[i][0];
64
65 // j = pozitie inceput de secventa
66 for(j=1;j<=ns;j++)
67 {
68 s=0;
69 for(k=j;k<j+nso;k++)
70 if (hdd[i][k]==0) s++;
71
72 if (s<min)
73 min=s;
74 }
75
76 g<<min<<" ";
77 }
78 }
CAPITOLUL 5. OJI 2015 96
79
80 g<<"\n";
81 f.close();
82 g.close();
83
84 return 0;
85 }
48 }
49
50 if (V == 1)
51 fout << pisteLibere << ’\n’;
52 else
53 {
54 int k, sum;
55 for (int p = 0; p < P; ++p)
56 {
57 k = cnt[p];
58 if ( k == 0 )
59 {
60 fout << 0 << ’ ’;
61 continue;
62 }
63
64 sum = 0;
65 for (int i = 0; i < k; ++i)
66 sum += d[p][i];
67
68 sp[k - 1] = sum;
69 for (int i = k; i < S + k; ++i )
70 sp[i % S] = sp[(i - 1)% S] + d[p][i % S] - d[p][i - k];
71
72 int maxim = 0;
73 for (int i = 0; i < S; ++i)
74 maxim = max(maxim, sp[i]);
75
76 fout << k - maxim << ’ ’;
77 }
78 }
79
80 fin.close();
81 fout.close();
82 }
38 cel=viz[x];
39 for(j=1;j<=sect;j++)
40 {
41 a[i][j+sect]=a[i][j];
42 a[i][j]=a[i][j-1]+a[i][j];//, fout<<a[i][j]<<"_";
43 }
44
45 for(j=sect+1;j<=2*sect;j++)
46 a[i][j]=a[i][j-1]+a[i][j];//, fout<<a[i][j]<<"_";
47
48 mut=0;
49 for(j=1;j<2*sect-cel;j++)
50 if(a[i][j+cel]-a[i][j]>mut ) mut=a[i][j+cel]-a[i][j];
51
52 fout<<cel-mut<<’ ’;
53 }
54 }
55
56 return 0;
57 }
53 if (b>m)
54 m=b;
55 }
56
57 // zonele de la final de pista care se completeaza
58 // la inceptul pistei
59 for (j=1;j<=k-1;j++)
60 {
61 b=b-a[i][s-k+j]+a[i][j];
62 if (b>m)
63 m=b;
64 }
65
66 g<<k-m<<" ";
67 }
68
69 }
70
71 g<<"\n";
72 g.close();
73 return 0;
74 }
51 for(j=1;j<=2*s-fr[i]-1;j++)
52 if(fr[i]-(a[i][j+fr[i]-1]-a[i][j-1])<min)
53 min=fr[i]-(a[i][j+fr[i]-1]-a[i][j-1]);
54
55 g<<min<<" ";
56 }
57
58 return 0;
59 }
Capitolul 6
OJI 2014
6.1 cool
Problema 1 - cool 100 de puncte
Se consider un ³ir A format din N elemente naturale nenule. Numim secvenµ de lungime K
a ³irului A orice succesiune de elemente consecutive din ³ir de forma Ai , Ai1 , ..., AiK 1 .
O secvenµ o numim secvenµ cool dac elementele care o compun sunt distincte ³i pot
rearanjate astfel încât s alc tuiasc o secvenµ continu de numere consecutive.
De exemplu, considerând ³irul A 3, 1, 6, 8, 4, 5, 6, 7, 4, 3, 4, atunci secvenµa 8, 4, 5, 6, 7 este
o secvenµ cool deoarece conµine elemente distincte ce pot rearanjate astfel încât s alc tuiasc
³irul de numere consecutive 4, 5, 6, 7, 8, pe când secvenµele 4, 3, 4, 6, 7, 4, 3 nu sunt considerate
secvenµe cool.
Cerinµe
Fiind dat un ³ir de N numere naturale nenule se cer urm toarele:
1. Pentru o valoare dat K s se verice dac secvenµa A1 , A2 , ..., AK este secvenµ cool.
Dac secvenµa este cool, atunci se va a³a cea mai mare valoare ce aparµine secvenµei. Dac
secvenµa nu este cool, atunci se va a³a num rul elementelor distincte din secvenµa A1 , A2 , ...,
AK , adic num rul elementelor care apar o singur dat .
2. Lungimea maxim a unei secvenµe cool ³i num rul secvenµelor cool de lungime maxim .
Date de intrare
Fi³ierul de intrare cool.in conµine pe prima linie un num r natural p. Pentru toate testele de
intrare, num rul p poate avea doar valoarea 1 sau valoarea 2. Pe linia a doua se g sesc, desp rµite
printr-un spaµiu, dou numere naturale N K . Pe urm toarea linie se g sesc N numere întregi,
separate prin câte un spaµiu, ce reprezint elementele ³irului.
Date de ie³ire
Dac valoarea lui p este 1, atunci se va rezolva numai punctul 1 din cerinµ . În acest caz, ³ierul
de ie³ire cool.out va conµine pe prima linie un num r natural, num r ce reprezint conform cerinµei
1, maximul secvenµei A1,A2, ...,AK , dac secvenµa este secvenµ cool, sau num rul elementelor
distincte din secvenµ , dac aceasta nu este secvenµ cool.
Dac valoarea lui p este 2, se va rezolva numai punctul 2 din cerinµ . În acest caz, ³ierul de
ie³ire cool.out va avea dou linii. Prima linie va conµine un num r natural nenul ce reprezint
lungimea maxim a unei secvenµe cool, iar urm toarea linie un num r natural nenul ce reprezint
num rul de secvenµe cool care au lungimea maxim .
Restricµii ³i preciz ri
a 1 & N & 5000
a 2 & K & 1000
a 1 & Ai & 1000, 1 & i & N
a Pentru 30% dintre teste N & 1000
a Pentru rezolvarea primei cerinµe se acord 20% din punctaj, iar pentru cerinµa a doua se
acord 80% din punctaj.
102
CAPITOLUL 6. OJI 2014 103
Exemple
col.in col.out Explicaµii
1 7 Atenµie! Pentru acest test se rezolv doar cerinµa 1.
7 4 Secvenµa 6 4 5 7 este cool.
6 457835 Valoarea maxim din secvenµ este 7
1 2 Atenµie! Pentru acest test se rezolv doar cerinµa 1.
7 6 Secvenµa 6 4 5 7 5 4 nu este secvenµ cool. Num rul
6 457543 valorilor distincte din secvenµ este 2. Valorile distincte
sunt: 6,7
2 5 Atenµie! Pentru acest test se rezolv doar cerinµa 2.
11 4 2 Cele dou secvenµe cool de lungime maxim 5 sunt:
74568457432 74568
68457
Cerinµa 1. ( 20 puncte)
Printr-o simpl vericare a frecvenµei de apariµie a primelor k numere se obµine r spunsul
a³teptat.
Cerinµa 2.
O soluµie brute-force obµine 25 p.
O soluµie bazat pe set(stl) obµine 40 50 p.
Soluµia 1. ( 80 puncte) (Eugen Nodea)
Rezolvarea cerinµei necesit câteva observaµii.
Fie secvenµa ce conµine k numere consecutive distincte:
x 1, x 2, ..., x k
Observ m c :
1) min x 1, max x k => max min k1
2) elementele sunt distincte
3) relaµia 1) este adev rat indiferent de ordinea elementelor
A³adar,
- pentru orice secvenµa care începe pe poziµia i si se termina pe poziµia j se va determina
minimul si maximul
- secvenµa este cool daca respecta relaµiile 1) si 2)
Astfel, complexitatea rezolv rii subpunctului b) poate redus la O N k amortizat.
Soluµia 2. ( 80 puncte) (Constantin Galatan)
Pentru secvenµa curent cuprins între poziµiile i ³i j , se menµine un ³ir de contoare pentru
valorile din secvenµ . La ad ugarea unui nou element aj în secvenµ se incrementeaz valoarea
contorului corespunz tor: cntaj , iar la eliminarea unui element ai din secvenµ , contorul
se decrementeaz : cntai . Se reµin de asemenea maximul ³i minimul valorilor din secvenµ
în amax ³i amin. La ecare pas se veric dac amax - amin == j - i ³i c nicio valoare din
2
secvenµ nu are contorul mai mare decât 1. Complexitatea soluµiei este O n
80 {
81 v[a[k]]++;
82 if (v[a[k]]>1)
83 {
84 ok=0;
85 break;
86 }
87 }
88
89 // daca este secventa cool verific lungimea ei
90 if (ok)
91 {
92 if (max-min+1>lsec)
93 {
94 lsec=max-min+1;
95 nrsec=1;
96 }
97 else
98 if (max-min+1==lsec)
99 nrsec++;
100 }
101 }
102 }
103 }
104 }
105
106 g<<lsec<<"\n"<<nrsec<<"\n";
107 }
108
109 f.close();
110 g.close();
111
112 return 0;
113 }
39 }
40 }
41
42 int main()
43 {
44 int i, p, Min = 1001, nr_dist = 0;
45
46 f >> p >> n >> k;
47 for (i=1; i<=n; ++i)
48 f >> a[i];
49
50 if (p == 1)
51 { //a
52 for (i=1; i<=k; ++i)
53 {
54 ap[a[i]]++;
55 if (a[i] < Min) Min = a[i];
56 if (a[i] > Max) Max = a[i];
57 }
58
59 for (i=Min; i<=Max; ++i)
60 if (ap[i] == 1) ++nr_dist;
61
62 if (nr_dist == k)
63 g << Max << "\n";
64 else
65 g << nr_dist << "\n";
66 }
67 else
68 { //b
69 cool();
70 g << Max << "\n" << nr <<"\n";
71 }
72
73 return 0;
74 }
37 }
38
39 int main()
40 {
41 int i, k, p, Min = 1001, nr_dist = 0;
42
43 freopen ("cool.in", "r", stdin);
44 freopen ("cool.out","w", stdout);
45
46 scanf("%d", &p);
47 scanf("%d %d", &n, &k);
48 for (i=1; i<=n; ++i)
49 scanf("%d", &a[i]);
50
51 if (p == 1)
52 { //a
53 for (i=1; i<=k; ++i)
54 {
55 ap[a[i]]++;
56 if (a[i] < Min) Min = a[i];
57 if (a[i] > Max) Max = a[i];
58 }
59
60 for (i=Min; i<=Max; ++i)
61 if (ap[i] == 1) ++nr_dist;
62
63 if (nr_dist == k)
64 printf("%d\n", Max);
65 else
66 printf("%d\n", nr_dist);
67 }
68 else
69 { //b
70 cool();
71 printf("%d\n%d\n", Max, nr);
72 }
73
74 return 0;
75 }
34 }
35
36 if ( T == 1 )
37 {
38 bool cool = true; int distincte = 0;
39 for ( int x = minK; x <= maxK; ++x )
40 {
41 if ( nr[x] == 0 || nr[x] > 1 )
42 cool = false;
43 if ( nr[x] == 1 ) distincte++;
44 }
45
46 if ( cool )
47 fout << maxK << ’\n’;
48 else
49 fout << distincte << ’\n’;
50 }
51 else
52 {
53 for ( int i = 0; i < n; ++i )
54 {
55 cnt[a[i]]++, bad = 0;
56 amin = amax = a[i];
57 for ( int j = i + 1; j < n; ++j )
58 {
59 cnt[a[j]]++, L = j - i + 1;
60 if ( cnt[a[j]] > 1 ) bad++;
61
62 if ( amax < a[j] ) amax = a[j];
63 if ( amin > a[j] ) amin = a[j];
64
65 if ( bad || amax - amin != j - i )
66 continue;
67 if ( L > Lmax )
68 Lmax = L, nMaxCool = 1;
69 else
70 if ( L == Lmax ) nMaxCool++;
71 }
72
73 cnt[a[i]]--;
74 memset(cnt, 0, sizeof(cnt));
75 }
76
77 fout << Lmax << ’\n’ << nMaxCool << ’\n’;
78 }
79
80 return 0;
81 }
6.2 pseudobil
Problema 2 - pseudobil 100 de puncte
Suprafaµa plan a unei mese de pseudo-biliard este format din n n celule p tratice cu
lungimea laturii egal cu 1 (o unitate), lipite, dispuse pe n linii numerotate de la 1 la n ³i n
coloane, numerotate de la 1 la n. Pe mas se a³eaz K bile, ecare bil g sindu-se în centrul unei
anumite celule a mesei. Un juc tor dore³te s plaseze pe suprafaµa mesei un cadru p tratic având
lungimea diagonalei egal cu D unit µi.
El trebuie s r spund la m întreb ri de forma: x y . Fiecare întrebare are semnicaµia: câte
bile se g sesc în interiorul sau pe laturile cadrului ?
Cadrul se plaseaz astfel încât ecare colµ s e poziµionat în centrul unei celule, colµurile
opuse s se g seasc pe aceea³i coloan , respectiv pe aceea³i linie, iar colµul de sus s e plasat
în centrul celulei aat pe linia x ³i coloana y .
Cerinµe
Cunoscând lungimea n a laturilor mesei, num rul m de întreb ri, num rul K de bile a³ezate
pe mas , poziµiile lor ³i lungimea D a diagonalei cadrului p tratic, se cere:
1. Num rul de celule care se vor g si în întregime în interiorul cadrului, dac acesta se a³eaz
pe suprafaµa mesei, conform descrierii de mai sus.
CAPITOLUL 6. OJI 2014 109
Date de intrare
Fi³ierul de intrare pseudobil.in conµine pe prima linie un num r natural p. Pentru toate
testele de intrare, num rul p poate avea doar valoarea 1 sau valoarea 2.
Pe linia a doua se g sesc numerele naturale n, K ³i D separate prin câte un spaµiu.
Pe ecare dintre urm toarele K linii, se g sesc câte dou numere a ³i b (a, b & n) reprezentând
linia ³i coloana celulei în centrul c reia va a³ezat o bil .
Pe linia K 3 se g se³te un num r natural m.
Urm toarele m linii conµin câte dou numere naturale x ³i y , reprezentând linia ³i coloana
celulei în centrul c reia se va plasa colµul de sus al cadrului.
Date de ie³ire
Dac valoarea lui p este 1, se va rezolva numai punctul 1 din cerinµ . În acest caz, în ³ierul
de ie³ire pseudobil.out se va scrie un singur num r natural n1 , reprezentând num rul de celule
care se vor g si în întregime în interiorul cadrului.
Dac valoarea lui p este 2, se va rezolva numai punctul 2 din cerinµ . În acest caz, ³ierul de
ie³ire pseudobil.out va conµine m linii. Pe ecare linie i se va scrie câte un num r natural n2 ,
reprezentând r spunsul pentru întrebarea i.
Restricµii ³i preciz ri
a 3 & n & 1500
a 1 & K & 55000
a 2 & D & n 1, D - num r par
a 1 & m & 100000
a Poziµiile cadrului sunt distince.
a Se garanteaz pentru x ³i y valori pentru care cadrul este plasat în interiorul suprafeµei mesei
de pseudo-biliard.
a Pentru rezolvarea corect a primei cerinµe se acord 20 de puncte, iar pentru cerinµa a doua
se acord 80 de puncte.
a Pentru primele 35% dintre testele care veric cerinµa 2, m & 1000 ³i n & 500
a Pentru primele 75% din testele care veric cerinµa 2, m & 10000 ³i n & 1000
Exemple
Cerinµa 1 ( 20 puncte)
Se parcurg segmentele orizontale care conµin numai celule în interiorul p tratului.
Se observ c segmentul de lungime maxim are nr D 1 celule. Segmentul aat imediat
de deasupra ³i cel de dedesupt au ecare câte nr 2 celule. Soluµia va
nr1 nr 2 nr 2 2 nr 4 ... 2 1
Cerinµa 2 ( 80 de puncte)
Soluµie O m n2
Pentru ecare interogare, se parcurg orizontal toate segmentele formate din celule interioare
sau traversate pe diagonal de c tre laturile p tratului.
Acest soluµie obµine 30 de puncte din punctajul cerinµei 2.
Soluµie O m K (Ciprian Che³c )
Se ³tie c o dreapt de ecuaµie ax by c 0 împarte planul în dou semiplane cu proprietatea
c toate punctele dintr-un semiplan veric relaµia ax by c % 0 sau ax by c $ 0.
Notând vârfurile cadrului cu ABCD laturile acestuia formeaz 4 drepte : AB , CD respectiv
AD, BC . Putem considera c o bila se g se³te în interiorul cadrului dac bila se g se³te în
regiunea pozitiv a semiplanului AB ³i regiunea negativ a semiplanului CD ³i analog dac bila
se g se³te în regiunea pozitiv a semiplanului AD ³i regiunea negativ a semiplanului BC .
Calculând în ce semiplan se g se³te ecare bil în funcµie de poziµia cadrului se poate deduce
dac bila este în interiorul cadrului sau pe una din laturi.
Acest soluµie obµine 30 de puncte din punctajul cerinµei 2.
Soluµie O n2 m n
Pentru reducerea complexit µii la O n per interogare, se reµin sumele parµiale pentru ecare
coloan a matricei.
Fie deci matricea a, cu aij - num rul de bile aate pe coloana j , pân la linia i.
Se parcurge ecare segment vertical aat în interiorul cadrului ³i se calculeaz num rul de bile
ca ind ai2 j ai1 j unde i2 este linia pe care se g se³te ultima celul (cea mai de jos), iar
i1 este linia anterioar primei celule a segmentului.
Acest soluµie obµine 60 de puncte din punctajul cerinµei 2.
CAPITOLUL 6. OJI 2014 111
Pentru a aa num rul de bile din interiorul cadrului plasat cu colµul superior în centrul celulei
CAPITOLUL 6. OJI 2014 112
x, y , se fac sume ³i diferenµe de sume parµiale. V puteµi gândi la arii ³i la principiul includerii
³i excluderii.
Prin urmare, aria poligonului acoperit de cadru (num rul de bile acoperite) va egal cu aria
întregii suprafeµe, din care se scad ariile poligoanelor marcate cu ro³u, verde ³i albastru:
2 Complexitate: O(m + n * n)
3 prof. Constantin Galatan
4 */
5 #include <iostream>
6 #include <fstream>
7 #include <vector>
8
9 using namespace std;
10
11 const int DIM = 1501;
12
13 ifstream fin("pseudobil.in");
14 ofstream fout("pseudobil.out");
15
16 typedef unsigned short M[2 * DIM][DIM];
17
18 M su, sd, pu, pd; // sec up, sec down, princ up, princ down
19 M a, b; // a[d][j] = 1 daca pe diagonala secundara d si coloana j
20 // este 1, b - acelasi lucru pentru diagonala principala d
21
22 int m, n, K, L, D, T, n1, n2;
23 unsigned short sc[DIM], ss[DIM], s[DIM]; // sume partiale pe coloane,
24 // suma dreptunghiului pana la col j
25 unsigned short sp1[DIM * 2], sp2[DIM * 2]; // suma pe diagonala curenta
26 // pana la coloana j
27
28 int main()
29 {
30 fin >> T >> n >> K >> D;
31 if ( T == 1 ) // rezolv numai cerinta 1)
32 {
33 int nr = D - 1;
34 n1 = nr;
35 while ( true )
36 {
37 nr -=2;
38 if ( nr < 0 ) break;
39 n1 += 2 * nr;
40 }
41
42 fout << n1 << ’\n’;
43 }
44 else // rezolv numai cerinta 2)
45 {
46 L = D / 2 + 1;
47 int d;
48 int x, y;
49
50 for ( int i = 0; i < K; ++i )
51 {
52 fin >> x >> y;
53 b[n + y - x][y] = 1;
54 a[x + y - 1][y] = 1;
55 s[y]++;
56 }
57
58 for ( int j = 1; j <= n; ++j )
59 ss[j] = ss[j - 1] + s[j];
60
61 for ( int d = 1; d < 2 * n; ++d )
62 {
63 for (int j = 0; j <= n; ++j )
64 sp1[j] = 0, sp2[j] = 0;
65
66 for ( int j = max(d - n + 1, 1); j <= min(d, n) ; ++j )
67 {
68 sp1[j] = sp1[j - 1] + a[d][j];
69 su[d][j] = su[d - 1][j] + sp1[j];
70
71 if ( j >= d ) su[d][j] += su[d - 1][j - 1];
72
73 sd[d][j] = ss[j] - su[d][j] + sp1[j];
74
75 sp2[j] = sp2[j - 1] + b[d][j];
76 pd[d][j] = pd[d - 1][j] + sp2[j];
77
CAPITOLUL 6. OJI 2014 114
78 if ( j >= d )
79 pd[d][j] += pd[d - 1][j - 1];
80
81 pu[d][j] = ss[j] - pd[d][j] + sp2[j];
82 }
83 }
84
85 int A, B, C, D, E, F;
86 fin >> m;
87
88 for ( int i = 0; i < m; ++i )
89 {
90 fin >> x >> y;
91
92 A = ss[y - L];
93 B = K - ss[y + L - 1];
94 if ( y > x + y - 2 )
95 C = su[x + y - 2][y - 1];
96 else
97 C = su[x + y - 2][y];
98
99 C -= su[x + y - 2][y - L];
100 D = pu[n - x + y + 1][y + L - 1] - pu[n - x + y + 1][y];
101
102 int X = x + 2 * (L - 1);
103 if ( y > n - X + y - 1)
104 E = pd[n - X + y - 1][y - 1];
105 else
106 E = pd[n - X + y - 1][y];
107
108 E -= pd[n - X + y -1][y - L];
109 F = sd[X + y ][y + L - 1] - sd[X + y ][y];
110 n2 = K - (A + B + C + D + E + F);
111
112 fout << n2 << ’\n’;
113 }
114 }
115
116 fin.close();
117 fout.close();
118 return 0;
119 }
31 if ( T == 1 )
32 { //1)
33 x = D / 2 - 1;
34 g << 2 * x * x + (D - 1) <<"\n";
35 }
36 else
37 { //2.
38 f >> m;
39 while (m--)
40 {
41 f >> x >> y;
42 x1 = x+y-1; y1 = n-x+y;
43 sol = nr[x1+D][y1] - nr[x1+D][y1-D-1] -
44 nr[x1-1][y1] + nr[x1-1][y1-D-1];
45
46 g << sol <<"\n";
47 }
48 }
49
50 return 0;
51 }
52 for(i=1;i<=m;i++)
53 {
54 fscanf(f,"%d%d",&x,&y);
55 x1=n-y+x;
56 y1=x+y-1;
57 x2=n-(y+d/2)+x+d/2;
58 y2=x+d/2+y+d/2-1;
59 x3=n-y+x+d;
60 y3=x+d+y-1;
61 x4=n-(y-d/2)+x+d/2;
62 y4=x+d/2+(y-d/2)-1;
63 n2=a[x3][y3]-a[x2-1][y2]-(a[x4][y4-1]-a[x1-1][y1-1]);
64 fprintf(g,"%d\n",n2);
65 }
66 }
67
68 fclose(f);
69 fclose(g);
70 return 0;
71 }
OJI 2013
7.1 betasah
Problema 1 - betasah 100 de puncte
Jocul beta³ah se joac folosindu-se doar piese asem n toare damelor clasicului ³ah, numite
N N 1
tot dame. Suprafaµa de joc are o form triunghiular ³i este format din 2
p trate identice
dispuse pe N rânduri ³i N coloane. Rândurile se numeroteaz de sus în jos, de la 1 la N . Coloanele
se numeroteaz de la stânga la dreapta, de la 1 la N . Primul rând conµine un singur p trat, al
doilea rând conµine dou p trate al turate, ..., al N -lea rând conµine N p trate al turate, ca în
N N 1
suprafeµele de joc cu N 6 din gurile de mai jos. Din cele 2
p trate, K sunt gri, iar restul
sunt albe. Poziµia ec rui p trat de pe suprafaµa de joc este dat de rândul ³i coloana în care
acesta este situat.
Pe suprafaµa de joc sunt a³ezate D dame în D p trate albe distincte, ocupându-le. Într-un
p trat alb poate a³ezat o singur dam , iar într-un p trat gri nu poate a³ezat nicio dam .
Poziµia unei dame pe suprafaµa de joc este dat de poziµia p tratului alb în care este a³ezat
dama.
Damele pot accesa orice p trat alb neocupat situat pe direcµiile: vertical , orizontal sau
diagonal , numerotate de la 1 la 8 în gura b). Accesul pe o direcµie se face trecând din p trat alb
în p trat alb (doar p trate albe neocupate) pân la întâlnirea unui p trat gri sau a unui p trat
alb ocupat de o alt dam sau pân la terminarea suprafeµei de joc.
Numim p trat accesibil orice p trat alb neocupat (de pe suprafaµa de joc) care ar putea
accesat de cel puµin una din cele D dame.
De exemplu, pentru suprafaµa de joc din gura c) num rul de p trate accesibile (marcate cu
X ) de pe suprafaµ este 11; pentru suprafaµa de joc cu N 6, D 3 ³i K 4 din gura d)
num rul de p trate accesibile de pe suprafaµ este 13. În gura e) sunt marcate cu X p tratele
accesibile ec rei dame de pe suprafaµa de joc din gura d).
118
CAPITOLUL 7. OJI 2013 119
Cerinµe
Scrieµi un program care s citeasc numerele naturale N , D, K , poziµiile damelor ³i ale p tra-
telor gri pe suprafaµa de joc ³i care s determine:
a) num rul maxim M de p trate albe conµinute de un rând al suprafeµei de joc;
b) num rul P de p trate accesibile de pe suprafaµa de joc.
Date de intrare
Fi³ierul de intrare betasah.in conµine:
- pe prima linie cele trei numere naturale N , D ³i K , separate prin câte un spaµiu, cu semni-
caµia din enunµ;
- pe linia i 1 dou numere naturale nenule xi ³i yi , separate printr-un singur spaµiu, repre-
zentând poziµia damei i pe suprafaµa de joc (rândul xi ³i coloana yi ), pentru i 1, 2, 3, ..., D;
- pe linia D 1 j dou numere naturale nenule zj ³i tj , separate printr-un singur spaµiu,
reprezentând poziµia p tratului gri j pe suprafaµa de joc (rândul zj ³i coloana tj ), pentru j
1, 2, 3, ..., K .
Date de ie³ire
Fi³ierul de ie³ire betasah.out va conµine pe prima linie num rul natural M ³i pe a doua linie
num rul natural P , cu semnicaµia din enunµ.
Restricµii ³i preciz ri
a 2 & N & 1000;
a 1 & D & 100;
a 1 & K & 50;
a DK &
N n1
2
;
a 1 & yi & xi & N pentru i 1, 2, 3, ..., D;
a 1 & tj & zj N pentru j 1, 2, 3, ..., K ;
a num rul M se va scrie obligatoriu pe prima linie a ³ierului de ie³ire betasah.out;
a num rul P se va scrie obligatoriu pe a doua linie a ³ierului de ie³ire betasah.out;
a pentru rezolvarea corect a cerinµei a) se acord 20% din punctaj, iar pentru rezolvarea
corect a cerinµei b) se acord 80% din punctaj.
Exemple
Pentru punctul a), se poate utiliza un vector v cu N componente care, iniµial, memoreaz în
ecare v i num rul maxim de p trate albe de pe rândul i: v i i pentru i 1, 2, 3, ..., N .
La citirea rândului i ³i a coloanei j pentru ecare p trat gri se decrementeaz valoarea com-
ponentei v i.
Num rul maxim M de p trate albe care pot conµinute de un rând al suprafeµei de joc este
egal cu maximul valorilor componentelor vectorului v , M max v 1, v 2, ..., v N
Pentru punctul b), o soluµie se poate obµine utilizând o matrice A cu N linii si N coloane.
Partea inferioar a matricei, format din elementele situate sub diagonala principal inclusiv
diagonala principal , vor reprezenta p tratele din suprafaµa de joc.
Iniµial, matricea va avea toate elementele cu valoarea 0, adic toate p tratele sunt albe.
Elementele matricei care corespund poziµiilor damelor vor avea valoarea 1, iar cele corespun-
z toare p tratelor gri vor avea valoarea 2. Pentru ecare dam se va simula deplasarea pe cele
8 direcµii. Dac dama se a în p tratul din poziµia l, c atunci aceasta se poate deplasa în
p tratele accesibile ale c ror poziµii corespund elementelor cu valoarea 0 din partea inferioar a
matricei ³i sunt situate în direcµia:
- 1, prin mic³orarea indicelui de linie: l 1, c, l 2, c, l 3, c etc.
- 5, prin m rirea indicelui de linie: l 1, c, l 2, c, l 3, c etc.
- 7, pe aceea³i linie, la stânga, prin mic³orarea indicelui de coloan :
l, c 1, l, c 2, l, c 3 etc.
- 3, pe aceea³i linie, la dreapta, prin m rirea indicelui de coloan : l, c
1, l, c 2, l, c 3 etc.
- 8, diagonal , prin mic³orarea indicilor de linie ³i coloan : l 1, c
1, l 2, c 2, l 3, c 3 etc. Figura 7.4: betasah
- 4, diagonal , prin m rirea indicilor de linie ³i coloan : l 1, c 1, l 2, c 2, l 3, c 3
etc.
- 2, diagonal , prin mic³orarea indicelui de linie ³i m rirea celui de coloan : l 1, c 1, l
2, c 2, l 3, c 3 etc.
- 6, diagonal , prin m rirea indicelui de linie ³i mic³orarea celui de coloan : l 1, c 1, l
2, c 2, l 3, c 3 etc.
Elementele matricei ce corespund p tratelor accesibile vor memora valoarea 3.
Pentru a se evita ie³irea din suprafaµa de joc în timpul c ut rii poziµiilor accesibile, se poate
borda partea inferioar a matricei cu valori de 2 sau se vor verica indicii ec rei poziµii accesibile
x, y : 1 $ x $ N ³i 1 $ y $ x.
Dup stabilirea p tratelor accesibile pentru ecare dam , partea inferioar a matricei va avea
elemente cu valoarea 3 ce corespund acestor p trate. Parcurgând partea inferioar a matricei, se
vor num ra aceste valori de 3. Num rul lor va reprezenta num rul P de p trate accesibile de pe
suprafaµa de joc.
Observaµie: o soluµie care const în parcurgerea integral a suprafeµei de joc ³i vericarea
pentru ecare p trat alb dac pe una din cele 8 direcµii exist vreo dam care s -l acceseze va
obµine un punctaj de aprox. 55p din cauza dep ³irii timpului de executare.
4
5 using namespace std;
6
7 int n,d,k,pozdama[103][3], albe[1003];
8 char a[1003][1003];
9
10 ifstream f("betasah.in");
11 ofstream g("betasah.out");
12
13 int main()
14 {
15 //citire date
16 int i,l,c,j,i1;
17 f>>n>>d>>k;
18 for(i=1;i<=d;i++)
19 {
20 f>>l>>c;
21 a[l][c]=1;//codific cu 1 pozitia damei din joc
22 pozdama[i][1]=l;pozdama[i][2]=c;
23 }
24
25 for(i=1;i<=n;i++) albe[i]=i;
26 for(i=1;i<=k;i++)
27 {
28 f>>l>>c;
29 a[l][c]=2;//codific cu 2 patratele gri din joc
30 albe[l]--;//scad patratele gri din nr total de patrate de pe linia l
31 }
32
33 int M=albe[1]; //a)
34 for(i=2;i<=n;i++)M=max(albe[i],M);
35
36 //bordare matrice. Incadrez suprafata de joc cu patrate gri
37 //pentru a nu iesi din suprafata de joc
38 for(i=0;i<=n+1;i++)
39 a[i][0]=a[i][i+1]=a[i][i+2]=2;
40 for(j=0;j<=n+2;j++)
41 a[n+1][j]=2;
42
43 //determin pentru fiecare dama patratele accesibile
44 for(i=1;i<=d;i++)
45 {
46 l=pozdama[i][1];
47 c=pozdama[i][2];
48
49 //pe aceeasi linie
50 j=c-1;
51 while(a[l][j]!=2)//directia 7
52 {
53 if(a[l][j]==0)a[l][j]=3;
54 j--;
55 }
56 j=c+1;
57 while(a[l][j]!=2)//directia 3
58 {
59 if(a[l][j]==0)a[l][j]=3;
60 j++;
61 }
62
63 //pe aceeasi coloana
64 i1=l-1;
65 while(a[i1][c]!=2)//directia 1
66 {
67 if(a[i1][c]==0)a[i1][c]=3;
68 i1--;
69 }
70 i1=l+1;
71 while(a[i1][c]!=2)//directia 5
72 {
73 if(a[i1][c]==0)a[i1][c]=3;
74 i1++;
75 }
76
77 //pe diagonala 8-4
78 i1=l-1;
79 j=c-1;
CAPITOLUL 7. OJI 2013 122
80 while (a[i1][j]!=2)//directia 8
81 {
82 if(a[i1][j]!=1)
83 a[i1][j]=3;//marchez cu 3 patratele accesibile
84 i1--;
85 j--;
86 }
87
88 i1=l+1;
89 j=c+1;
90 while (a[i1][j]!=2)//directia 4
91 {
92 if(a[i1][j]!=1)
93 a[i1][j]=3;
94 i1++; j++;
95 }
96
97 //pe diagonala 2-6
98 i1=l-1;
99 j=c+1;
100 while (a[i1][j]!=2)//spre 2
101 {
102 if(a[i1][j]!=1) a[i1][j]=3;
103 i1--;
104 j++;
105 }
106
107 i1=l+1;
108 j=c-1;
109 while (a[i1][j]!=2)//spre 6
110 {
111 if(a[i1][j]!=1)
112 a[i1][j]=3;
113 i1++;
114 j--;
115 }
116 }
117
118 //numarul patratelor accesibile = nr valori de 3 din matrice
119 int P=0;
120 for(i=1;i<=n;i++)
121 for(j=1;j<=i;j++)
122 if(a[i][j]==3)
123 P++;
124
125 g<<M<<endl<<P<<endl;
126
127 return 0;
128 }
24 for(i=1;i<=n;i++ )v[i]=i;
25 for(i=1;i<=k;i++)
26 {
27 f>>l>>c; v[l]--;
28 a[l][c]=2;//codific cu 2 patratele gri din joc
29 }
30 }
31
32 void bordare()//incadrez suprafata de joc cu patrate gri
33 //pentru a nu iesi din suprafata de joc
34 {
35 int i,j;
36 for(i=0;i<=n+1;i++)
37 a[i][0]=a[i][i+1]=a[i][i+2]=2;
38 for(j=0;j<=n+2;j++)
39 a[n+1][j]=2;
40 }
41
42 void linie(int l,int c) //deplasare dama pe aceeasi linie
43 {
44 int j=c-1;
45 while(a[l][j]!=2)//directia 7
46 {
47 if(a[l][j]==0)a[l][j]=3;
48 j--;
49 }
50
51 j=c+1;
52 while(a[l][j]!=2)//directia 3
53 {
54 if(a[l][j]==0)a[l][j]=3;
55 j++;
56 }
57 }
58
59 void coloana(int l,int c)//deplasare dama pe aceeasi coloana
60 {
61 int i=l-1;
62 while(a[i][c]!=2)//directia 1
63 {
64 if(a[i][c]==0)a[i][c]=3;
65 i--;
66 }
67
68 i=l+1;
69 while(a[i][c]!=2)//directia 5
70 {
71 if(a[i][c]==0)a[i][c]=3;
72 i++;
73 }
74 }
75
76 void diag1(int l,int c)//deplasare dama pe directia 8-4
77 {
78 int i,j;
79 i=l-1;
80 j=c-1;
81 while (a[i][j]!=2)//directia 8
82 {
83 if(a[i][j]!=1) a[i][j]=3;//marchez cu 3 patratele accesibile
84 i--;
85 j--;
86 }
87
88 i=l+1;
89 j=c+1;
90 while (a[i][j]!=2)//directia 4
91 {
92 if(a[i][j]!=1)
93 a[i][j]=3;
94 i++;
95 j++;
96 }
97 }
98
99 void diag2(int l,int c)//deplasare dama pe directia 2-6
CAPITOLUL 7. OJI 2013 124
100 {
101 int i,j;
102 i=l-1;
103 j=c+1;
104 while (a[i][j]!=2)//directia 2
105 {
106 if(a[i][j]!=1) a[i][j]=3;
107 i--;
108 j++;
109 }
110
111 i=l+1;
112 j=c-1;
113 while (a[i][j]!=2)//directia 6
114 {
115 if(a[i][j]!=1)
116 a[i][j]=3;
117 i++;
118 j--;
119 }
120 }
121
122 int numara()
123 {
124 //numarul patratelor accesibile = nr valori de 3 din matrice
125 int i,j,P=0;
126 for(i=1;i<=n;i++)
127 for(j=1;j<=i;j++)
128 if(a[i][j]==3)
129 P++;
130 return P;
131 }
132
133 int main()
134 {
135 int i,l,c,M;
136
137 citeste();
138 bordare();
139
140 M=v[1];
141 for(i=2;i<=n;i++) M=max(M,v[i]);
142 for(i=1;i<=d;i++)
143 {
144 l=pozdama[i][1];
145 c=pozdama[i][2];
146 linie(l,c);
147 coloana(l,c);
148 diag1(l,c);
149 diag2(l,c);
150 }
151
152 g<<M<<endl<<numara()<<endl;
153
154 return 0;
155 }
17
18 //initializez partea inferioara a matricei cu 0
19 for(i=1;i<=n;i++)
20 for(j=1;j<=i;j++)a[i][j]=0;
21
22 for(i=1;i<=d;i++)
23 {
24 f>>l>>c;
25 a[l][c]=1;//codific cu 1 pozitia damei din joc
26 pozdama[i][1]=l;pozdama[i][2]=c;
27 }
28
29 for(i=1;i<=n;i++)albe[i]=i;
30 for(i=1;i<=k;i++)
31 {
32 f>>l>>c;
33 a[l][c]=2;//codific cu 2 patratele gri din joc
34 albe[l]--;//scad patratele gri din nr total de patrate de pe linia l
35 }
36
37 M=albe[1]; //a)
38 for(i=2;i<=n;i++) M=max(albe[i],M);
39 g<<M<<endl;
40
41 //bordare matrice. Incadrez suprafata de joc cu patrate gri
42 //pentru a nu iesi din suprafata de joc
43 for(i=0;i<=n+1;i++)
44 a[i][0]=a[i][i+1]=a[i][i+2]=2;
45 for(j=0;j<=n+2;j++)
46 a[n+1][j]=2;
47
48 //determin pentru fiecare dama patratele accesibile
49 for(i=1;i<=d;i++)
50 {
51 l=pozdama[i][1];
52 c=pozdama[i][2];
53 //pe aceeasi linie
54 j=c-1;
55
56 while(a[l][j]!=2)//directia 7
57 {
58 if(a[l][j]==0) a[l][j]=3;
59 j--;
60 }
61
62 j=c+1;
63 while(a[l][j]!=2)//directia 3
64 {
65 if(a[l][j]==0) a[l][j]=3;
66 j++;
67 }
68
69 //pe aceeasi coloana
70 i1=l-1;
71 while(a[i1][c]!=2)//directia 1
72 {
73 if(a[i1][c]==0) a[i1][c]=3;
74 i1--;
75 }
76
77 i1=l+1;
78 while(a[i1][c]!=2)//directia 5
79 {
80 if(a[i1][c]==0) a[i1][c]=3;
81 i1++;
82 }
83
84 //pe diagonala 8-4
85 i1=l-1;
86 j=c-1;
87 while (a[i1][j]!=2)//directia 8
88 {
89 if(a[i1][j]!=1) a[i1][j]=3;//marchez cu 3 patratele accesibile
90 i1--;
91 j--;
92 }
CAPITOLUL 7. OJI 2013 126
93
94 i1=l+1;
95 j=c+1;
96 while (a[i1][j]!=2)//directia 4
97 {
98 if(a[i1][j]!=1) a[i1][j]=3;
99 i1++;
100 j++;
101 }
102
103 //pe diagonala 2-6
104 i1=l-1;
105 j=c+1;
106 while (a[i1][j]!=2)//directia 2
107 {
108 if(a[i1][j]!=1) a[i1][j]=3;
109 i1--;
110 j++;
111 }
112
113 i1=l+1;
114 j=c-1;
115 while (a[i1][j]!=2)//directia 6
116 {
117 if(a[i1][j]!=1) a[i1][j]=3;
118 i1++;
119 j--;
120 }
121 }
122
123 //numarul patratelor accesibile = nr valori de 3 din matrice
124 for(i=1;i<=n;i++)
125 for(j=1;j<=i;j++)
126 if(a[i][j]==3) P++;
127 g<<P<<endl;
128 return 0;
129 }
36
37 for(i=1;i<=N;i++)
38 M=(M+V[i]+(int)abs((double)M-V[i]) )/2;
39
40 for(i=0;i<=N+1;i++)
41 {
42 T[i][0]=-1;
43 T[N+1][i]=-1;
44 T[0][i]=-1;
45 }
46
47 for (i=1;i<=D;i++)
48 {
49 l=Dame[0][i];
50 c=Dame[1][i];
51 T[l][c]=0;
52
53 // directia NORD
54 while (l>=c && (abs)((float)T[l][c])!=1)
55 {
56 T[l][c]=3;
57 --l;
58 }
59
60 l=Dame[0][i];
61 c=Dame[1][i];
62
63 // directia Nord Est
64 while (l>=c &&(abs)((float)T[l][c])!=1)
65 {
66 T[l][c]=3;
67 --l;
68 ++c;
69 }
70
71 l=Dame[0][i];
72 c=Dame[1][i];
73
74 // directia Est
75 while (l>=c && (abs)((float)T[l][c])!=1)
76 {
77 T[l][c]=3;c++;
78 }
79
80 l=Dame[0][i];
81 c=Dame[1][i];
82
83 // directia Sud Est
84 while ((abs)((float)T[l][c])!=1)
85 {
86
87 T[l][c]=3;
88 l++;
89 c++;
90 }
91
92 l=Dame[0][i];
93 c=Dame[1][i];
94
95 // directia Sud
96 while ((abs)((float)T[l][c])!=1)
97 {
98 T[l][c]=3;
99 l++;
100 }
101
102 l=Dame[0][i];
103 c=Dame[1][i];
104
105 // directia Sud Vest
106 while ( (abs)((float)T[l][c])!=1)
107 {
108 T[l][c]=3;
109 ++l;
110 --c;
111 }
CAPITOLUL 7. OJI 2013 128
112
113 l=Dame[0][i];
114 c=Dame[1][i];
115
116 // directia Vest
117 while ((abs)((float)T[l][c])!=1)
118 {
119 T[l][c]=3;
120 --c;
121 }
122
123 l=Dame[0][i];
124 c=Dame[1][i];
125
126 // directia Nord Vest
127 while ((abs)((float)T[l][c])!=1)
128 {
129 T[l][c]=3;
130 --c;
131 --l;
132 }
133
134 l=Dame[0][i];
135 c=Dame[1][i];
136 T[l][c]=1;
137 }
138
139 for(i=1;i<=N;i++)
140 for(j=1;j<=i;j++)
141 if(T[i][j]==3) P++;
142
143 P+=(T[i][j]==3);
144
145 fprintf(g,"%d\n%d\n",M,P);
146
147 fclose(f);
148 fclose(g);
149 return 0;
150 }
110 {
111 if (a[l][c]==0)
112 {
113 ++atacate; // se numara orice camp nenumarat
114 a[l][c]=1; //
115 }
116 ++l;
117 }
118
119 l=d[0][i];
120 c=d[1][i];
121
122 // directia oblic stanga-jos
123 while (l<=N && c>0 && a[l][c]!=-1)
124 {
125 if (a[l][c]==0)
126 {
127 ++atacate; // se numara orice camp nenumarat
128 a[l][c]=1; //
129 }
130 ++l;
131 --c;
132 }
133
134 l=d[0][i];
135 c=d[1][i];
136
137 // directia orizontala-dreapta
138 while (c>0 && a[l][c]!=-1)
139 {
140 if (a[l][c]==0)
141 {
142 ++atacate; // se numara orice camp nenumarat
143 a[l][c]=1; //
144 }
145 --c;
146 }
147
148 l=d[0][i];
149 c=d[1][i];
150
151 // directia oblic-stanga-sus
152 while (c>0 && a[l][c]!=-1)
153 {
154 if (a[l][c]==0)
155 {
156 ++atacate; // se numara orice camp nenumarat
157 a[l][c]=1; //
158 }
159 --c;
160 --l;
161 }
162 }
163
164 fout <<maxalbe<<endl<<atacate<< endl;
165
166 fin.close();
167 fout.close();
168 return 0;
169 }
7.2 clepsidru
Problema 2 - clepsidru 100 de puncte
Date de intrare
Prima linie a ³ierului de intrare clepsidru.in conµine dou numere naturale nenule n ³i b,
separate printr-un singur spaµiu, cu semnicaµia din enunµ; a doua linie conµine num rul natural
nenul k având semnicaµia din enunµ, iar urm toarele k linii conµin ecare câte o pereche de valori
si ³i pi , 1 & i & k , separate printr-un singur spaµiu, cu semnicaµia din enunµ.
Date de ie³ire
Fi³ierul de ie³ire clepsidru.out va conµine pe prima linie un num r natural ce reprezint
valoarea obµinut la primul experiment, iar pe urm toarele n linii va conµine câte o pereche de
numere naturale, separate printr-un singur spaµiu, ce reprezint cantit µile de boabe de nisip din
incintele de sus ³i de jos ale celor n clepsidre, scrise în ordinea de la 1 la n a clepsidrelor, dup
realizarea celui de-al doilea experiment.
Restricµii ³i preciz ri
a 1 & n & 1000;
a 1 & b & 1000000000;
a 1 & k & 1000;
a 1 & si & 1000, 1 & i & k ;
a pi " 1, 2, 1 & i & k ;
a pentru rezolvarea corect a primei cerinµe se acord 25% din punctaj, iar pentru rezolvarea
corect a celei de-a doua cerinµe se acord 75% din punctaj.
a acordarea punctajului pentru a doua cerinµ se face numai dac în ³ierul de ie³ire exist un
r spuns pentru prima cerinµ , indiferent de corectitudinea acestuia.
CAPITOLUL 7. OJI 2013 132
Exemple
CAPITOLUL 7. OJI 2013 133
Varianta nr. 1
autor prof. Che³c Ciprian - Liceul Tehnologic Costin Neniµescu Buz u
<
Soluµie în O n si - C++
Valoarea cerut de primul experiment, adic dup câte secunde ajung toate boabele de nisip
în incinta de jos a ultimei clepsidre, se determin cu formula n b 1. Justicarea este urm toarea:
la ecare secund câte un bob de nisip cade în clepsidra urm toare, a³adar ultimul bob de nisip
din incinta de sus a primei clepsidre întârzie b 1 secunde pân începe s cad , iar pentru a c dea
are nevoie de n secunde, câte clepsidre sunt.
Pentru a r spunde cerinµei celui de-al doilea experiment, adic pentru a preciza num rul de
boabe de nisip din incintele clepsidrelor, dup cele k a³ez ri consecutive, am f cut o simulare
la nivel de secund . La ecare secund am simulat curgerea boabelor de nisip într-unul sau în
cel lalt sens de curgere, în funcµie de poziµie. La citirea unei noi poziµii am simulat, dac era
cazul, r sturnarea clepsidrului ³i rea³ezarea boabelor de nisip.
Varianta nr. 2
prof. Szabo Zoltan - Inspectoratul ³colar Judeµean Mure³
Dac clepsidra este în starea 2, procedeul este identic, dar cu direcµie invers .
La tip rire vom avea grij s vedem ultima stare a clepsidrului, indc în incintele intermediare
vom avea 0 1 sau 1 0 boabe de nisip.
Varianta nr.3
prof. Rodica Moldovan - C.N. Gheorghe ³incai Baia Mare
2
Soluµie în O k n - C++
Vom lucra într-un vector stare1001, în care vom p stra num rul de boabe din ecare clepsidr
la un moment dat. Iniµializ m staren b;
Vom folosi urm toarele notaµii:
l - nivelul de pe care pornesc boabele,
k - nivelul pe care ajung boabele
s - num r de secunde într-o anumit stare
Pentru ecare pereche citit (secunde poziµie) vom actualiza (vectorul stare) num rul de boabe
din clepsidre (nu la nivel de secund ci funcµie de l, k , s)
La ecare actualizare, num rul de boabe b se iniµializeaz cu num rul de boabe aate în
recipientul de pornire b starel
Se disting urm toarele situaµii:
transformareJos(int l, int k, int s)
a Dac (l 0) && (k 0)
atunci suntem pe nivelul inferior ³i boabele nu coboar , deci poziµia din vectorul stare se va
actualiza cu b
a Dac (l k)
atunci num rul de boabe r mase în recipientul iniµial va max 0, b s;
a Dac (k 0)
atunci num rul de boabe adunate în recipientul inferior va max 0, min b, s l k 1;
a Dac (s $ l k )
atunci timpul este mai mic decât timpul necesar s ajung o boab în recipient ³i vom actualiza
cu 0
a Dac (s ' b l k )
atunci boabele au trecut deja prin recipient ³i vom actualiza cu 0
a Altfel boaba se aa în tranziµie prin recipient ³i vom actualiza cu 1
Varianta nr. 4
prof. Popa Daniel - C.N. Aurel Vlaicu Or ³tie
71 u[j]--;
72 u[j+1]++;
73 }
74 }
75
76 // clepsidru in pozitia 2
77 if (sens==-1)
78 {
79 if (d[1]>0)
80 {
81 d[1]--;
82 u[1]++;
83 }
84
85 for(j=2;j<=n;j++)
86 if (d[j]>0)
87 {
88 d[j]--;
89 d[j-1]++;
90 }
91 }
92
93 }
94
95 sensv=sens;
96 }
97
98 // afisez a doua cerinta
99 for(i=1;i<=n;i++)
100 g<<u[i]<<" "<<d[i]<<"\n";
101
102 f.close();
103 g.close();
104
105 return 0;
106 }
65 return 0;
66 }
147 }
148
149 if (sus>0 && jos==n && stare==2)
150 {
151 c[n][2]=bjos;
152 for(i=sus;i<jos;++i)
153 c[i][2]=1;
154 }
155
156 if (sus>0 && jos<n && stare==1)
157 {
158 for(i=sus+1;i<=jos+1;++i)
159 c[i][1]=1;
160 }
161
162 if (sus>0 && jos<n && stare==2)
163 {
164 for(i=sus;i<=jos;++i)
165 c[i][2]=1;
166 }
167
168 for (i=1;i<=n;++i)
169 fout<<c[i][1]<<" "<<c[i][2]<<"\n";
170
171 fin.close();
172 fout.close();
173
174 return 0;
175 }
Capitolul 8
OJI 2012
8.1 elicop
Problema 1 - elicop 100 de puncte
Un teren de fotbal este folosit pentru aterizarea elicopterelor. Gazonul de pe stadion este
parcelat în p tr µele de aceea³i dimensiune, cu laturile paralele cu marginile terenului. Liniile cu
p tr µele de gazon sunt numerotate de sus în jos cu numerele 1, 2, ..., m, iar coloanele cu p tr µele
de gazon sunt numerotate de la stânga la dreapta cu numerele 1, 2, ..., n.
Din cauza tipului diferit de iarb se ³tie care dintre p tr µele de gazon sunt afectate sau nu
de umbr . Acest lucru este precizat printr-un tablou bidimensional a cu m linii ³i n coloane, cu
elemente 0 ³i 1 (aij 0 înseamn c p tr µelul aat pe linia i ³i coloana j este afectat de umbr ,
iar aij 1 înseamn c p tr µelul aat pe linia i ³i coloana j nu este afectat de umbr ).
Fiecare elicopter are 3 roµi pe care se sprijin . Roµile ec rui elicopter determin un triunghi
dreptunghic isoscel. Elicopterele aterizeaz , astfel încât triunghiurile formate s e cu catetele
paralele cu marginile terenului. în exemplul urm tor avem patru elicoptere.
Pentru a preciza poziµia unui elicopter pe teren este sucient s cunoa³tem linia ³i coloana
v rfurilor ipotenuzei ³i poziµia vârfului deasupra (codicat prin 1) sau dedesubtul ipotenuzei
(codicat prin 1). Pentru exemplu, elicopterul din stânga sus este dat prin 1, 1, 3, 3 ³i 1,
cel din dreapta sus prin 1, 9, 5, 5 ³i 1, cel din stânga jos prin 5, 1, 6, 2 ³i 1, iar cel din
dreapta jos prin 5, 9, 6, 8 ³i 1.
Un elicopter se consider c a aterizat gre³it, dac triunghiul format sub el (denit mai sus)
are mai mult de jum tate din p tr µele afectate de umbr .
Administratorul terenului de fotbal dore³te s determine num rul N 1 de elicoptere, care nu
afecteaz nici un p tr µel din teren ³i numerele de ordine al elicopterelor, care au aterizat gre³it în
ordine cresc toare: e1 , e2 , ..., eN 2 , ³tiind c exist k elicoptere codicate prin numerele 1, 2, ..., k .
Cerinµe
Scrieµi un program care s determine, pentru ³ierul cu datele din enunµ: num rul de elicoptere
N 1, care nu afecteaz nici un p tr µel din teren ³i numerele de ordine al elicopterelor, care au
aterizat gre³it în ordine cresc toare, precedate de num rul lor N 2.
Date de intrare
Prima linie a ³ierului de intrare elicop.in conµine dou numere naturale m ³i n, separate
printr-un spaµiu, cu semnicaµia din enunµ.
142
CAPITOLUL 8. OJI 2012 143
Urm toarele m linii conµin câte n numere 0 sau 1, separate prin câte un spaµiu cu semnicaµia
0 - p tr µel de gazon care este afectat de umbr , respectiv 1 - p tr µel care nu este afectat de
umbr .
Pe linia m 2 se a num rul de elicoptere k , iar pe urm toarele k linii (în ordinea codic rii
lor 1, 2, ..., k ) câte cinci numere separate prin cate un spaµiu, pentru liniile ³i coloanele ipotenuzelor
³i poziµia vârfului (1 sau 1), triunghiurilor dreptunghice asociate elicopterelor:
L1 C1 L2 C2 p
Date de ie³ire
Fi³ierul de ie³ire elicop.out va conµine dou linii: prima linie num rul N 1 de elicoptere, care
nu afecteaz nici un p tr µel din teren, a doua linie cu numerele naturale N 2, e1 , e2 , ..., e N 2
separate prin câte un spaµiu, în ordine cresc toare.
Restricµii ³i preciz ri
a2 & m, n & 100; 1 & k & 40
aNu exist suprapuneri de triunghiuri asociate la dou elicoptere. Triunghiurile asociate
elicopterelor conµin cel puµin trei p tr µele.
a Pentru determinarea corect a valorilor N 1 se obµine 40% din punctajul unui test, iar pentru
determinarea corect a valorilor N 2, e1 , e2 , ..., eN 2 se obµine 60% din punctajul unui test.
Exemple
elicop.in elicop.out Explicaµii
7 9 2 Elicopterele 2 ³i 4 nu afecteaz niciun p tr µel de gazon.
1 1 1 1 1 1 1 1 1 213
0 0 0 0 1 1 1 1 0 Elicopterele 1 ³i 3 afecteaz ecare mai mult de jum tate din
0 0 1 0 1 1 1 0 0 num rul p tr µelelor asociate triunghiurilor dreptunghice ³i
1 1 1 0 1 1 0 1 1 deci aterizeaz gre³it. Elicopterul 1 face umbr la 6 p tr µele,
0 0 1 1 1 1 0 1 1 din care afectate sunt 4.
1 1 1 1 1 1 0 1 1
1 1 1 1 1 1 0 0 1 Elicopterul 3 face umbr la 3 p tr µele, din care afectate sunt
4 dou .
1 1 3 3 -1
1 9 5 5 1
5 1 6 2 1
5 9 6 8 1
Pentru tabloul a cu elementele ai, j , 1 & i & m, 1 & j & n, un elicopter dat prin L1, C1, L2, C2
³i p poate avea în una din poziµiile:
43 f>>k;
44
45 for(i=1;i<=k;i++)
46 {
47 f>>x1>>y1>>x2>>y2>>v;
48
49 d=(x2-x1)*(y2-y1);
50
51 if (d>0&&v==-1) tip=1;
52 if (d>0&&v==1) tip=2;
53 if (d<0&&v==1) tip=3;
54 if (d<0&&v==-1) tip=4;
55
56 pg=0;
57 switch (tip)
58 {
59 case 1 :{
60 for(l=1;l<=max(x1,x2)-min(x1,x2)+1;l++)
61 for(c=1;c<=l;c++)
62 if (t[l+min(x1,x2)-1][c+min(y1,y2)-1]==0)
63 pg++;
64 break;
65 }
66 case 2 :{
67 for(l=1;l<=max(x1,x2)-min(x1,x2)+1;l++)
68 for(c=l;c<=max(y1,y2)-min(y1,y2)+1;c++)
69 if (t[l+min(x1,x2)-1][c+min(y1,y2)-1]==0)
70 pg++;
71 break;
72 }
73 case 3 :{
74 for(l=1;l<=max(x1,x2)-min(x1,x2)+1;l++)
75 for(c=1;c<=modul(x2-x1)+2-l;c++)
76 if (t[l+min(x1,x2)-1][c+min(y1,y2)-1]==0)
77 pg++;
78 break;
79 }
80 case 4 :{
81 for(l=1;l<=max(x1,x2)-min(x1,x2)+1;l++)
82 for(c=modul(x2-x1)+2-l;
83 c<=max(y1,y2)-min(y1,y2)+1;
84 c++)
85 if (t[l+min(x1,x2)-1][c+min(y1,y2)-1]==0)
86 pg++;
87 break;
88 }
89 }
90
91 if (pg==0)
92 ne++;
93 else
94 if (pg>(modul(x2-x1)+1)*(modul(x2-x1)+2)/4)
95 sol[++sol[0]]=i;
96 }
97
98 g<<ne<<"\n";
99 g<<sol[0]<<" ";
100 for(i=1;i<=sol[0];i++)
101 g<<sol[i]<<" ";
102
103 f.close();
104 g.close();
105 return 0;
106 }
9
10 int a[110][110],m,n,i,j,k,tip[1000],
11 L1[1000],C1[1000],L2[1000],C2[1000],N1,p[1000],np,temp,t;
12
13 void interschimba(int &i, int &j)
14 {
15 int aux;
16 aux=i;
17 i=j;
18 j=aux;
19 }
20
21 //-------------------------
22 int triunghicu1(int i)
23 {
24 int L11,L22,C11,C22,t,aux,p,q,no=0;
25
26 L11=L1[i];
27 L22=L2[i];
28 C11=C1[i];
29 C22=C2[i];
30 t=tip[i];
31
32 if(L11>L22)
33 {
34 aux=L11;
35 L11=L22;
36 L22=aux;
37 aux=C11;
38 C11=C22;
39 C22=aux;
40 }
41
42 if(C11>C22)
43 if(t==1)
44 {
45 aux=0;
46 for(p=L11;p<=L22;p++)
47 {
48 for(q=C22;q<=C11-aux;q++)
49 if(a[p][q]==1)
50 no++;
51 aux++;
52 }
53 }
54 else
55 {
56 aux=0;
57 for(p=L22;p>=L11;p--)
58 {
59 for(q=C22+aux;q<=C11;q++)
60 if(a[p][q]==1)
61 no++;
62 aux++;
63 }
64 }
65
66 if(C11<C22)
67 if(t==1)
68 {
69 aux=0;
70 for(p=L11;p<=L22;p++)
71 {
72 for(q=C11+aux;q<=C22;q++)
73 if(a[p][q]==1)
74 no++;
75 aux++;
76 }
77 }
78 else
79 {
80 aux=0;
81 for(p=L11;p<=L22;p++)
82 {
83 for(q=C11;q<=C11+aux;q++)
84 if(a[p][q]==1)
CAPITOLUL 8. OJI 2012 147
85 no++;
86 aux++;
87 }
88 }
89
90 return no;
91 }
92
93 //---------------------
94
95 void afis()
96 {
97 int i;
98 fout<<N1<<"\n"<<np<<" ";
99 for(i=1;i<=np;i++)
100 fout<<p[i]<<" ";
101 fout.close();
102 }
103
104 int main()
105 {
106 fin>>m>>n;
107
108 for(i=1;i<=m;i++)
109 for(j=1;j<=n;j++)
110 fin>>a[i][j];
111 fin>>k;
112
113 for(i=1;i<=k;i++)
114 fin>>L1[i]>>C1[i]>>L2[i]>>C2[i]>>tip[i];
115
116 fin.close();
117
118 np=0;
119 for(i=1;i<=k;i++)
120 {
121 t=triunghicu1(i);
122 //cout<<"Q "<<t<<"\n";
123
124 temp=abs(L1[i]-L2[i]);
125 temp=(temp+1)*(temp+2)/2;
126 //cout<<"*"<<L1[i]<<" "<<L2[i]<<" "<<temp<<"\n";
127
128 if(t==temp)
129 N1++;
130 if(t<temp/2.0)
131 {
132 np++;
133 p[np]=i;
134 }
135 }
136
137 afis();
138 return 0;
139 }
18
19 fscanf(f,"%d",&k);
20
21 for(int i=1;i<=k;i++)
22 fscanf(f,"%d%d%d%d%d",&Elicop[i][1],&Elicop[i][2],
23 &Elicop[i][3],&Elicop[i][4],&Elicop[i][0]);
24 fclose(f);
25 }
26
27 int main()
28 {
29 f=fopen("elicop.in","r");
30 g=fopen("elicop.out","w");
31
32 nre=0;
33 citire();
34 int nr1;
35
36 for(int i=1;i<=k;i++)
37 {
38 if((Elicop[i][3]-Elicop[i][1])*(Elicop[i][4]-Elicop[i][2])>0 &&
39 Elicop[i][0]==-1)
40 Caz=1;
41 else
42 if((Elicop[i][3]-Elicop[i][1])*(Elicop[i][4]-Elicop[i][2])>0 &&
43 Elicop[i][0]==1)
44 Caz=2;
45 else
46 if((Elicop[i][3]-Elicop[i][1])*(Elicop[i][4]-Elicop[i][2])<0&&
47 Elicop[i][0]==-1)
48 Caz=3;
49 else
50 Caz=4;
51 nr1=0;
52
53 int J=max(Elicop[i][1],Elicop[i][3])-min(Elicop[i][1],Elicop[i][3])+1;
54 int Lx1=min(Elicop[i][1],Elicop[i][3]);
55 int Ly1=min(Elicop[i][2],Elicop[i][4]);
56 int Ly2=max(Elicop[i][2],Elicop[i][4]);
57
58 switch(Caz)
59 {
60 case 1: {
61 for(int j=1;j<=J;j++)
62 for(int l=1;l<=j;l++)
63 nr1+=!(Teren[j+Lx1-1][l+Ly1-1]);
64 break;
65 }
66 case 2: {
67 for(int j=1;j<=J;j++)
68 for(int l=j;l<=Ly2-Ly1+1;l++)
69 nr1+=!(Teren[j+Lx1-1][l+Ly1-1]);
70 break;
71 }
72 case 3: {
73 for(int j=1;j<=J;j++)
74 for(int l=(int)abs(Elicop[i][1]-Elicop[i][3])+2-j;
75 l<=Ly2-Ly1+1;
76 l++)
77 nr1+=!(Teren[j+Lx1-1][l+Ly1-1]);
78 break;
79 }
80 case 4: {
81 for(int j=1;j<=J;j++)
82 for(int l=1;
83 l<=(int)abs(Elicop[i][1]-Elicop[i][3])+2-j;
84 l++)
85 nr1+=!(Teren[j+Lx1-1][l+Ly1-1]);
86 break;
87 }
88 }
89
90 nre+=!nr1;
91 if(nr1 > (abs(Elicop[i][1]-Elicop[i][3])+1)*
92 (abs(Elicop[i][1]-Elicop[i][3])+2)/4)
93 E_Sol[++nr_umbra]=i;
CAPITOLUL 8. OJI 2012 149
94 }
95
96 fprintf(g,"%d\n%d ",nre,nr_umbra);
97
98 for(int i=1;i<=nr_umbra;i++)
99 fprintf(g,"%d ",E_Sol[i]);
100
101 fclose(g);
102 return 0;
103 }
8.2 roata
Problema 2 - roata 90 de puncte
Una dintre atracµiile celebrului parc de distracµii Prater din Viena este
Marea Roat Vienez . Din ea se poate admira priveli³tea întregii Viene.
Roata are n cabine, numerotate de la 1 la n în sens orar ³i dispuse simetric
pe circumferinµa roµii. îmbarcarea clienµilor se face în cabina în care roata
este tangent cu solul, iar rotirea începe cu cabina 1 aat în poziµia de
îmbarcare ³i se face în sens antiorar. Un client pl te³te pentru o rotire 1
EUR ³i poate cump ra un num r oarecare de rotiri. Figura 8.2: roata
Cei p clienµi care doresc utilizarea roµii trebuie s respecte urm toarea procedur : clientul cu
num rul de ordine i î³i cump r un bilet pe care sunt înscrise num rul s u de ordine ³i num rul
de rotiri ci, 1 & i & p, apoi se a³eaz la rând. Când în poziµia de îmbarcare este o cabin liber
sau se elibereaz o cabin , roata se opre³te ³i urc urm torul clientul. Un client coboar dup ce
se efectueaz num rul de rotiri înscris pe bilet.
Cerinµe
S se scrie un program care, cunoscând num rul n de cabine al roµii, num rul p de clienµi,
precum ³i num rul de rotiri cump rate de ecare client, ci , 1 & i & p, s calculeze:
a suma total încasat de administratorul roµii de la clienµi;
a ordinea în care coboar clienµii din roat ;
a num rul cabinei din care coboar ultimul client.
Date de intrare
Fi³ierul de intrare roata.in conµine pe primul rând num rul natural n, pe al doilea rând
num rul natural p iar pe al treilea rând numerele naturale ci , 1 & i & p, separate printr-un spaµiu,
cu semnicaµiile de mai sus.
Date de ie³ire
Fi³ierul de ie³ire roata.out va conµine pe prima linie suma total încasat , pe a doua linie
numerele de ordine ale clienµilor, în ordinea coborârii, separate printr-un spaµiu, iar pe a treia linie
num rul cabinei din care va coborî ultimul client.
Restricµii ³i preciz ri
a2 & n & 360
a1 & p & 100000
a 1 & ci & 100000
a pentru rezolvarea primei cerinµe se acord 20% din punctaj, iar pentru celelalte dou cerinµe
se acord câte 40% din punctaj ecare.
Exemple
roata.in roata.out Explicaµii
CAPITOLUL 8. OJI 2012 150
În cazul în care n ' p se încarc num rul de rotiri într-un vector ³i se determin suma total
încasat ca ind suma valorilor din vector, apoi se determin poziµia maximului dintre elementele
vectorului, care reprezint cabina din care va coborî ultimul client.
Pentru a determina ordinea în care coboar clienµii, se determin poziµia minimul dintre valorile
vectorului ³i se a³eaz , apoi se elimin acest minim ³i se reia operaµia anterioar .
În cazul în care n $ p se încarc într-un vector c i 1 & i & p num rul de rotiri ³i se iniµializeaz
un vector cu num rul de ordine al clienµilor o i 1 & i & n.
Se calculeaz ³i se a³eaz suma total încasat ca ind suma valorilor din vector.
Considerând c primii n clienµi sunt urcaµi în roat , pentru restul clienµilor cu numere de
ordine de la n 1 la p se procedeaz astfel :
- se determin poziµia minimului dintre primele n valori ale vectorului c i ³i se a³eaz num rul
de ordine al acestuia;
- se încarc un nou client în roat ad ugând pe poziµia minimului calculat precedent datele
noului client (num rul de rotiri ³i num rul s u de ordine);
De remarcat c dup ce a fost calculat poziµia unui minim, pentru a-l elimina, e sucient s
adun m pe poziµia acestuia num rul de rotiri ale urm torului client ³i s atribuim vectorului de
ordine num rul de ordine al clientului; aceast metod evit înc o parcurgerea a vectorului c i
în vederea prelucr rii informaµiilor clienµilor la o coborare, îns are dezavantajul c prin adun ri
repetate se poate ajunge la valori mari care trebuie gestionate cu tipuri de date corect alese.
- dup prelucrarea tuturor clienµilor cu numerele de ordine de la n 1 la p se intr pe secvenµa
descris în cazul n ' p.
Varianta 2
prof. Florentina Ungureanu - Colegiul Naµional de Informatic Piatra Neamµ
Vectorul roata reµine în poziµia i num rul de ordine al clientului din cabina i, respectiv p+1
dac aceast cabin este liber . (Iniµializat cu 1, 2, ..., n pentru n & p, respectiv 1, 2, ..., p, p 1, p
1, ...).
Vectorul ture conµine pentru început num rul de ture pl tite de ecare client, dar va actuali-
zat indicând la nal, pentru ecare client, num rul total de ture f cute de roat pân la momentul
coborârii acestuia.
Rezolvare:
1. Suma valorilor de pe a treia linie a ³ierului furnizeaz prima valoare cerut .
2. Determinarea ordinii coborârii:
Etapa I coboar -urc (n $ p):
a. Pentru ecare client i (i % n) r mas în a³teptare se determin num rul de ordine k al cabinei
care se elibereaz - cea al c rei client are num r minim de ture pân la coborâre ³i se a³eaz
num rul de ordine al clientului.
CAPITOLUL 8. OJI 2012 151
b. Clientul i urc în cabina k , iar num rul de ture pl tit de acesta se actualizeaz devenind
egal cu num rul total de ture f cute de roat pân când acest client va coborî.
Etapa II coboar :
a. Se determin num rul de ordine k al cabinei care se elibereaz - cea al c rei client are num r
minim de ture pân la coborâre.
b. Dac num rul de ture corespunz tor este mai mic decât inf (mai exist clienµi în roat ):
a se a³eaz num rul de ordine al clientului;
a se completeaz cabina k cu valoarea p 1 - (cabin goal );
a se reia pasul a.
c. Când nu mai sunt clienµi în roat se a³eaz num rul cabinei din care a coborât ultimul
client.
51 for(i=1;i<=n;i++)
52 c[i]-=10000000;
53
54 c[pozmin]+=c[k]; // o mica smecherie - in loc sa scad
55 // din toate minimul, am adunat
56 o[pozmin]=k;
57 }
58 else
59 n=p;
60
61 // determin numarul cabinei din care va cobora ultimul client
62 pozmax=1;
63 for(i=2;i<=n;i++)
64 if (c[i]>=c[pozmax])
65 pozmax=i;
66
67 for(k=1;k<=n;k++)
68 {
69 // determin clientul care urmeaza sa coboare
70 pozmin=1;
71 for(i=2;i<=n;i++)
72 if (c[i]<c[pozmin]) pozmin=i;
73
74 // afisez ordinea la coborare
75 g<<o[pozmin]<<" ";
76
77 c[pozmin]+=100001;
78 }
79
80 // afisez numarul cabinei din care va cobora ultimul client
81 g<<"\n"<<pozmax<<"\n";
82
83 f.close();
84 g.close();
85 return 0;
86 }
113 g.close();
114 }
Capitolul 9
OJI 2011
9.1 vase
Problema 1 - vase 100 de puncte
Speciali³tii chimi³ti au reu³it crearea în laborator a unei game diversicate
de substanµe lichide nemiscibile (care nu se amestec între ele), de aceea³i
densitate ³i de culori diferite.
Acest rezultat a fost utilizat de c tre speciali³tii zicieni pentru studiul
principiului vaselor comunicante. Conform acestui principiu într-un sistem de
vase comunicante nivelul lichidului este acela³i, indiferent de forma vaselor.
Experimentele zicienilor se desf ³oar astfel: Figura 9.1: vase
Într-un sistem cu dou vase comunicante, gradat identic pe ecare ramur
cu 0, 1, 2, 3, ..., zicienii introduc un num r de n lichide, pe ramura din stânga sau pe ramura din
dreapta. Volumele introduse din ecare lichid, notate cu Vi (1 & i & n), sunt numere naturale
nenule pare astfel încât, la echilibru, orice lichid se va a³eza între dou gradaµii de aceea³i parte a
unei ramuri sau pe cele dou ramuri ale sistemului de vase comunicante. Lichidele sunt identicate
prin intermediul culorii acestora, culori numerotate cu 1, 2, 3, ..., n.
Introducerea lichidelor în sistemul cu dou vase comunicante se face în ordinea cresc toare a
numerelor culorilor, începând cu lichidul de culoare 1.
Scopul experimentului este de a determina gradaµia maxim
la care se ridic lichidele în sistemul cu dou vase comunicante,
precum ³i între ce gradaµii se g se³te un lichid de culoare x, dintre
cele introduse.
De exemplu, dac în sistemul cu dou vase comunicante se
introduc n 3 lichide în ordinea: V1 4 lichid de culoare 1
introdus prin ramura din dreapta (operaµie codicat 4D), V2
4 lichid de culoare 2 introdus prin ramura din stânga (operaµie
codicat 4S ) ³i V3 2 lichid de culoare 3 introdus prin ramura
din stânga (operaµie codicat 2S ) atunci gradaµia maxim la care
se ridic nivelul lichidelor în sistemul cu dou vase comunicante
este 5, iar lichidul de culoare x 2 se g se³te între gradaµiile: 3 pe
ramura din stânga 3S ³i 1 pe ramura din dreapta 1D, conform
gurii al turate.
Date de intrare
Prima linie a ³ierului de intrare vase.in conµine un singur num r natural nenul n, cu sem-
nicaµia de mai sus. Fiecare linie, din urm toarele n, conµine câte dou valori separate printr-un
spaµiu: un num r natural nenul par ³i o liter mare, S sau D, reprezentând volumul introdus
155
CAPITOLUL 9. OJI 2011 156
din lichidul de culoare i, respectiv ramura (S pentru ramura din stânga ³i D pentru ramura din
dreapta) prin care se face introducerea acestuia. Linia n 2 a ³ierului de intrare conµine un
singur num r nenul x ce reprezint culoarea lichidului c utat.
Date de ie³ire
Fi³ierul de ie³ire vase.out va conµine pe prima linie un num r natural nenul ce reprezint gra-
daµia maxim la care se ridic lichidele în sistemul de vase comunicante la echilibru. Urm toarele
dou linii vor conµine ecare câte dou valori separate printr-un spaµiu: un num r natural ³i o
liter mare (S sau D), reprezentând gradaµia ³i ramura între care se a³eaz lichidul c utat.
Restricµii ³i preciz ri
a 1 & x & n & 100000
a 2 & V i & 100000 pentru 1 & i & n
a sistemul de vase este gradat în acelea³i unit µi de m sur în care sunt exprimate volumele
de lichid;
a dac lichidul c utat, de culoare x, se a³eaz pe aceea³i ramur se va a³a întâi gradaµia
superioar ³i apoi cea inferioar ;
a dac lichidul c utat, de culoare x, se a³eaz pe ramuri diferite se va a³a întâi gradaµia de
pe ramura din stânga ³i apoi cea de pe ramura din dreapta;
a dac una dintre gradaµiile între care se situeaz lichidul c utat, de culoare x, este 0 atunci
se consider c aceast gradaµie se g se³te pe aceea³i ramur cu cealalt gradaµie;
a pentru rezolvarea primei cerinµe se acord 20% din punctaj, iar pentru a doua cerinµ 80%
din punctaj.
Exemple
vase.in vase.out Explicaµii
3 5 Se introduc 3 lichide în sistemul de dou vase comunicante:
4D 3S - primul cu volumul 4, se introduce prin dreapta ³i are culoarea 1;
4S 1D - al doilea cu volumul 4, se introduce prin stânga ³i are culoarea 2;
2S - al treilea cu volumul 2, se introduce prin stânga ³i are culoarea 3;
2 Se caut gradaµiile ce corespund lichidului de culoare 2.
Gradaµia maxim la care ajunge nivelul lichidului este 5.
Lichidul de culoare 2 se a³eaz între gradaµiile 3 pe ramura din stânga
³i 1 pe ramura din dreapta.
O prim abordare a problemei pleac de la ideea c înc de la citirea datelor despre lichidele
introduse în sistemul de vase comunicante se face separarea acelora introduse pe ramura stâng faµ
de cele introduse pe ramura dreapt în dou structuri de date identice (tablouri unidimensionale),
câte un tablou pentru volume ³i respectiv culoare. În acela³i timp se calculeaz suma tuturor
volumelor în vederea determin rii echilibrului ³i deci a gradaµiei maxime la care se ridic lichidele.
Pentru rezolvarea celei de-a doua cerinµe se face o c utare secvenµial în funcµie de culoare pe
cele dou ramuri, actualizând în permanenµ gradaµiile între care se g se³te lichidul curent. Se
analizeaz cu atenµie a³area în ³ierul de ie³ire a rezultatelor, în funcµie de preciz rile problemei
referitoare la modul de a³are (întâi gradaµia superioar ³i apoi cea inferioar , înt i ramura stâng
³i apoi cea dreapt , s.a.m.d.)
Aceast abordare necesit îns mai mult memorie deoarece se reµine ³i culoarea lichidului
introdus, întrucât s-a facut separarea pe ramuri a lichidelor.
O a doua abordare a problemei se poate face prin preluarea datelelor despre lichidele introduse
în ordinea culorilor (a citirii datelor), adic în dou tablouri unidimensionale (unul pentru volume
³i altul pentru ramur ) de la 1 la n.
CAPITOLUL 9. OJI 2011 157
Apoi se calculeaz nivelul la care se ajunge pân la lichidul c utat, se determin intervalul
iniµial al lichidului c utat ³i se actualizeaz intervalul ocupat de lichidul c utat, în funcµie de
direcµia curent pentru lichidele care au mai r mas de ad ugat.
Aceast soluµie necesit mai puµin memorie deoarece memorarea culorilor s-a f cut natural
prin indicele vectorilor utilizaµi.
58 return 0;
59 }
71 if(es>-1)
72 if(ns<echi)
73 {
74 dif=echi-ns;
75 ss+=dif;
76 fin=ss+s[es][1];
77 g<<fin<<" S"<<endl<<ss<<" S";
78 }
79 else
80 {
81 dif=-echi+ns;
82 ss-=dif;
83 fin=ss+s[es][1];
84 if (ss<0)
85 if(fin==0)
86 g<<-ss<<" D"<<endl<<0<<" D";
87 else
88 if(fin<0)
89 {
90 fin=-fin;
91 ss=-ss;
92 if(fin>ss)
93 g<<fin<<" D"<<endl<<ss<<" D";
94 else
95 g<<ss<<" D"<<endl<<fin<<" D";
96 }
97 else
98 g<<fin<<" S"<<endl<<-ss<<" D";
99 else
100 g<<fin<<" S"<<endl<<ss<<" S";
101 }
102 else
103 if(nd<echi)
104 {
105 dif=echi-nd;
106 sd+=dif;
107 fin=sd+d[ed][1];
108 g<<fin<<" D"<<endl<<sd<<" D";
109 }
110 else
111 {
112 dif=-echi+nd;
113 sd-=dif;
114 fin=sd+d[ed][1];
115 if (sd<0)
116 if(fin<=0)
117 g<<-sd<<" S"<<endl<<-fin<<" S";
118 else
119 g<<-sd<<" S"<<endl<<fin<<" D";
120 else
121 g<<fin<<" D"<<endl<<sd<<" D";
122 }
123
124 return 0;
125 }
18 ifstream f("vase.in");
19 ofstream g("vase.out");
20
21 int main()
22 {
23 long long i,n,x,z,mij,l1=0,l2=0,h1,h2,gasit,s=0;
24 char c,l1r=’ ’,l2r=’ ’;
25
26 f>>n;
27
28 // citesc datele sub forma a 2 stive st si dr si calculez suma totala
29 for(i=1;i<=n;i++)
30 {
31 f>>x>>c;
32 s+=x;
33 switch (c)
34 {
35 case ’S’:
36 st[++vst].cant=x;
37 st[vst].ram=c;
38 st[vst].cul=i;
39 break;
40 case ’D’:
41 dr[++vdr].cant=x;
42 dr[vdr].ram=c;
43 dr[vdr].cul=i;
44 break;
45 }
46 }
47
48 // culoarea pe care o caut
49 f>>z;
50
51 //calculez punctul de echilibru
52 mij=s/2;
53
54 h1=mij;
55 gasit=0;
56 while(h1>-mij&&vst>0&&!gasit)
57 {
58 if (st[vst].cul==z)
59 {
60 if (h1<0)
61 {
62 l1=-h1;
63 l1r=’D’;
64 }
65 else
66 { l1=h1;
67 l1r=’S’;
68 }
69
70 if (h1-st[vst].cant<0)
71 {
72 l2=-(h1-st[vst].cant);
73 l2r=’D’;
74 }
75 else
76 {
77 l2=h1-st[vst].cant;
78 l2r=’S’;
79 }
80
81 gasit=1;
82 }
83
84 h1-=st[vst--].cant;
85 }
86
87 h2=mij;
88 while(h2>-mij&&vdr>0&&!gasit)
89 {
90 if (dr[vdr].cul==z)
91 {
92 if (h2<0)
93 {
CAPITOLUL 9. OJI 2011 161
94 l1=-h2;
95 l1r=’S’;
96 }
97 else
98 {
99 l1=h2;
100 l1r=’D’;
101 }
102
103 if (h2-dr[vdr].cant<0)
104 {
105 l2=-(h2-dr[vdr].cant);
106 l2r=’S’;
107 }
108 else
109 {
110 l2=h2-dr[vdr].cant;
111 l2r=’D’;
112 }
113
114 gasit=1;
115 }
116
117 h2-=dr[vdr--].cant;
118 }
119
120 if (l1==0) l1r=l2r;
121 if (l2==0) l2r=l1r;
122
123 // scriu rezultatele in fisier
124 g<<mij<<"\n";
125 if (l1r==’D’&&l2r==’S’)
126 {
127 g<<l2<<" "<<l2r<<"\n";
128 g<<l1<<" "<<l1r<<"\n";
129 }
130 else
131 if (l1r==’S’&&l2r==’D’)
132 {
133 g<<l1<<" "<<l1r<<"\n";
134 g<<l2<<" "<<l2r<<"\n";
135 }
136 else
137 if (l1>l2)
138 {
139 g<<l1<<" "<<l1r<<"\n";
140 g<<l2<<" "<<l2r<<"\n";
141 }
142 else
143 {
144 g<<l2<<" "<<l2r<<"\n";
145 g<<l1<<" "<<l1r<<"\n";
146 }
147
148 f.close();
149 g.close();
150 return 0;
151 }
9.2 cri
Problema 2 - cri 100 de puncte
Furnicuµa ³i-a construit un depozit pentru gr unµe pe o suprafaµ de teren dreptunghiular
³i l-a compartimentat în N M camere identice, de form p tratic , dispuse câte M pe direcµia
Ox ³i câte N pe direcµia Oy . Din ecare camer se poate intra în orice camer învecinat cu ea
(camer care are un perete comun cu aceasta).
În ecare camer , identicat prin coordonatele sale, ca în
desenul al turat în care N 5 ³i M 4, furnica a depozitat
o cantitate de gr unµe. De exemplu, în camera de coordonate
I, J este depozitat cantitatea CIJ de gr unµe.
CAPITOLUL 9. OJI 2011 162
Exemple
CAPITOLUL 9. OJI 2011 163
Cazul I
Dac X ³i Y sunt ambele numere pare, atunci num rul de camere prin care va trece Cri este
egal cu X Y 1. Dac ar trece prin toate camerele, el nu ar mai putea s ias din zon f r s
treac de dou ori printr-o camer , lucru nepermis.
Fie Ai0j0 cea mai mic valoare din matricea A cu proprietatea c suma indicilor i0 j0 este
un num r impar. Atunci, Cri nu va trece prin camera de coordonate X i0 1, Y j0 1 iar
cantitatea total maxim de gr unµe pe care Cri poate s-o fure în acest caz este egal cu S Ai0j0 .
Cazul al II-lea
Dac X este impar sau Y este impar, sau ambele sunt impare, atunci num rul de camere prin
care va trece Cri este egal cu X Y . Astfel, cantitatea total maxim de gr unµe pe care Cri
poate s-o fure în acest caz este egal cu S .
Se procedeaz analog pentru celelalte trei zone, ³i apoi se alege zona pentru care se obµine
cantitatea total maxim de gr unµe prin traversarea unui num r minim de camere.
Implementarea soluµiei se poate realiza prin utilizarea unui tablou bidimensional ce memoreaz
cantit µile de gr unµe (sursele: cripas1.pas, cricpp1.cpp) sau se poate realiza f r tablouri (sursele:
cripas2.pas, cricpp2.cpp, cricpp3.cpp).
Complexitatea soluµiei propuse este O N M
Pentru exemplul dat în enunµul problemei, traseul pe care l-ar putea str bate Cri în ecare
zon este:
CAPITOLUL 9. OJI 2011 164
45 min3=a;
46 }
47
48 if((i>=i0)&&(j>=j0))
49 {
50 s4+=a;
51 if((i-i0+j-j0)%2!=0)
52 if(min4>a)
53 min4=a;
54 }
55 }
56
57 k1=i0*j0;
58 k2=i0*(m-j0+1);
59 k3=(n-i0+1)*j0;
60 k4=(n-i0+1)*(m-j0+1);
61
62 if((i0%2==0)&&(j0%2==0))
63 {
64 k1--;
65 s1=s1-min1;
66 }
67
68 if((i0%2==0)&&((m-j0+1)%2==0))
69 {
70 k2--;
71 s2=s2-min2;
72 }
73
74 if(((n-i0+1)%2==0)&&(j0%2==0))
75 {
76 k3--;
77 s3=s3-min3;
78 }
79
80 if(((n-i0+1)%2==0)&&((m-j0+1)%2==0))
81 {
82 k4--;
83 s4=s4-min4;
84 }
85
86 if(s2>s1)
87 {
88 ies=2;
89 k1=k2;s1=s2;
90 }
91 else
92 if((s2==s1)&&(k1>k2))
93 {
94 ies=2;
95 k1=k2;
96 }
97
98 if(s3>s1)
99 {
100 ies=3;
101 k1=k3;
102 s1=s3;
103 }
104 else
105 if((s3==s1)&&(k1>k3))
106 {
107 ies=3;
108 k1=k3;
109 }
110
111 if(s4>s1)
112 {
113 ies=4;
114 k1=k4;
115 s1=s4;
116 }
117 else
118 if((s4==s1)&&(k1>k4))
119 {
120 ies=4;
CAPITOLUL 9. OJI 2011 166
121 k1=k4;
122 }
123
124 g<<ies<<’ ’<<s1<<’ ’<<k1;
125
126 g.close();
127 return 0;
128 }
65 nr=nb*mb;
66 if(mb%2==0 && nb%2==0)
67 {
68 nr=nr-1;
69 s=s-min;
70 }
71
72 return s;
73 }
74
75 int zona3( int &nr)
76 {
77 int i,j,s=0,min=2000000000;
78
79 nb=0;
80 for(i=x; i<=n;i++)
81 {
82 nb++;
83 mb=0;
84 for(j=y;j>=1;j--)
85 {
86 mb++;
87 s=s+a[i][j];
88 if(((nb+mb)%2!=0)&&(a[i][j]<min))
89 min=a[i][j];
90 }
91 }
92
93 nr=nb*mb;
94 if(mb%2==0 && nb%2==0)
95 {
96 nr=nr-1;
97 s=s-min;
98 }
99
100 return s;
101 }
102
103 int zona4( int &nr)
104 {
105 int i,j,s=0,min=2000000000;nb=0;
106
107 for(i=x; i<=n;i++)
108 {
109 nb++;
110 mb=0;
111 for(j=y;j<=m;j++)
112 {
113 mb++;
114 s=s+a[i][j];
115 if(((nb+mb)%2!=0)&&(a[i][j]<min))
116 min=a[i][j];
117 }
118 }
119
120 nr=nb*mb;
121 if((mb%2==0) && (nb%2==0))
122 {
123 nr--;
124 s=s-min;
125 }
126
127 return s;
128 }
129
130 int main()
131 {
132 int nr,s,k=0,smax=0,ies;
133
134 citire();
135
136 smax=zona1(k);
137 ies=1;
138 s=zona2(nr);
139 if(s>smax)
140 {
CAPITOLUL 9. OJI 2011 168
141 smax=s;
142 k=nr;ies=2;
143 }
144 else
145 if(s==smax)
146 if(nr<k)
147 {
148 k=nr;
149 ies=2;
150 }
151
152 s=zona3(nr);
153 if(s>smax)
154 {
155 smax=s;
156 k=nr;ies=3;
157 }
158 else
159 if(s==smax)
160 if(nr<k)
161 {
162 k=nr;
163 ies=3;
164 }
165
166 s=zona4(nr);
167 if(s>smax)
168 {
169 smax=s;
170 k=nr;ies=4;
171 }
172 else
173 if(s==smax)
174 if(nr<k)
175 {
176 k=nr;
177 ies=4;
178 }
179
180 freopen("cri.out","w",stdout);
181 printf("%d %d %d",ies,smax,k);
182 return 0;
183 }
30 { s2+=a;
31 if((i0-i+j-j0)%2!=0)
32 if(min2>a)min2=a;
33 }
34 if((i>=i0)&&(j<=j0))
35 {
36 s3+=a;
37 if((i-i0+j0-j)%2!=0)
38 if(min3>a)
39 min3=a;
40 }
41
42 if((i>=i0)&&(j>=j0))
43 {
44 s4+=a;
45 if((i-i0+j-j0)%2!=0)
46 if(min4>a)
47 min4=a;
48 }
49 }
50
51 k1=i0*j0;
52 k2=i0*(m-j0+1);
53 k3=(n-i0+1)*j0;
54 k4=(n-i0+1)*(m-j0+1);
55
56 if((i0%2==0)&&(j0%2==0))
57 {
58 k1--;
59 s1=s1-min1;
60 }
61
62 if((i0%2==0)&&((m-j0+1)%2==0))
63 {
64 k2--;
65 s2=s2-min2;
66 }
67
68 if(((n-i0+1)%2==0)&&(j0%2==0))
69 {
70 k3--;
71 s3=s3-min3;
72 }
73
74 if(((n-i0+1)%2==0)&&((m-j0+1)%2==0))
75 {
76 k4--;
77 s4=s4-min4;
78 }
79
80 if(s2>s1)
81 {
82 ies=2;
83 k1=k2;
84 s1=s2;
85 }
86 else
87 if((s2==s1)&&(k1>k2))
88 {
89 ies=2;
90 k1=k2;
91 }
92
93 if(s3>s1)
94 {
95 ies=3;
96 k1=k3;
97 s1=s3;
98 }
99 else
100 if((s3==s1)&&(k1>k3))
101 {
102 ies=3;
103 k1=k3;
104 }
105
CAPITOLUL 9. OJI 2011 170
106 if(s4>s1)
107 {
108 ies=4;
109 k1=k4;
110 s1=s4;
111 }
112 else
113 if((s4==s1)&&(k1>k4))
114 {
115 ies=4;
116 k1=k4;
117 }
118
119 printf("%d %d %d",ies,s1,k1);
120
121 return 0;
122 }
56 kk2++;
57 if( (i!=x || j!=y ) && (i!=1 || j!=m) &&
58 (i + j)%2!=(m+1)%2 && q<m2 )
59 m2 = q;
60 }
61
62 if(i>=x && j<=y)
63 {
64 s3 += q;kk3++;
65 if( (i!=x || j!=y) && (i!=n || j!=1) &&
66 (i+j)%2 != (n+1)%2 && q<m3 )
67 m3 = q;
68 }
69
70 if(i>=x && j>= y)
71 {
72 s4 += q;kk4++;
73 if((i!=x || j!=y) && (i!=n || j!=m) &&
74 (i+j)%2 != (n+m)%2 && q<m4 )
75 m4 = q;
76 }
77 }
78
79 int k1=x*y, k2=x*(m-y+1), k3=(n-x+1)*y, k4=(n-x+1)*(m-y+1);
80
81 if(x%2==0 && y%2==0)
82 s1-=m1, k1--;
83
84 if(x%2==0 && (m-y+1)%2==0)
85 s2-=m2, k2--;
86
87 if((n-x+1)%2==0 && y%2==0)
88 s3-=m3, k3--;
89
90 if((n-x+1)%2==0 && (m-y+1)%2==0)
91 s4-=m4, k4--;
92
93 #ifdef DEBUG
94 printf("%d %d %d %d\n",kk1,kk2,kk3,kk4);
95 printf(" zona suma min k\n");
96 printf("%d %d %d %d\n",1,s1,m1,k1);
97 printf("%d %d %d %d\n",2,s2,m2,k2);
98 printf("%d %d %d %d\n",3,s3,m3,k3);
99 printf("%d %d %d %d\n",4,s4,m4,k4);
100 #endif
101
102 int z=1,k=k1;
103 int s=s1;
104
105 if(s2>s)
106 z=2,s=s2,k=k2;
107 else
108 if (s2==s && k2<k)
109 z=2,s=s2,k=k2;
110
111 if(s3>s)
112 z=3,s=s3,k=k3;
113 else
114 if (s3==s && k3<k)
115 z=3,s=s3,k=k3;
116
117 if(s4>s)
118 z=4,s=s4,k=k4;
119 else
120 if (s4==s && k4<k)
121 z=4,s=s4,k=k4;
122
123 #ifndef STDIO
124 ofstream fout("cri.out");
125 fout<<z<<" "<<s<<" "<<k<<endl;
126 #else
127 freopen("cri.out","w",stdout);
128 printf("%d %d %d\n",z,s,k);
129 #endif
130
131 return 0;
CAPITOLUL 9. OJI 2011 172
132 }
Capitolul 10
OJI 2010
10.1 livada
Problema 1 - livada 100 de puncte
Norocosul Gigel tocmai a primit în dar de la bunicul s u, Nelu, o imens plantaµie de pomi
fructiferi. Fost profesor de geometrie, Nelu a plantat în mod riguros pomii fructiferi pe m rânduri
paralele, iar pe ecare rând a plantat exact câte n pomi fructiferi. Îns , din motive mai mult sau
mai puµin obiective, domnul Nelu nu a plantat pe ecare rând toµi pomii de acela³i soi, ci din
mai multe soiuri diferite. Soiurile de pomi plantaµi în livad sunt codicate cu numere naturale
cuprinse între 1 ³i p.
Cuprins de febra rigurozit µii matematice ³i de cea a statisticii, Gigel a denit noµiunea de soi
majoritar astfel: dac pe un rând k format din n pomi fructiferi avem cel puµin n©2 1 pomi de
acela³i soi x, atunci spunem c soiul x este soi majoritar pe rândul k (prin y se înµelege partea
întreag a num rului real y ).
Cerinµe
Cunoscând numerele m, n ³i p, precum ³i soiul ec rui pom de pe ecare rând al plantaµiei,
ajutaµi-l pe Gigel s determine:
1. pe câte rânduri din livad exist un soi majoritar;
2. care este cel mai mare num r de pomi de acela³i soi plantaµi în poziµii consecutive pe un
rând.
Date de intrare
Fi³ierul de intrare livada.in conµine pe prima linie trei numere naturale m, n ³i p cu semni-
caµia din enunµ, iar pe ecare dintre urm toarele m linii se g sesc câte n numere, desp rµite prin
câte un spaµiu, reprezentând soiurile pomilor de pe rândul respectiv.
Date de ie³ire
Fi³ierul de ie³ire livada.out va conµine dou linii:
1. pe prima linie se va scrie un num r natural reprezentând num rul de rânduri din livad pe
care exist un soi majoritar;
2. pe a doua linie se va scrie un num r natural reprezentând cel mai mare numar de pomi de
acelasi soi plantaµi în poziµii consecutive pe un rând.
Restricµii ³i preciz ri
a 1 & m & 100
a 1 & n & 700.000
a 1 & m n & 700.000
a 1 & p & 998.560.000
a Pe ecare rând diferenµa dintre valoarea maxim ³i cea minim este cel mult 250.000.
a Dac doar valoarea de pe prima linie este corect , se acord 40% din punctaj. Dac doar
valoarea de pe a doua linie este corect , se acord 60% din punctaj. Dac ambele valori sunt
corecte, se acord 100% din punctajul testului respectiv.
173
CAPITOLUL 10. OJI 2010 174
Exemple
livada.in livada.out Explicaµii
4 7 9 2 Plantaµia este format din m=4 rânduri, iar pe ecare rând
2 1 23 8 2 2 3 avem câte n=7 pomi.
4 7 24 9 7 4 Pentru ca un soi sa e majoritar pe un rând trebuie ca pe acel
5 5 25 5 5 7 rând s existe cel puµin [7/2]+1 = 4 pomi din soiul respectiv.
2 3 23 2 3 1 Exist soiuri majoritare pe dou rânduri: primul ³i al treilea.
Pe randul al treilea exista 3 poziµii consecutive în care se a
pomi din acela³i soi (soiul 5).
Timp maxim de executare/test: 1.0 secunde
Memorie: total 8 MB din care pentru stiv 4 MB
Dimensiune maxim a sursei: 20 KB
71
72 return 0;
73 }
70 }
71
72 fprintf(fout,"%d\n%d",rsm,max);
73
74 fclose(fin);
75 fclose(fout);
76
77 return 0;
78 }
10.2 numar
Problema 2 - numar 100 de puncte
Cerinµe
S se determine dou numere naturale a ³i b astfel încât q a
b
iar modulul diferenµei dintre a
³i b s e minim.
Date de intrare
Fi³ierul numar.in conµine
- pe prima linie dou valori naturale ni ³i nz . ni reprezint num rul de cifre care formeaz
partea întreag a lui q iar nz reprezint num rul de cifre care formeaz partea fracµionara a lui q .
- pe a doua linie, ni cifre care reprezint partea întreag a lui q . Între dou cifre se a câte
un caracter spaµiu.
- pe a treia linie, nz cifre care reprezint partea zecimal a lui q . Între dou cifre se a câte
un caracter spaµiu.
Date de ie³ire
³ierul numar.out va conµine:
- pe prima linie un num r natural n1 care reprezint num rul de cifre din care este alc tuit
num rul a;
- pe a doua linie, cifrele num rului a, f r spaµiu între ele.
- pe a treia linie un num r natural n2 care reprezint num rul de cifre din care este alc tuit
num rul b;
- pe a patra linie, cifrele numarului b, f r spaµiu între ele.
Restricµii ³i preciz ri
- 1 & n1, n2 $ 2000
- 1 & n1 n2 & 2000
- Cifrele din care este alc tuit q sunt cele din sistemul zecimal.
- Pentru 20% dintre teste, n1 n2 & 9; pentru alte 15% dintre teste, 10 & n1 n2 & 16
Exemple
numar.in numar.out Explicaµii
13 1 q 0.375 83
0 3 Exist ³i alte perechi de valori naturale x, y astfel încât
375 1 x
y
0.375, dar pentru oricare alt pereche, ¶x y ¶ % ¶3 8¶
8 (¶...¶ reprezint modulul)
37 7
012 1234567 q 12.34567 1234567
100000
3456700 6
100000
Se ia iniµial
- a = num rul format din cifrele lui q din care se scoate punctual zecimal
- b = 1 urmat de atâtea cifre de 0 câte cifre are partea zecimal (fracµionar ).
Evident, a ³i b trebuie implementate ca numere mari - ecare cifr ca element al unui vector.
Apoi simplic m fracµia format din a ³i b.
Matematic, simplicarea ar trebui facut cu cmmmdc-ul dintre a ³i b, dar nu are rost s
calcul m acest num r deoarece a ³i b sunt numere mari ³i acest calcul s-ar face prin sc deri
repetate sau implementarea imparµirii pe numere mari, ceea ce e complicat ³i nu garanteaz
încadrarea în timp.
De fapt, cele dou numere a ³i b nu se pot simplica decât cu o putere a lui 2 sau a lui 5,
având în vedere c b este o putere a lui 10 - a³a c tot ce trebuie s facem este s implement m
împarµirea unui num r mare la un num r de o singur cifr .
Pentru punctaje parµiale, putem lucra cu variabile numerice:
- dac folosim tipuri pe 16 biµi (integer în Pascal) obµinem 10 de puncte
- dac folosim tipuri pe 36 biµi (longint în Pascal respective long sau int în C/C++) obµinem
20 de puncte
- dac folosim tipuri pe 64 biµi (int64 în Pascal respective long long în C/C++) obµinem 35
de puncte
Mai putem prinde 2 teste în care partea întreag ³i/sau partea zecimal au mai mult de 16
cifre, îns ele conµin multe 0-uri redundante, pe care trebuie s nu le includem în numerele pe care
le construim.
Putem lucra ³i cu tipuri reale (dar care s ne permit precizii cat mai bune: extended în Pascal
sau long double în C) conform unuia dintre urm torii algoritmi, ceea ce ne permite obµinerea unor
punctaje parµiale (de exemplu al doilea dintre algoritmii descri³i mai jos prind 6 teste)
citim valoarea q într-o variabil real
a q 10
nz
b 10
nz
c cmmdc a, b
a a©c, b b©c
sau
citim valoarea q într-o variabil real
pentru i 1, valoare arbitrar foarte mare
dac q i este valoare natural atunci
a qi
b i
break
10
11 unsigned long prim[]={2,5};
12
13 void initializare(vector v)
14 {
15 v[0] = 0;
16 }
17
18 void atribuire(vector v, unsigned long x)
19 {
20 v[0] = 0;
21 while (x)
22 {
23 ++v[0];
24 v[v[0]] = x % 10;
25 x /= 10;
26 }
27 }
28
29 void inmultire(vector v, unsigned long x) /* v <- v*x */
30 {
31 unsigned long i,t=0;
32
33 for (i=1;i<=v[0];i++)
34 {
35 v[i]=v[i]*x+t;
36 t=v[i]/10;
37 v[i]=v[i]%10;
38 }
39
40 while (t) /* Cat timp exista transport */
41 {
42 v[++v[0]]=t%10;
43 t/=10;
44 }
45 }
46
47 void adunare(vector a, vector b) /* a <- a+b */
48 {
49 unsigned long i,t=0;
50
51 if (b[0]>a[0])
52 {
53 for (i=a[0]+1;i<=b[0];)
54 a[i++]=0;
55
56 a[0]=b[0];
57 }
58 else
59 for (i=b[0]+1;i<=a[0];)
60 b[i++]=0;
61
62 for (i=1;i<=a[0];i++)
63 {
64 a[i]+=b[i]+t;
65 t=a[i]/10;
66 a[i]%=10;
67 }
68
69 if (t)
70 a[++a[0]]=t;
71 }
72
73
74 void scriere(vector v)
75 {
76 unsigned long i;
77
78 for(i=v[0];i>=1;i--)
79 g<<v[i];
80
81 g<<endl;
82 }
83
84 void shl(vector a, int p) /* H <- H*10ACount */
85 {
CAPITOLUL 10. OJI 2010 180
86 long i;
87
88 /* Shifteaza vectorul cu Count pozitii */
89 for (i=a[0];i;i--)
90 a[i+p]=a[i];
91
92 /* Umple primele Count pozitii cu 0 */
93 for (i=1;i<=p;)
94 a[i++]=0;
95
96 /* Incrementeaza numarul de cifre */
97 a[0]+=p;
98 }
99
100 void shr(vector a, int p) /* H <- H/10ACount */
101 {
102 unsigned long i;
103
104 /* Shifteaza vectorul cu Count pozitii */
105 for (i=p+1;i<=a[0];i++)
106 a[i-p]=a[i];
107
108 /* Decrementeaza numarul de cifre */
109 a[0]-=p;
110 }
111
112 unsigned long divide(vector a, unsigned long x) /* A <- A/X si intoarce A%X */
113 {
114 unsigned long i;
115 unsigned long R=0;
116
117 for (i=a[0];i;i--)
118 {
119 a[i]=(R=10*R+a[i])/x;
120 R%=x;
121 }
122
123 while (!a[a[0]] && a[0]>1)
124 a[0]--;
125
126 return R;
127 }
128
129 unsigned long mod(vector a, unsigned long x) /* Intoarce A%X */
130 {
131 unsigned long i;
132 unsigned long R=0;
133
134 for (i=a[0];i;i--)
135 R=(10*R+a[i])%x;
136
137 return R;
138 }
139
140 int main()
141 {
142 unsigned long n,m,i;
143
144 vector v; // numarator
145 vector s; // numitor
146
147 initializare(v);
148 initializare(s);
149
150 f>>n>>m;
151
152 // citesc partea intreaga
153 for(i=1;i<=n;i++)
154 f>>v[n+m-i+1];
155
156 // citesc partea fractionara
157 for(i=1;i<=m;i++)
158 f>>v[m-i+1];
159
160 v[0]=n+m;
161 if (v[n+m]==0) v[0]--;
CAPITOLUL 10. OJI 2010 181
162
163 atribuire(s,1);
164 shl(s,m);
165 if (m==0)
166 {
167 g<<n<<"\n";
168 scriere(v);
169
170 g<<1<<"\n";
171 scriere(s);
172
173 return 0;
174 }
175
176 for(i=0;i<=1;i++)
177 while (mod(v,prim[i])==0&&mod(s,prim[i])==0)
178 {
179 divide(v,prim[i]);
180 divide(s,prim[i]);
181 }
182
183 g<<v[0]<<"\n";
184 scriere(v);
185 g<<s[0]<<"\n";
186 scriere(s);
187
188 f.close();
189 g.close();
190
191 return 0;
192 }
Capitolul 11
OJI 2009
11.1 expresie
Problema 1 - expresie 100 de puncte
Costel are de rezolvat o tem grea la matematic : având la dispoziµie N numere naturale nenule
trebuie s a³eze între acestea 2 operaµii de înmulµire ³i N 3 operaµii de adunare, astfel încât
rezultatul calculelor s e cel mai mare posibil. Nu este permis modicarea ordinii numerelor
date.
De exemplu, dac N 5 ³i numerele sunt 4, 7, 1, 5, 3, operaµiile pot a³ezate 4 7 1 5 3,
4 7 1 5 3 e.t.c
Cerinµe
Scrieµi un program care s a³eze dou operaµii de înmulµire ³i N 3 operaµii de adunare între
cele N valori date astfel încât valoarea expresiei obµinute s e maxim .
Date de intrare
Fi³ierul de intrare expresie.in are urm toarea structur :
Pe prima linie se a un num r natural N , reprezentând num rul elementelor date.
Pe urm toarele linii se a cele N numere naturale date, ecare pe câte o linie.
Date de ie³ire
Fi³ierul de ie³ire expresie.out va conµine, pe prima linie, valoarea maxim obµinut prin
evaluarea expresiei.
Restricµii ³i preciz ri
4 & N & 1000
Numerele date sunt numere naturale între 1 ³i 10000
Exemple
expresie.in expresie.out Explicaµii
5 44 Valoarea maxim se obµine prin a³ezarea operaµiilor sub forma:
4 47153
7
1
5
3
182
CAPITOLUL 11. OJI 2009 183
Memor m cele N numere naturale date în tabloul unidimensional T . Calcul m suma celor N
valori, deoarece presupunem c , iniµial, avem în expresia noastr doar operaµii de adunare.
Exist dou cazuri posibile pentru a introduce dou operaµii de înmulµire în expresie:
Cazul 1. Cele dou înmulµiri sunt consecutive. Obµinem valoarea maxim a expresiei în
variabila suma1, luând pe rând toate tripletele de numere consecutive ti, ti 1, ti 2 ³i
alegând tripletul pentru care suma ti ti 1 ti 2 ti ti 1 ti 2 este maxim .
Cazul 2. Cele dou operaµii de înmulµire nu sunt a³ezate consecutiv. Obµinem valoarea maxim
a expresiei în variabila suma1, luând pe rand toate perechile (ti, ti 1) ³i (tj , tj 1) ³i
alegând combinaµia pentru care suma ti ti 1 tj tj 1 ti ti 1 tj tj 1
este maxim .
Deoarece numerele date sunt între 1 ³i 10000, valoarea expresiei poate dep ³i tipul de date
longint (long int).
Pentru exemplul din enunt, avem:
1 2 3 4 5
T: 4 7 1 5 3
Suma iniµial este suma=20.
Cazul 1. Avem expresiile posibile:
4*7*1+5+3 = 36
4+7*1*5+3 = 42
4+7+1*5*3 = 26
deci valoarea maxim de pân acum este 42
Cazul 2 Avem expresiile posibile:
4*7+1*5+3 = 28+5+3 = 36
4*7+1+5*3 = 28+1+15= 44
4+7*1+5*3 = 4+7+15=26
deci valoarea maxim este 44
11.2 placare
Problema 2 - placare 100 de puncte
O suprafaµ dreptunghiular de în lµime N ³i l µime M unit µi trebuie acoperit perfect (pla-
cat ) prin utilizarea unor pl ci de form dreptunghiular de dimensiune 1 P sau P 1, unde P
este un num r natural nenul. Suprafaµa dat poate privit ca un caroiaj cu N M p tr µele
egale cu unitatea.
O placare corect a suprafeµei iniµiale se memoreaz într-un ³ier text folosind urm toarele
convenµii de codicare:
a pe prima linie se precizeaz dimensiunile N ³i M ale suprafeµei;
a o plac dreptunghiular de laµime P este codicat prin num rul natural P , iar o plac de
înalµime P se codic prin num rul întreg P ;
a convenim ca placa având ambele dimensiuni egale cu unitatea s se codice cu valoarea 1;
a pe ecare din cele N linii ale codic rii se a câte un ³ir de valori întregi reprezentând, în
ordine de la stânga la dreapta, codurile pl cilor care se g sesc amplasate începând de la respectiva
linie;
a codul P strict mai mare ca 1 al unei placi orizontale apare o singur dat pe linia corespun-
z toare pe care se a placa, iar codul P al unei placi verticale va apare o singur dat ³i anume
pe prima linie de la care placa respectiv este amplasat în jos pe o anumita coloan a suprafeµei;
a Dac pe o anumit linie a suprafeµei nu exist astfel de coduri de pl ci, atunci pe respectiva
linie din ³ier este o singur valoare de 0.
CAPITOLUL 11. OJI 2009 184
Folosind codicarea unei plac ri a suprafeµei iniµiale, se poate determina imaginea acestei
plac ri sub forma unui tablou bidimensional A, cu N linii ³i M coloane, unde Aij = valoarea
absolut a codului pl cii care se suprapune peste p tr µelul de pe linia i ³i coloana j.
Cerinµe
Cunoscând codicarea unei plac ri corecte a suprafeµei date s se obµin imaginea acestei
plac ri (matricea de valori corespunz toare codic rii suprafeµei).
Date de intrare
Fi³ierul de intrare placare.in are urm toarea structur :
- pe prima linie valorile naturale N M , separate printr-un spaµiu, unde N este în lµimea
suprafeµei, M este l µimea suprafeµei.
- pe ecare din urm toarele N linii se a un ³ir de valori întregi, separate prin câte un spaµiu,
reprezentând codicarea respectivei linii a plac rii.
Date de ie³ire
În ³ierul de ie³ire placare.out se va tip ri tabloul bidimensional ce reprezint imaginea
plac rii, compus din N linii, pe ecare dintre ele aându-se M valori naturale separate prin câte
un spaµiu, cu semnicaµia din enunµ.
Restricµii ³i preciz ri
- 1 & N, M & 100 pentru 80% din teste;
- 100 $ N, M & 300 pentru 20% din teste
- dimensiunea P sau P a unei pl ci este aleas astfel încât acoperirea obµinut s nu dep -
³easc în lµimea N sau l µimea M a suprafeµei.
- datele din ³ierul de intrare sunt corecte în sensul c reprezint codicarea unei acoperiri a
zonei dreptunghiulare de dimensiuni N ³i M .
Exemple
placare.in placare.out Explicaµii
44 4 1 1 1 Valoarea 4 codic o plac de în lµime 4 ³i laµime 1 plasat
-4 1 1 1 4 1 2 2 începând din p tratul de coordonate 1, 1 ³i pîn în p tratul
12 4 2 2 1 de coordonate 4, 1
21 4 3 3 3 Valoarea 3 de pe ultima linie a codic rii desemneaz o plac de
3 l µime 3 ³i în lµime 1, plasat orizontal, începând din p tr µelul
de coordonate 4, 2.
32 32
-3 -2 32
0 31
1
Se citesc datele de intrare folosind un vector A, care va reµine, succesiv, câte o linie a ³ierului
de intrare.
Construim soluµia printr-o parcurgere a datelor de intrare.
Folosim ca memorie auxiliara o matrice REST U RI cu dou linii ³i 300 coloane.
Pentru ecare poziµie J , REST U RI 1, J va memora valoarea asociat unei pl ci întâlnite
pe una din liniile anterioare, iar REST U RI 2, J va memora num rul r mas de linii pe care se
a³eaz placa respectiv .
Pe o linie oarecare I , a codic rii, sunt posibile trei situaµii:
- dac exist plac vertical pe coloana curent , ce ocup spaµiu ³i pe linia I , se va memora
valoarea corespunz toare acelei pl ci sc zându-se cu o unitate valoarea de pe linia 2 a matricei
CAPITOLUL 11. OJI 2009 185
auxiliare REST U RI .
- dac nu, se cite³te urm toarea valoare din vectorul A de pe coloana I ³i se a³eaz placa
gasit pe linia I , orizontal dac valoarea este pozitiv sau vertical dac valoarea este negativ ; în
acela³i timp se actualizeaz matricea REST U RI , în cazul în care placa este asezat pe vertical ;
- în al treilea caz, singura valoare de pe linia curent este 0, aceasta însemnând c pe aceast
linie a plac rii exist doar placi verticale plasate pe liniile anterioare; pentru aceasta e sucient s
plas m valorile memorate în matricea REST U RI , actualizând REST U RI 2, J .
Procedeul se repet pentru ecare linie a codic rii.
Utilizarea unor tablouri bidimensionale pentru construirea imaginii plac rii determin obµine-
rea a 80 de puncte, datorit dimensiunilor prea mari ale acestora.
Observaµie: Algorimul nu necesit tehnici de programare ³i este insprirat din deniµia tabelelor
HT M L, în care o celul se poate extinde pe mai multe linii sau coloane. Programul simuleaz
modul in care tabelul este interpretat de browser ³i asat pe ecran ca pagin web.
OJI 2008
12.1 Concurs
Problema 1 - concurs 100 de puncte
La Olimpiada Naµional de Informatic particip elevi din mai multe judeµe, ecare judeµ
ind identicat în mod unic printr-un num r natural. Elevii din ecare judeµ au asociat câte
un num r natural care permite identicarea în mod unic a elevului în cadrul judeµului. Astfel,
orice participant la olimpiada poate identicat prin dou numere: identicatorul judeµului ³i
identicatorul elevului în cadrul judeµului.
Pentru a repartiza elevii la calculatoare, organizatorii au nevoie de o list care s respecte
urm toarele condiµii:
- lista conµine toµi elevii participanµi la olimpiad ;
- oricare doi elevi consecutivi în list sunt din judeµe diferite;
- elevii din orice judeµ apar în list în ordinea cresc toare a numerelor de identicare.
Cerinµe
Scrieµi un program care s genereze lista necesar organizatorilor.
Date de intrare
Fi³ierul de intrare concurs.in conµine pe prima linie un num r natural P reprezentând num -
rul total de participanµi la ONI. Pe urm toarele P linii este descris lista participanµilor, câte un
participant pe o linie. Pentru ecare participant sunt scrise dou numere naturale separate prin
spaµiu J E , unde J reprezint identicatorul judeµului, iar E reprezint identicatorul elevului în
cadrul judeµului.
Date de ie³ire
Fi³ierul de ie³ire concurs.out va conµine pe prima linie un num r natural N J , reprezentând
num rul de judeµe din care exist participanµi la olimpiad . Pe cea de a doua linie sunt scrise
N J numere naturale nenule separate prin câte un spaµiu reprezentând (în ordinea cresc toare a
numerelor de identicare a judeµelor) num rul de participanµi din ecare judeµ. Pe urm toarele P
linii este descris lista necesar organizatorilor, câte un elev pe o linie. Pentru ecare elev este scris
mai întâi identicatorul judeµului din care face parte, urmat de un spaµiu, apoi de identicatorul
elevului în cadrul judeµului.
Restricµii ³i preciz ri
Identicatorii judeµelor sunt numere naturale cuprinse între 1 ³i 50.
Identicatorii elevilor în cadrul judeµelor sunt numere naturale cuprinse între 1 ³i 1000.
Num rul total de elevi participanµi la olimpiad nu dep ³e³te 500.
Pentru datele de test exist întotdeauna soluµie, nu neap rat unic .
Pentru determinarea corect a num rului de judeµe se acord 20% din punctaj. Pentru deter-
minarea corect a num rului de judeµe, precum ³i a num rului de participanµi din ecare judeµ
se acord 30% din punctaj. Punctajul se acord integral pentru rezolvarea tuturor celor 3 cerinµe
(num r de judeµe, num r de participanµi din ecare judeµ ³i lista necesar organizatorilor).
186
CAPITOLUL 12. OJI 2008 187
Exemple
concurs.in concurs.out
7 3
1 3 4 12
2 4 1 2
1 2 5 2
5 2 1 3
5 3 5 3
1 6 1 6
1 9 2 4
1 9
Vom utiliza o matrice A cu maxim 50 de linii. Pe linia i vor memorate numerele de identicare
ale elevilor din judeµul i.
Mai exact:
Ai0 reprezint num rul de elevi din judeµul i;
Ai1, Ai2, ..., AiAi0 sunt elevii din judeµul i.
Pentru a num ra judeµele din care exist participanµi este sucient s parcurgem coloana 0 a
matricei ³i s num r m liniile i pentru care Ai0 j 0.
Pentru a rezolva cerinµa 2, vom parcurge din nou coloana 0 (începând de la 1) ³i vom a³a
valorile nenule Ai0.
Pentru a construi lista necesar organizatorilor:
1. vom sorta cresc tor elevii din ecare judeµ;
2. vom repartiza elevii astfel:
- la ecare pas determin m dou judeµe cu num r maxim de participanµi la ONI
- plasez în list câte un elev din ecare dintre cele dou judeµe (astfel judeµele vor alterna).
Pentru a p stra ordinea cresc toare a elevilor în cadrul judeµelor vom reµine pentru ecare
judeµ poziµia elevului curent (cel care urmeaz a plasat în list ).
Când plas m în list un elev dintr-un judeµ avem grij s decrement m num rul de elevi
disponibili din judeµul respectiv (pentru a putea calcula la ecare pas care sunt judeµele cu num r
maxim de elevi disponibili).
Când num rul total de elevi este impar trebuie s m atenµi la ultimul pas, indc nu trebuie
s mai select m doi elevi, ci unul singur.
16 int inc[JMax+1];
17 FILE * fout;
18
19 read();
20 for (i=1; i<=JMax; i++)
21 if (a[i][0])
22 nrJ++;
23
24 fout=fopen("concurs.out","w");
25 fprintf(fout,"%d\n",nrJ);
26
27 for (i=1; i<=JMax; i++)
28 if (a[i][0])
29 fprintf(fout,"%d ",a[i][0]);
30 fprintf(fout,"\n");
31
32 for (i=1; i<=JMax; i++)
33 if (a[i][0])
34 sortare(i);
35
36 for (j=1; j<=JMax; j++) inc[j]=1;
37
38 for (k=1; k<=P; i++)
39 {
40 //determina max1 si max2
41 max1=max2=0;
42 pozmax1=pozmax2=0;
43
44 for (j=1; j<=JMax; j++)
45 if (a[j][0]>max1)
46 {
47 max2=max1;
48 pozmax2=pozmax1;
49 max1=a[j][0];
50 pozmax1=j;
51 }
52 else
53 if (a[j][0]>max2)
54 {
55 max2=a[j][0];
56 pozmax2=j;
57 }
58
59 //distribuie primii 2 elevi in lista
60 lista[k][0]=pozmax1;
61 lista[k][1]=a[pozmax1][inc[pozmax1]];
62 if (max2)
63 {
64 lista[k+1][0]=pozmax2;
65 lista[k+1][1]=a[pozmax2][inc[pozmax2]];
66 }
67 k+=2;
68
69 //elimina elevii repartizati
70 a[pozmax1][0]--;
71 a[pozmax2][0]--;
72 inc[pozmax1]++;
73 inc[pozmax2]++;
74 }
75
76 for (i=1; i<=P; i++)
77 fprintf(fout,"%d %d\n", lista[i][0], lista[i][1]);
78
79 fclose(fout);
80 return 0;
81 }
82
83 void read()
84 {
85 int i, el, jud;
86 FILE * fin = fopen("concurs.in", "rt");
87
88 fscanf(fin, "%d", &P);
89 for (i=1; i<=P; i++)
90 {
91 fscanf (fin,"%d %d",&jud, &el);
CAPITOLUL 12. OJI 2008 189
92 a[jud][0]++;
93 a[jud][a[jud][0]]=el;
94 }
95
96 fclose(fin);
97 }
98
99 void sortare (int i)
100 {
101 int ok, j, aux;
102
103 do
104 {
105 ok=1;
106 for (j=1; j<a[i][0]; j++)
107 if (a[i][j]>a[i][j+1])
108 {
109 aux=a[i][j];
110 a[i][j]=a[i][j+1];
111 a[i][j+1]=aux;
112 ok=0;
113 }
114 } while (!ok);
115 }
12.2 Pluricex
Problema 2 - Pluricex 100 de puncte
Cerinµe
Scrieµi un program care s determine toate echipele ce pot formate din k dintre cei n elevi
de pe lista directorului, cu condiµia ca pentru ecare disciplin s existe în echip cel puµin un
membru care s studieze la CEX disciplina respectiv .
Date de intrare
Fi³ierul de intrare pluricex.in conµine pe prima linie trei numere naturale n k D (cu semni-
caµia din enunµ). Urmeaz n linii care descriu particip rile la CEX ale celor n elevi de pe lista
directorului. Mai exact, pe linia i 1 este descris participarea elevului i astfel:
nr d1 d2 ... dnr
Primul num r de pe linie (nr) indic num rul de discipline la care particip elevul i. Urm -
toarele nr numere reprezint disciplinele la care particip elevul i. Numerele scrise pe aceea³i linie
sunt separate prin spaµiu.
Date de ie³ire
Fi³ierul de ie³ire pluricex.out va conµine toate echipele ce se pot forma respectând condiµiile
din enunµ, câte o echip pe o linie. Membrii unei echipe vor scri³i în ordine cresc toare, separaµi
prin câte un spaµiu. Echipele vor scrise în ordine lexicograc .
Restricµii ³i preciz ri
a 0 $ n & 22
a 0$k&8
a 0 $ D & 10
a Pentru datele de test problema admite întotdeauna soluµie, num rul de soluµii ind $ 20000.
CAPITOLUL 12. OJI 2008 190
Exemple
pluricex.in pluricex.out
6 3 5 234
1 2 345
2 1 4
3 2 43
1 5
2 3 1
1 3
Vom genera în ordine lexicograc toate submulµimile de k elemente ale mulµimii r1, 2, ..., nx
(combin ri de n luate câte k ) printr-un algoritm de tip succesor.
Pentru ecare submulµime vom verica dac pentru ecare disciplin exist cel puµin un mem-
bru al echipei care s studieze la CEX disciplina respectiv (în caz armativ, soluµia va a³at ).
Generare combin ri
Fie n ³i k dou numere naturale, 1 & k & n & 22.
S se genereze în ordine lexicograc toate submulµimile formate din k elemente ale mulµimii
r1, 2, ..., nx.
Soluµie
Vom reprezenta o submulµime ca un vector C cu k elemente (elementele submulµimii).
Evident, 1 & C i & n.
Deoarece ordinea elementelor într-o submulµime nu conteaz , pentru a nu genera de mai multe
ori aceea³i submulµime vom conveni c plas m elementele în submulµime în ordine cresc toare:
C i $ C i 1, pentru orice 1 & i $ k .
Vom genera submuµimile printr-un algoritm de tip succesor.
Cea mai mic submulµime (din pdv lexicograc) este 1, 2, ..., k.
Cea mai mare submulµime este: n-k+1,..., n-1, n
Intrebare: care este cea mai mare valoare care poate plasat pe poziµia i:
Poziµie k k 1 k 2 ... i ... 1
Valoare maxim n n 1 n 2 ... ? ... n k 1
Observ m c atunci când poziµia scade cu 1, valoarea maxim scade cu 1, deci diferenµa dintre
V aloarea_maxima ³i P ozitie este constant :
V aloare_maxima P ozitie n k ? i.
Deducem c valoarea maxim care poate plasat pe poziµia i este n k i.
Pas 1. Iniµializ m vectorul C (C i 1, pentru orice 1 & i & k )
Pas 2. Cât timp este posibil (mai exist succesor)
- a³ m submulµimea curent (dac veric condiµiile din enunµ);
- gener m submulµimea urm toare; în acest scop c ut m prima component (începând din
dreapta c tre stânga) care poate m rit (adic C i $ n k i; dac g sim o astfel de
component o m rim, ³i repunem pe cea mai mic valoare posibil toate componentele urm toare
(C j C j 1 1, i $ j & k ); dac nu g sim o astfel de component deducem c generarea s-a
încheiat, acesta a fost cea mai mare submulµime din punct de vedere lexicograc.
Generare submulµimi
O alt soluµie posibil este de a genera toate submulµimile mulµimii r1, 2, ..., nx ³i de a verica
corectitudinea acelor soluµii care au k elemente. O astfel de abordare ar obµine în principiu 80 de
puncte (70 sau 90 ind punctaje posibile, funcµie de calculatorul de evaluare ³i ecienµa veric rii
condiµiilor).
CAPITOLUL 12. OJI 2008 191
66 {
67 fscanf (fin,"%d",&nr);
68 for (j=1; j<=nr; j++)
69 {
70 fscanf (fin, "%d",&d);
71 a[i][d]=1;
72 }
73 }
74
75 fclose(fin);
76 }
77
78 void write()
79 {
80 int i;
81 for (i=1; i<k; i++)
82 fprintf(fout,"%d ",sol[i]);
83
84 fprintf(fout,"%d\n",sol[k]);
85 }
Capitolul 13
13.1 Cartele
În sediul unei rme se intr doar cu ajutorul cartelelor magnetice. De câte ori se schimb
codurile de acces, cartelele trebuie formatate. Formatarea presupune imprimarea unui model
prin magnetizare. Dispozitivul în care se introduc cartelele, numit cititor de cartele, veric acest
model. Toate cartelele au acelea³i dimensiuni, suprafaµa p trat ³i grosimea neglijabil . Cele dou
feµe plane ale unei cartele se împart ecare în N N celule p trate, identice ca dimensiuni. Prin
formatare unele celule, marcate cu negru în exemplu, se magnetizeaz permiµând radiaµiei infraro³ii
s treac dintr-o parte în cealalt a cartelei. În interiorul cititorului de cartele se ilumineaz
uniform una dintre feµele cartelei. De cealalt parte fasciculele de lumin care str bat cartela sunt
analizate electronic. Pentru a permite accesul în cl dire modelul imprimat pe cartel trebuie s
coincid exact cu modelul ³ablonului care memoreaz codul de intrare. Prin fanta dispozitivului
nu se pot introduce mai multe cartele deodat . Cartela se poate introduce prin fant cu oricare
dintre muchii spre deschiz tura fantei ³i cu oricare dintre cele dou feµe orientate c tre ³ablon.
Dup introducere cartela se dispune în plan paralel cu ³ablonul, lipit de acesta, astfel încât cele
patru colµuri ale cartelei se suprapun exact cu colµurile ³ablonului. Modelele imprimate pe cele
dou feµe ale unei cartele sunt identice. Unei celule magnetizate îi corespunde pe faµa opus tot
o celul magnetizat , iar unei celule nemagnetizate îi corespunde una nemagnetizat . O celul
magnetizat este transparent pentru radiaµia infraro³ie indiferent de faµa care se ilumineaz .
Un angajat al rmei are mai multe cartele. Pe unele dintre acestea a fost imprimat noul cod
de intrare, iar pe altele sunt coduri mai vechi. Pentru a aa care sunt cartelele care-i permit
accesul în sediul rmei angajatul este nevoit s le verice pe toate, introduc ndu-le pe rând, în
toate modurile pe care le consider necesare, în fanta cititorului de cartele.
Cerinµ
Scrieµi un program care determin care dintre cartele permite accesul în sediul rmei.
Date de intrare
Fi³ierul de intrare cartele.in conµine pe prima linie dou numere naturale N ³i C desp rµite
printr-un spaµiu. N este dimensiunea tablourilor care reprezint modelul ³ablon ³i modelele car-
telelelor. C reprezint num rul de cartele. Urmeaz C 1 blocuri de câte N linii ecare. Primul
bloc de N linii codic ³ablonul. Urm toarele C blocuri de câte N linii codic ecare câte o
cartel . Pe ecare linie sunt câte N valori întregi, desp rµite printr-un singur spaµiu. Celulelor
magnetizate le corespunde valoarea 1, iar celorlalte, valoarea 0.
193
CAPITOLUL 13. OJI 2007 CLASA A IX-A 194
Date de ie³ire
În ³ierul de ie³ire cartele.out se vor scrie C linii, câte o valoare pe linie. Pe linia i se va scrie
valoarea 1 dac cartela i permite accesul în cl dire ³i valoarea 0 în caz contrar.
Restricµii ³i preciz ri
1 $ N, C & 50
Exemplu
cartele.in cartele.out Explicaµii
3 2 1 Datele de intrare corespund situaµiei din gur .
0 1 0 0 Cartela 1 se potrive³te perfect ³ablonului, dac
0 0 1 se rote³te în sens trigonometric cu 90 de grade.
1 0 0 Cartela 2 nu se potrive³te ³ablonului, indiferent
1 0 0 de modul în care se introduce în fant .
0 0 1
0 1 0
0 0 1
0 0 1
0 1 0
Timp maxim de execuµie/test: 1 secund
Pentru ecare cartel , se compar element cu element, matricea care reprezint sablonul, cu
urm toarele tablouri:
1. Cartela
2. Cartela rotit cu 90 grade
3. Cartela rotit cu 180 grade
4. Cartela rotit cu 270 grade
Dac nu s-a gasit o coincidenµ , se întoarce cartela, printr-o operaµie de oglindire faµ de linia
i n©2, (sau faµ de coloana j n©2), dup care se compar ³ablonul cu urm toarele tablouri:
5. Cartela oglindit
6. Cartela oglindit rotit cu 90 grade
7. Cartela oglindit rotit cu 180 grade
8. Cartela oglindit rotit cu 270 grade
Rotirile se pot face în sens trigonometric sau orar.
Dac s-a g sit o coincidenµ la oricare dintre pa³ii de mai sus, se opre³te c utarea, se aseaz
1 ³i se trece la prelucrarea urm toarei cartele.
Dac nici dup pasul 8 nu s-a gasit o potrivire exact , se a³eaz 0 ³i se trece la prelucrarea
urm toarei cartele.
Varianta 1:
42 for(i=1;i<=n;i++)
43 for(j=1;j<=n;j++)
44 {
45 st.nextToken(); b[i][j]=(int)st.nval;
46 if(b[i][j]!=a[i][j]) identice=false;
47 }
48
49 for(int f=1;f<=2&&!identice;f++) // pentru fata 1 si 2
50 {
51 for(r=1;r<=4&&!identice;r++) // la a patra rotatie se revine la matricea
initiala
52 {
53 roteste(); // cu 90 in sens trigonometric
54 if(egale()) identice=true;
55 }
56 if(!identice) inverseaza();
57 }
58 if(identice) out.println(1); else out.println(0);
59 }// for k
60 }// rezolva(...)
61
62 static boolean egale()
63 {
64 for(int i=1;i<=n;i++)
65 for(int j=1; j<=n; j++)
66 if(a[i][j]!=b[i][j] ) return false;
67 return true;
68 }// egale(...)
69
70 static void inverseaza()
71 {
72 int i, j, temp;
73 for(i=1;i<=n/2;i++)
74 for(j=1;j<=n;j++) { temp=b[i][j]; b[i][j]=b[n-i+1][j]; b[n-i+1][j]=temp; }
75 } // inverseaza(...)
76
77 static void roteste()
78 {
79 int i, j;
80 for(i=1;i<=n;i++)
81 for(j=1;j<=n;j++) aux[n-j+1][i]=b[i][j];
82
83 for(i=1;i<=n;i++)
84 for(j=1;j<=n;j++) b[i][j]=aux[i][j];
85 }// roteste(...)
86 }// class
Varianta 2:
26 for(j=1;j<=n;j++)
27 {
28 st.nextToken(); a[i][j]=(int)st.nval;
29 }
30
31 for(k=1;k<=c;k++)
32 {
33 for(i=1;i<=n;i++) // citesc cartela k
34 for(j=1;j<=n;j++)
35 {
36 st.nextToken(); b[i][j]=(int)st.nval;
37 }
38
39 ok=true;
40 for(i=1;i<=n&&ok;i++) // direct
41 for(j=1;j<=n&&ok;j++)
42 if(a[i][j]!=b[i][j]) ok=false;
43 if(ok) {out.println(1); continue;} // cu alta cartela
44
45 ok=true;
46 for(i=1;i<=n&&ok;i++) // rotit cu 90 (ceas!)
47 for(j=1;j<=n&&ok;j++)
48 if(a[i][j]!=b[j][n-(i-1)]) ok=false;
49 if(ok) {out.println(1); continue;} // cu alta cartela
50
51 ok=true;
52 for(i=1;i<=n&&ok;i++) // rotit cu 180 (ceas!)
53 for(j=1;j<=n&&ok;j++)
54 if(a[i][j]!=b[n-(i-1)][n-(j-1)]) ok=false;
55 if(ok) {out.println(1); continue;} // cu alta cartela
56
57 ok=true;
58 for(i=1;i<=n&&ok;i++) // rotit cu 270 (ceas!) <==> 90 trig
59 for(j=1;j<=n&&ok;j++)
60 if(a[i][j]!=b[n-(j-1)][i]) ok=false;
61 if(ok) {out.println(1); continue;} // cu alta cartela
62
63 ok=true;
64 for(i=1;i<=n&&ok;i++) // invers + direct
65 for(j=1;j<=n&&ok;j++)
66 if(a[i][j]!=b[i][n-(j-1)]) ok=false;
67 if(ok) {out.println(1); continue;} // cu alta cartela
68
69 ok=true;
70 for(i=1;i<=n&&ok;i++) // invers + rotit 90 (ceas!)
71 for(j=1;j<=n&&ok;j++)
72 if(a[i][j]!=b[n-(j-1)][n-(i-1)]) ok=false;
73 if(ok) {out.println(1); continue;} // cu alta cartela
74
75 ok=true;
76 for(i=1;i<=n&&ok;i++) // invers + rotit 180 (ceas!)
77 for(j=1;j<=n&&ok;j++)
78 if(a[i][j]!=b[n-(i-1)][j]) ok=false;
79 if(ok) {out.println(1); continue;} // cu alta cartela
80
81 ok=true;
82 for(i=1;i<=n&&ok;i++) // invers + rotit cu 270 (ceas!) <==> 90 trig
83 for(j=1;j<=n&&ok;j++)
84 if(a[i][j]!=b[j][i]) ok=false;
85 if(ok) {out.println(1); continue;} // cu alta cartela
86
87 out.println(0); // nu s-a potrivit
88 } // for k
89 out.close();
90 }// main
91 }// class
Varianta 3:
13.2 Paritate
În vederea asigur rii unei transmiteri cât mai exacte a informaµiilor pe reµea, transmiterea se
efectueaz caracter cu caracter, ecare caracter ind dat prin codul s u ASCII, adic o grup de
8 biµi (octet). Pentru ecare 8 biµi transmi³i se calculeaz un bit de paritate care are valoarea 0
(dac codul ASCII al caracterului conµine un num r par de cifre binare 1) sau 1 (în caz contrar).
Deoarece în problema noastr se transmit numai caractere ASCII standard, cu codul ASCII
CAPITOLUL 13. OJI 2007 CLASA A IX-A 200
din intervalul [32,127], codul lor ASCII are bitul 7 (primul bit din stnga) egal cu 0. Pe aceast
poziµie va pus bitul de paritate, economisind astfel câte un bit pentru ecare caracter transmis.
De exemplu, dac mesajul care trebuie trasmis conµine caracterele "Paritate", succesiunea de biµi
transmis va :
În plus, pe lâng caracterele amintite, în mesaj mai poate s apar un caracter special care
indic trecerea la începutul unui nou rând. Acest caracter are codul ASCII 10.
Cerinµ
S se scrie un program care s verice dac un text a fost sau nu transmis corect.
Date de intrare
Fi³ierul de intrare paritate.in are pe prima linie o succesiune de caractere '0' ³i '1' care
reprezint mesajul transmis. Între caractere nu exist spaµii. Linia se termin cu caracterul
marcaj de sfâr³it de linie (newline).
Date de ie³ire
Fi³ierul de ie³ire paritate.out are pe prima linie mesajul DA dac textul a fost transmis corect
sau NU în caz contrar. În cazul în care mesajul de pe prima linie este DA liniile urm toare vor
conµine textul transmis în clar. În cazul în care mesajul de pe prima linie este NU linia urm toare
va conµine numerele de ordine ale caracterelor care nu au fost transmise corect, în ordine strict
cresc toare, separate prin câte un spaµiu.
Restricµii ³i preciz ri
a Cei 8 biµi ai codului ASCII a unui caracter se numeroteaz de la 0 la 7, de la dreapta la
stânga, cel mai din stânga bit ind bitul 7 iar cel mai din dreapta bitul 0.
a Textul transmis are cel mult 60000 caractere.
a Num rul de caractere '0' ³i '1' din prima linie a ³ierului de intrare este multiplu de 8.
a Codurile ASCII ale caracterelor din text aparµin mulµimii r10, 32 127x, codul 10 însemnând
trecerea la începutul unui rând nou.
a Nici o linie din ³ierul de iec sire nu va avea mai mult de 255 caractere.
a Caracterele din text sunt numerotate începând de la 0.
a mesajele DA/NU din prima linie a ³ierului de ie³ire se scriu cu majuscule.
Exemplul 1:
paritate.in
0101000011100001011100100110100101110100111000010111010001100101
paritate.out Explicaµie
DA Toate codurile sunt
Paritate
Exemplul 2:
paritate.in
1101000011100001111100100110100101110100111000010111010011100101
paritate.out Explicaµie
NU Primul caracter a fost transmis ca succesiunea de biµi 11010000
027 ceea ce înseamn c f r bitul de paritate ar trebuit s existe
un num r impar de cifre 1, ceea ce este fals. Deci caracterul nu
a fosttransmis corect. Acela³i lucru se veric ³i pentru
caracterele cu numerele de ordine 2 ³i 7.
Exemplul 3:
paritate.in
010000011111101001101001000010100110010100001010011010100110111101101001
paritate.out Explicaµie
DA Toate codurile sunt corecte.
Azi În text exist dou caractere cu cod ASCII 10
e
joi
Timp maxim de execuµie/test: 1 secund
CAPITOLUL 13. OJI 2007 CLASA A IX-A 201
35
36 if ((Nr1+BitP)%2==0) //daca cod corect
37 a[i]=Cod; //pun caracterul in vector
38 else //altfel
39 {
40 a[i]=1; //pun 1
41 Eroare=i; //si retin pozitia
42 }
43 fscanf(f, "%c", &c);
44 }
45
46 if (Eroare==0) //daca nu sunt erori
47 { //scrie DA si
48 fprintf(g, "DA\n");
49 for (j=0; j<=i; j++) //afiseaza cele i+1 caractere
50 if (a[j]==10) //avand grija la caracterul cu codul 10
51 fprintf(g, "\n");
52 else //altfel
53 fprintf(g, "%c", a[j]); //scrie caracterul
54 // fprintf(g, "\n");
55 }
56 else //eroare!!!
57 {
58 fprintf(g, "NU\n"); //scrie NU si
59 for (j=0; j<Eroare; j++)
60 if (a[j]==1) //cauta erorile - cod 01
61 fprintf(g, "%ld ", j); //si afiseaza pozitia lor
62 fprintf(g, "%ld\n", Eroare); //afiseaza pozitia ultimei erori
63 }
64
65 fclose(g);
66 return 0;
67 }
Varianta 1: Versiunea este o prelucrare a variantei ociale; comentariile din sursa au r mas
nemodicate pentru c sunt un exemplu bun!
14.1 Flori
Cristina Bohm
Fetiµele din grupa mare de la gr diniµ culeg ori ³i vor s împleteasc coroniµe pentru festivi-
tatea de premiere. În gr din sunt mai multe tipuri de ori. Fiecare dintre cele n fetiµe culege un
buchet având acela³i num r de ori, îns nu neap rat de acela³i tip. Pentru a împleti coroniµele
fetiµele se împart în grupe. O fetiµ se poate ata³a unui grup numai dac are cel puµin o oare de
acela³i tip cu cel puµin o alt fetiµ din grupul respectiv.
Cerinµ
Fiind dat un num r natural n reprezentând num rul fetiµelor ³i num rul natural k reprezentând
num rul de ori dintr-un buchet, s se determine grupele care se formeaz .
Date de intrare
Fi³ierul de intrare ori.in conµine pe prima linie, separate printr-un spaµiu, numerele naturale
n ³i k , reprezentând num rul de fetiµe ³i respectiv num rul de ori din ecare buchet. Fiecare
dintre urm toarele n linii conµine, pentru ecare fetiµ , câte k valori separate prin câte un spaµiu
reprezentând tipurile de ori culese.
Date de ie³ire
Fi³ierul de ie³ire ori.out va conµine pe ecare linie câte o grup format din numerele de
ordine ale fetiµelor separate prin câte un spaµiu, în ordine cresc toare, ca în exemplu.
Restricµii ³i preciz ri
a 1 & n & 150
a 1 & k & 100
a Tipul unei ori este un num r întreg din intervalul 0, 100.
a Într-o grup numerele de ordine ale fetiµelor trebuie date în ordine strict cresc toare.
a În ³ierul de ie³ire grupele vor a³ate în ordinea cresc toare a num rului de ordine al
primei fetiµe din grup .
Exemplu
ori.in ori.out Explicaµie
5 4 134 Fetiµele 1 ³i 3 au cules amândou ori de tipul 1,
1 2 3 4 2 iar fetiµele 1 ³i 4 au cules amândou ori de tipurile
5 6 9 6 5 2,3 ³i 4, deci toate cele trei fetiµe (1, 3, 4) se vor aa
1 1 1 1 în aceea³i grup . Fetiµele 2 ³i 5 vor forma ecare câte
2 4 4 3 o grup deoarece nu au cules ori de acela³i tip cu
7 7 7 7 nici una dintre celelalte fetiµe.
Timp de rulare/test: 1 secund
Soluµia comisiei
204
CAPITOLUL 14. OJI 2006 CLASA A IX-A 205
- construiesc matricea a denita astfel : pe linia i sunt tipurile distincte de ori ale fetiµei cu
num rul de ordine i
- a[i][0] = num rul de elemente de pe linia i; acesta va deveni 0 dac linia a fost reunit
în alt linie
- vectorul viz are n elemente ³i pe parcursul prelucr rii , fetiµele care ajung în aceea³i grup
vor avea aceea³i valoare în vectorul viz: de exemplu, dac fetiµa 3 ajunge în grupa în care
e fetiµa 1 atunci viz[3]=viz[1];
- funcµia reuneste face reuniunea mulµimilor de pe liniile i ³i j în linia i; dac s-a f -
cut o astfel de reuniune, scad i (i ) ³i astfel se rezolv situaµia în care de exemplu
i rel j, not ( i rel k) , j rel k; executând i--, k va ajunge tot în grup cu
i; altfel k ar ajunge în alt grup
- a³area grupelor presupune selectarea din vectorul viz a poziµiilor care au aceea³i valoare:
toate poziµiile i care au viz[i]=1 (de exemplu) sunt în prima grup ; pun pe 0 poziµiile
a³ate pentru a nu le mai relua o dat .
38 a[i][0]++;
39 a[i][ a[i][0] ]=a[j][u];
40 }
41 }
42
43 int main()
44 {
45 int viz[150],i,j,val,ok;
46 fscanf(f,"%d %d",&n,&k);
47
48 for(i=1;i<=n;i++)
49 for(j=1;j<=k;j++)
50 {
51 fscanf(f,"%d",&val);
52 if(!apartine(val,i))
53 {
54 a[i][0]++; // pe prima coloana am nr. de tipuri distincte
55 // de flori
56 a[i][ a[i][0] ]=val; // in multimea de pe linia i am tipurile
57 // distincte de flori al fetitei i
58 }
59 }
60
61 for(i=1;i<=n;i++)
62 viz[i]=i; //initial exista n grupe
63
64 for(i=1;i<=n;i++)
65 {
66 ok=0;
67 if(a[i][0])
68 {
69 for(j=i+1;j<=n;j++)
70 if(irelj(i,j))
71 {
72 viz[j]=viz[i]; //j trebuie sa ajunga in grupa cu i
73 reuneste(i,j); //reunesc in linia i linia j
74 a[j][0]=0;//consider ca in multimea j am 0 elemente acuma
75 ok=1;
76 }
77 }
78
79 if (ok) i--;// faptul ca am reunit in i cel putin o multime j implica
80 // sa continui cu aceeasi linie i
81 // daca as lasa i sa se incrementeze conform for-ului,
82 // ar gresi in sensul ca
83 // pt. i rel j si i nu e in rel cu k si j rel k
84 // ar pune j in grupa i dar k ar ajunge in alta grupa
85 }
86
87 for(i=1;i<=n;i++)
88 if(viz[i])
89 {
90 fprintf(g,"%d ",i);
91 for(j=i+1;j<=n;j++)
92 if(viz[i]==viz[j])
93 {
94 fprintf(g,"%d ",j);
95 viz[j]=0; //ca sa nu mai fie prelucrat
96 }
97
98 fprintf(g,"\n");
99 }
100
101 fclose(g);
102 return 0;
103 }
Variant iterativ :
1 import java.io.*;
2 class Flori1
3 {
4 static int n,k;
5 static int[][] a=new int[151][101];
6 static int[] gf=new int[151];
7 static int[] fgc=new int[101];
8
9 public static void main(String[] args) throws IOException
10 {
11 int i,j,ii,ng,ok,gasit;
12 StreamTokenizer st=new StreamTokenizer(
13 new BufferedReader(new FileReader("flori.in")));
14 PrintWriter out=new PrintWriter(
15 new BufferedWriter(new FileWriter("flori.out")));
16
17 st.nextToken(); n=(int)st.nval;
18 st.nextToken(); k=(int)st.nval;
19
20 for(i=1;i<=n;i++)
21 for(j=1;j<=k;j++) { st.nextToken(); a[i][j]=(int)st.nval; }
22
23 ng=0;
24 for(i=1;i<=n;i++)
25 {
26 if(gf[i]!=0) continue;
27 ng++;
28 for(j=0;j<=100;j++) fgc[j]=0;
29 for(j=1;j<=k;j++) fgc[a[i][j]]=1;
30
31 ok=1;
32 while(ok==1)
33 {
34 ok=0;
35 for(ii=i+1;ii<=n;ii++)
36 {
37 if(gf[ii]!=0) continue;
38 gasit=0;
39 for(j=1;j<=k;j++) if(fgc[a[ii][j]]==1)
40 {
41 gasit=1;
42 break;
43 }
44
45 if(gasit==1)
46 {
47 for(j=1;j<=k;j++) fgc[a[ii][j]]=1;
48 ok=1;
49 gf[ii]=ng;
50 }
51 }//for ii
52 }//while
53
54 out.print(i+" ");
55 for(j=1;j<=n;j++) if(gf[j]==ng) out.print(j+" ");
56 out.println();
57 }//for i
58
59 out.close();
60 }// main
61 }// class
Variant recursiv :
Listing 14.1.3: ori2.java
1 import java.io.*;
2 class Flori2
3 {
4 static int n,k,ng;
5 static char[][] a=new char[151][101];
6 static int[] gf=new int[151];
7
8 public static void main(String[] args) throws IOException
9 {
CAPITOLUL 14. OJI 2006 CLASA A IX-A 208
10 int i,j,fij;
11 StreamTokenizer st=new StreamTokenizer(
12 new BufferedReader(new FileReader("flori.in")));
13 PrintWriter out=new PrintWriter(
14 new BufferedWriter(new FileWriter("flori.out")));
15
16 st.nextToken(); n=(int)st.nval;
17 st.nextToken(); k=(int)st.nval;
18
19 for(i=1;i<=n;i++)
20 for(j=1;j<=k;j++) { st.nextToken(); fij=(int)st.nval; a[i][fij]=1;}
21
22 ng=0;
23 for(i=1;i<=n;i++)
24 {
25 if(gf[i]!=0) continue;
26 ng++;
27 fata(i);
28 }
29
30 for(i=1;i<=ng;i++)
31 {
32 for(j=1;j<=n;j++) if(gf[j]==i) out.print(j+" ");
33 out.println();
34 }
35
36 out.close();
37 }// main
38
39 static void fata(int i)
40 {
41 int j,ii;
42
43 gf[i]=ng;
44 for(j=0;j<=100;j++)
45 {
46 if(a[i][j]==0) continue;
47 for(ii=1;ii<=n;ii++)
48 {
49 if(ii==i) continue;
50 if(a[ii][j]==1)
51 if(gf[ii]==0) fata(ii);
52 }
53 }
54 }// fata(...)
55 }// class
14.2 Pluton
Marinel Serban
În timpul acµiunii "Furtun în de³ert" din cauza unei furtuni de nisip, n soldaµi s-au r t cit de
plutoanele lor. Dup trecerea furtunii se pune problema regrup rii acestora pe plutoane. Pentru
aceasta se folosesc pl cuµele de identicare pe care soldaµii le poart la gât. Pe aceste pl cuµe
sunt scrise numere care pot identica ecare soldat ³i plutonul din care acesta face parte. Astfel,
soldaµii din acela³i pluton au num rul de identicare format din acelea³i cifre, dispuse în alt
ordine ³i numerele de identicare sunt unice. De exemplu, numerele de identicare 78003433,
83043073, 33347008 indic faptul c cei trei soldaµi care le poart fac parte din acela³i pluton.
Cerinµ
Fiind date cele n numere de pe pl cuµele de identicare, s se regrupeze cei n soldaµi pe
plutoane, indicându-se num rul de plutoane g site (un pluton ref cut trebuie s aib minimum
un soldat), num rul de soldaµi din cel mai numeros pluton, num rul de plutoane care au acest
num r maxim de soldaµi precum ³i componenµa unui astfel de pluton (cu num r maxim de soldaµi
regrupaµi).
Date de intrare
Fi³ierul de intrare pluton.in conµine pe prima linie num rul n de soldaµi recuperaµi, iar pe
ecare dintre urm toarele n linii câte un num r de identicare a celor n soldaµi.
Date de ie³ire
CAPITOLUL 14. OJI 2006 CLASA A IX-A 209
Fi³ierul de ie³ire pluton.out va conµine pe prima linie num rul de plutoane ref cute. Linia a
doua va conµine num rul de soldaµi din cel mai numeros pluton ref cut. Linia a treia va conµine
num rul de plutoane care au num rul maxim de soldaµi recuperaµi. Linia a patra va conµine
componenµa unui astfel de pluton, cu num r maxim de soldaµi recuperaµi, numerele de identicare
ale soldaµilor din componenµ ind scrise unul dup altul separate prin câte un spaµiu.
Restricµii ³i preciz ri
a 0 $ n & 4000
a 0 $ num r de identicare $ 2.000.000.000
Observaµii
Deoarece linia a patra conµine numerele de identicare ale soldaµilor unuia dintre plutoanele
cu un num r maxim de soldaµi, pot exista mai multe soluµii corecte. Se poate alege oricare dintre
acestea.
Se acord punctaje parµiale astfel: pentru valoarea corect de pe prima linie se acord 30%
din punctaj; pentru valorile corecte de pe prima ³i a doua linie se acord 50% din punctaj, pentru
valorile corecte de pe prima, a doua ³i a treia linie se acord 70% din punctaj, iar pentru rezolvarea
corect a tuturor cerinµelor se acord punctajul integral aferent testului.
Exemplu
pluton.in pluton.out Explicaµie
10 6 Au fost recuperaµi soldaµi din 6 plutoane
1223 3 distincte, cei mai mulµi soldaµi recuperaµi
123 2 dintr-un pluton ind în num r de 3.
666 321 312 123
321 Exist 2 plutoane cu num r maxim de
7890 soldaµi recuperaµi (3), unul dintre ele
2213 ind format din soldaµii cu numerele
312 321 312 123.
655
1000 De remarcat c ³i soluµia
1322 1223 2213 1322 este corect .
Timp de rulare/test: 1 secund
Soluµia comisiei
Soluµia 1:
în timpul citirii creez un nou vector care conµine pe poziµiile corespunz toare numerele de
identicare din vectorul iniµial în ordinea descrescatoare a cifrelor
în etapa a doua se parcurge vectorul nou format grupând toate numerele de identicare
identice; dup formarea unui grup (pluton) se determin m rimea acestuia reµinâdu-se acesta
dac e cel mai numeros g sit pân în acel moment sau contorizându-l dac num rul de soldaµi
determinat este egal cu cel maxim determinat anterior.
Soluµia 2:
citesc numerele de identicare în vectorul a[]
construiesc 2 vectori ajut tori
a vectorul b[] care va conµine num rul de cifre al ec rui element
a vectorul c[] care va conµine num rul de cifre distincte a ec rui element
ordonez cei trei vectori cresc tor dup num rul de cifre distincte (dup c[]) ³i dup num rul
de cifre, deci cheia de sortare va un num r construit dup formula c[i]*10+b[i]
formez ³i num r plutoanele; plutoanele le voi reµine pe linii distincte a matricei G[MAX][2]
a în ecare linie, elementul G[i][0] va conµine num rul de elemente din pluton
a elementul G[i][1] va conµine reprezentantul plutonului, primul care apare în a[]
a repet pân când toate elementele din a au fost vericate
reµinem primul element nepus înc din pluton cu caracteristicile lui
CAPITOLUL 14. OJI 2006 CLASA A IX-A 210
veric elementele cu acelea³i caracteristici s fac parte din acela³i pluton cu primul
element din pluton pe care l-am reµinut
testez dac are acelea³i cifre
· dac nu are acelea³i cifre trec mai departe
· altfel îl numar (înc face parte din acela³i pluton)
detectez num rul maxim de elemente ale unui pluton ³i reµin maximul
a³are cerinµele 1 2 3 folosind valorile aate
la cerinµa 4
caut in a[] reprezentantul unui pluton numeros
a³ez cele maxe elemente - în vectorul sortat elementele cu acelea³i caracteristici (b ³i c)
sunt unul dup altul, dar mai trebuie vericat s aib caracteristicile reprezentantului
(ex. 1212 ³i 3434 au acelea³i caracteristici (4,2), (4,2), dar nu fac parte din acela³i
pluton)
Soluµia 3:
se utilizeaza notiunea de lista: dintr-o lista fac parte toti membrii unui pluton
se construieste un vector ajutator care retine pentru ecare element elementul care il urmeaza
in lista
pe parcursul formarii listelor se determina lista cea mai numeroasa precum si numarul de
liste de acest tip
asarea se face utilizand informatiile din vetorul urm
31 while (x)
32 {
33 c[x%10]++;
34 x/=10;
35 }
36 }
37
38 void Citire(void)
39 {
40 int i, j;
41 long x;
42
43 fscanf(Fin, "%ld", &n);
44 for (i=1; i<=n; i++)
45 {
46 fscanf(Fin, "%ld", &a[i]);
47 /*construiesc 2 vectori ajutatori
48 - vectorul b care va contine numarul de cifre al fiecarui element
49 - vectorul c care va contine numarul de cifre distincte a fiecarui element*/
50 for (j=0; j<=9; j++) cifre[j]=0;
51 x=a[i];
52 while (x)
53 {
54 b[i]++; //numar total de cifre
55 cifre[x%10]=1;
56 x/=10;
57 }
58 for (j=0; j<=9; j++)
59 c[i]+=cifre[j]; //numar de cifre distincte
60 }
61 }
62
63 void Sortare(void)
64 {
65 int i, j;
66 long min, pm, x, aux;
67
68 /*ordonez cei trei vectori crescator dupa numarul de cifre (dupa b)
69 si dupa numarul de cifre distincte, deci cheia de sortare va fi un numar
70 construit dupa formula b[i]*10+c[i] */
71 for (i=1; i<=n-1; i++)
72 {
73 min=b[i]*10+c[i]; pm=i;
74 for (j=i+1; j<=n; j++)
75 {
76 x=b[j]*10+c[j];
77 if (x<min)
78 {
79 min=x; pm=j;
80 }
81 }
82
83 aux=c[i]; c[i]=c[pm]; c[pm]=aux;
84 aux=b[i]; b[i]=b[pm]; b[pm]=aux;
85 aux=a[i]; a[i]=a[pm]; a[pm]=aux;
86 }
87 }
88
89 void FormarePlutoane(void)
90 {
91 int i, j;
92
93 /*formez si numar plutoanele
94 - plutoanele le voi retine pe linii distincte a matricii G
95 - in fiecare linie, elementul 0 va contine numarul de elemente din pluton
96 iar elementul 1 reprezentantul plutonului, primul care apare in a*/
97 while (!ToatePuse())
98 {
99 i=1;
100 while (Pus[i]) i++; //caut primul nepus inca
101
102 //retinem primul element nepus din pluton cu caracteristicile lui
103 btest=b[i]; ctest=c[i];
104 NrG=NrG+1; G[NrG][0]=1;
105 G[NrG][1]=a[i]; Pus[i]=TRUE; //il pun in pluton
106 Cifrele(a[i], cifreTest); //retin cifrele in cifreTest[]
CAPITOLUL 14. OJI 2006 CLASA A IX-A 212
107
108 //verific elementele cu aceleasi caracteristici daca fac parte din
109 //acelasi pluton cu primul element pe care l-am retinut
110 i++;
111 while ((b[i]==btest) && (c[i]==ctest) && (i<=n))
112 { //ar putea face parte din acelasi pluton
113 Cifrele(a[i], cifre);//aflu cifrele in cifre[]
114 OK=TRUE; //testez daca are aceleasi cifre
115 for (j=0; j<=9; j++)
116 if (cifreTest[j]!=cifre[j]) OK=FALSE;
117 if (OK) //are aceleasi cifre
118 {
119 G[NrG][0]++; //un nou soldat in pluton
120 Pus[i]=TRUE; //l-am pus
121 }
122 i++;
123 }
124 }
125 }
126
127 void Afisare(void)
128 {
129 int i, j;
130 long x;
131
132 fprintf(Fout, "%ld\n", NrG); //cerinta 1
133
134 maxe=0; //determin numarul maxim de elemente ale unui pluton
135 for (i=1; i<=n; i++)
136 if (G[i][0]>maxe)
137 {
138 maxe=G[i][0];
139 x=G[i][1]; //retin reprezentantul plutonului numeros
140 }
141
142 fprintf(Fout, "%ld\n", maxe); //cerinta 2
143
144 Nre=0;
145 for (i=1; i<=NrG; i++)
146 if (G[i][0]==maxe)
147 Nre++;
148
149 fprintf(Fout, "%ld\n", Nre); //cerinta 3
150
151 i=1;
152 while (x!=a[i]) i++; //il caut in a
153 fprintf(Fout, "%ld ", a[i]); //scriu reprezentantul plutonului
154 btest=b[i]; ctest=c[i]; //retin caracteristicile
155 Cifrele(a[i], cifreTest); //aflu cifrele
156
157 i++; //cerinta 4
158
159 while ((b[i]==btest) && (c[i]==ctest) && (i<=n))
160 { //ar putea face parte din acelasi pluton
161 Cifrele(a[i], cifre); //aflu cifrele
162 OK=TRUE; //testez daca are aceleasi cifre
163 for (j=0; j<=9; j++)
164 if (cifreTest[j]!=cifre[j]) OK=FALSE;
165 if (OK) //are aceleasi cifre
166 fprintf(Fout, "%ld ", a[i]); //il afisez
167 i++;
168 }
169
170 fprintf(Fout, "\n");
171 }
172
173 int main(void)
174 {
175 Fin=fopen("pluton.in", "rt"); //deschid fisierul ’pluton.in’ pentru citire
176 Fout=fopen("pluton.out", "wt");//deschid fisierul ’pluton.out’ pentru scriere
177 Citire();
178 Sortare();
179 FormarePlutoane();
180 Afisare();
181 fclose(Fin);
182 fclose(Fout);
CAPITOLUL 14. OJI 2006 CLASA A IX-A 213
183 return 0;
184 }
34 return y;
35 }
36
37 int main()
38 {
39 long i,j,p,pmax;
40 long aux;
41 fstream f;
42
43 f.open("pluton.in",ios::in);
44 f>>n; //se citesc din fisierul pluton.in numarul n si
45 for(i=1;i<=n;i++) //elementele vectorului Nr si se completeaza valorile
46 { //corespunzatoare in vectorul NrSort
47 f>>Nr[i];
48 NrSort[i]=SortareCifre(Nr[i]);
49 }
50 f.close();
51
52 i=1; //pozitia curenta din vectori Nr si NrSort(soldatul curent i)
53 nrp=nrmax=maxx=0;
54 while(i<=n)
55 {
56 p=i; //se salveaza pozitia curenta i in variabila p
57 j=i+1; //se cauta soldati j din acelasi pluton cu soldatul curent i
58 while(j<=n) //adica soldati pentru care NrSort[j]=NrSort[i]
59 {
60 if(NrSort[i]==NrSort[j]) //in cazul in care se gaseste un astfel de soldat
61 { //acesta este adus langa soldatul curent i
62 i++;
63 aux=Nr[i]; Nr[i]=Nr[j]; Nr[j]=aux;
64 aux=NrSort[i]; NrSort[i]=NrSort[j]; NrSort[j]=aux;
65 }
66 j++;
67 }
68
69 i++; //s-au adus langa soldatul i toti posibilii sai colegi de pluton
70 nrp++; //deci s-a mai refacut un pluton intre pozitiile p si i-1 din
71 //cei doi vectori Nr si NrSort
72
73 if(i-p>maxx) //daca numarul de soldati din ultimul pluton refacut (adica i-p)
74 { //este mai mare strict decat max se actualizeaza valorile
75 maxx=i-p; //variabilelor max si nrmax
76 nrmax=1;
77 pmax=p; //pmax retine pozitia la care incepe in vectorul Nr plutonul
78 } //cu numar maxim de soldati
79 else
80 if(i-p==maxx) nrmax++; //daca numarul de soldati din ultimul pluton refacut
81 } //este egal cu max se actualizeaza valoarea lui nrmax
82
83 f.open("pluton.out",ios::out); //se scriu in fisierul pluton.out rezultatele
84 f<<nrp<<endl<<maxx<<endl<<nrmax<<endl;
85 for(i=pmax;i<pmax+maxx;i++) f<<Nr[i]<<" ";
86 f.close();
87
88 return 0;
89 }
Solutie incorect pentru Borland C++ 3.1 dar care ia 100 puncte !!!
11
12 static long cifre(long nr) // 1230456789 --> 9.876.543.210 !!!
13 {
14 int i,j,k,nc=0;
15 long nrcd=0; // nr cu cifre descrescatoare
16
17 for(i=0;i<=9;i++) fc[i]=0;
18 for(i=0;i<=10;i++) x[i]=0;
19
20 while(nr!=0) { fc[(int)(nr%10)]++; nr=nr/10; nc++; }
21
22 k=0;
23 for(i=9;i>=0;i--)
24 if(fc[i]!=0)
25 for(j=1;j<=fc[i];j++) { k++; x[k]=i; }
26
27 for(i=1;i<=nc;i++) nrcd=nrcd*10+x[i];
28 return nrcd;
29 }// cifre(...)
30
31 public static void main(String[] args) throws IOException
32 {
33 int i,j;
34 int max,npmax,pmax;
35
36 StreamTokenizer st=new StreamTokenizer(
37 new BufferedReader(new FileReader("9-pluton.in")));
38 PrintWriter out=new PrintWriter(
39 new BufferedWriter(new FileWriter("pluton.out")));
40
41 st.nextToken(); n=(int)st.nval;
42 for(i=1;i<=n;i++) {st.nextToken(); ni[i]=(int)st.nval;}
43
44 for(i=1;i<=n;i++) nid[i]=cifre(ni[i]);
45
46 np=0;
47 for(i=1;i<=n;i++)
48 {
49 if(nip[i]!=0) continue;
50 np++;
51 nip[i]=np;
52 for(j=i+1;j<=n;j++)
53 if(nip[j]==0)
54 if(nid[j]==nid[i]) nip[j]=np;
55 }
56
57 out.println(np);
58
59 for(i=1;i<=np;i++)
60 for(j=1;j<=n;j++) if(nip[j]==i) z[i]++;
61
62 max=0;
63 npmax=0;
64 pmax=0;
65
66 for(i=1;i<=np;i++) if(z[i]>max) {max=z[i];pmax=i;}
67 out.println(max);
68
69 for(i=1;i<=np;i++) if(z[i]==max) npmax++;
70 out.println(npmax);
71
72 for(i=1;i<=n;i++) if(nip[i]==pmax) out.print(ni[i]+" ");
73
74 out.println();
75 out.close();
76 }// main
77 }// class
15.1 Numere
Doru Popescu Anastasiu
Mircea este pasionat de programare. El a început s rezolve probleme din ce în ce mai
grele. Astfel a ajuns la o problem , care are ca date de intrare un tablou p tratic cu n linii ³i
2
n coloane, componente tabloului ind toate numerele naturale distincte de la 1 la n . Pentru a
verica programul pe care l-a scris îi trebuie un ³ier care s conµin tabloul respectiv. Dup ce a
creat acest ³ier, fratele s u, pus pe ³otii îi umbl în ³ier ³i îi schimb câteva numere consecutive,
cu num rul 0. Când se întoarce Mircea de la joac constat cu stupoare c nu îi merge programul
pentru testul respectiv. Dup câteva ore de depanare î³i d seama c programul lui este corect ³i
c ³ierul de intrare are probleme.
Cerinµ
Scrieµi un program care s -l ajute pe Mircea, g sindu-i cel mai mic ³i cel mai mare dintre
numerele consecutive schimbate de fratele s u.
Date de intrare
În ³ierul numere.in se d pe prima linie n, iar pe urm toarele n linii elementele tabloului,
câte n elemente pe o linie, separate între ele prin câte un spaµiu, dup modic rile f cute de fratele
lui Mircea.
Date de ie³ire
În ³ierul numere.out se va scrie pe un singur rând cu un singur spaµiu între ele numerele
cerute (primul ind cel mai mic).
Restricµii ³i preciz ri
a 0 $ n & 500.
a Fratele lui Mircea schimb cel puµin un num r în ³ier.
a Numerele schimbate de fratele lui Mircea sunt mai mici sau cel mult egale cu 60000.
Exemplu
numere.in numere.out Explicaµie
3 24 În ³ierul de intrare au fost înlocuite cu 0
507 numerele 2, 3, 4.
001
698
Timp maxim de execuµie: 1 secund /test
Soluµia ocial
Se folose³te un vector cu componente 0 sau 1, x x1 , ..., xm , unde m este 64000 dac
2 2
num rul de componente al tabloului (n ) este mai mare decât 64000, respectiv m n în cel lalt
caz.
Iniµial vectorul x are toate componentele 0. Pe m sur ce se citesc numere v din ³ier, com-
ponentele corespunz toare din x se schimb în 1 (xv 1).
218
CAPITOLUL 15. OJI 2005 CLASA A IX-A 219
Dup citirea numerelor din ³ier se obµine în x o secvenµ de 0. Indicii corespunz tori acestei
secvenµe formeaz mulµimea de numere consecutive care au fost înlocuite cu 0 de fratele lui Mircea.
O alt modalitate de rezolvare const în calculul sumei tuturor numerelor din tablou ³i obµi-
nerea astfel a sumei secvenµei de numere consecutive ³terse de Mircea. Din p cate sumele sunt
prea mari ³i dep ³esc tipurile predenite. Dac se folosesc implement ri pe numere mari se obµine
punctajul maxim, altfel doar jum tate din punctaj.
Soluµie prezentat în GInfo nr. 15/3
Pentru rezolvarea acestei probleme este sucient s utiliz m un ³ir de biµi care vor indica dac
un num r apare sau nu în ³ier.
Vom avea nevoie întotdeauna de cel mult 250.000 de biµi, deci 31250 de octeµi.
Iniµial toµi biµii vor avea valoarea 0, iar pe m sur ce sunt citite numerele care formeaz
matricea, valoarea bitului corespunz tor unui num r citit devine 1.
irul de biµi va conµine în nal o secvenµ de zerouri care va reprezenta soluµia problemei.
Exist ³i posibilitatea de a utiliza heap-ul pentru a p stra 250.000 de valori booleene sau întregi
care vor permite ³i ele determinarea secvenµei care lipse³te.
15.2 MaxD
Maria ³i Adrian Niµ
Fiind elev în clasa a IX-a, George, î³i propune s studieze capitolul divizibilitate cât mai
bine. Ajungând la num rul de divizori asociat unui num natural, constat c sunt numere într-un
interval dat, cu acela³i num r de divizori.
De exemplu, în intervalul 1, 10, 6, 8 ³i 10 au acela³i num r de divizori, egal cu 4. De asemenea,
4 ³i 9 au acela³i num r de divizori, egal cu 3 etc.
Cerinµ
Scrieµi un program care pentru un interval dat determin care este cel mai mic num r din
interval ce are num r maxim de divizori. Dac sunt mai multe numere cu aceast proprietate se
cere s se numere câte sunt.
Date de intrare
Fi³ierul de intrare maxd.in conµine pe prima linie dou numere a ³i b separate prin spaµiu
(a & b) reprezentând extremit µile intervalului.
Date de ie³ire
Fi³ierul de ie³ire maxd.out va conµine pe prima linie trei numere separate prin câte un spaµiu
min nrdiv contor cu semnicaµia:
min = cea mai mic valoare din interval care are num r maxim de divizori
nrdiv = num rul de divizori ai lui min
contor = câte numere din intervalul citit mai au acela³i num r de divizori egal cu nrdiv
Restricµii ³i preciz ri
a 1 & a & b & 1.000.000.000
a 0 & b a & 10.000
Punctaj
Dac aµi determinat corect min, obµineµi 50% din punctaj.
CAPITOLUL 15. OJI 2005 CLASA A IX-A 221
Varianta 1:
6
7 public static void main(String[] args) throws IOException
8 {
9 int i;
10 long t1,t2;
11 t1=System.currentTimeMillis();
12 StreamTokenizer st=new StreamTokenizer(
13 new BufferedReader(new FileReader("maxd.in")));
14 st.nextToken(); a=(int)st.nval;
15 st.nextToken(); b=(int)st.nval;
16 x=new int[b-a+2];
17 for(i=a;i<=b;i++) x[i-a+1]=descfact(i);
18 int max=-1;
19 int imax=-1;
20 for(i=1;i<=b-a+1;i++)
21 if(x[i]>max) { max=x[i]; imax=i; }
22 int nrmax=0;
23 for(i=1;i<=b-a+1;i++) if(x[i]==max) nrmax++;
24
25 PrintWriter out=new PrintWriter(
26 new BufferedWriter(new FileWriter("maxd.out")));
27 out.println((imax+a-1)+" "+max+" "+nrmax);
28 out.close();
29 t2=System.currentTimeMillis();
30 System.out.println("Timp = "+(t2-t1));
31 }
32
33 static int descfact(int nr)
34 {
35 int d;
36 int nrd;
37 int p=1;
38
39 d=2;
40 nrd=0;
41 while(nr%d==0) { nrd++; nr=nr/d; }
42 p=p*(nrd+1);
43
44 d=3;
45 while(d*d<=nr)
46 {
47 nrd=0;
48 while(nr%d==0) { nrd++; nr=nr/d; }
49 p=p*(nrd+1);
50 d=d+2;
51 }
52 if(nr>1) p*=2;
53 return p;
54 }
55 }
Varianta 2:
21 int nd;
22
23 for(i=a;i<=b;i++)
24 {
25 nd=nrDiv(i);
26 if(nd>max) {max=nd; imax=i; nrmax=1;}
27 else if(nd==max) nrmax++;
28 }
29
30 PrintWriter out=new PrintWriter(
31 new BufferedWriter(new FileWriter("maxd.out")));
32 out.println(imax+" "+max+" "+nrmax);
33 out.close();
34 t2=System.currentTimeMillis();
35 System.out.println("Timp = "+(t2-t1));
36 }// main(...)
37
38 static int nrDiv(int nr)
39 {
40 int d;
41 int nrd;
42 int p=1;
43
44 d=2;
45 nrd=0;
46 while(nr%d==0) { nrd++; nr=nr/d; }
47 p=p*(nrd+1);
48
49 d=3;
50 while(d*d<=nr)
51 {
52 nrd=0;
53 while(nr%d==0) { nrd++; nr=nr/d; }
54 p=p*(nrd+1);
55
56 d=d+2;
57 }
58
59 if(nr>1) p*=2;
60 return p;
61 }// nrDiv(...)
62 }// class
Capitolul 16
16.1 Expresie
Se d un ³ir de n numere naturale nenule x1 , x2 , ..., xn ³i un num r natural m.
Cerinµ
Ó
S se verice dac valoarea expresiei m x1 ...xn exte un num r natural.
În caz armativ s se a³eze acest num r descompus în factori primi.
Date de intrare
În ³ierul exp.in se a pe prima linie m, pe linia a doua n, iar pe linia a treia numerele
x1 , x2 , ..., xn separate între ele prin câte un spaµiu.
Date de ie³ire
În ³ierul exp.out se va scrie pe prima linie cifra 0, dac valoarea expresiei nu este un num r
natural, respectiv 1 dac este un num r natural. Dac valoarea expresiei este un num r natural pe
urm toarele linii se vor scrie perechi de forma p e (p este factor prim care apare în descompunere
la puterea e ' 1). Aceste perechi se vor scrie în ordine cresc toare dup primul num r (adic p).
Restricµii ³i preciz ri
a n - num r natural nenul $ 5000
a xi - num r natural nenul $ 30000, i " 1, 2, ..., n
a m - poate una din cifrele 2, 3, 4
Exemple
exp.in exp.out exp.in exp.out
2 0 2 1
4 4 24
32 81 100 19 32 81 100 18 33
51
Timp maxim de execuµie: 1 secund /test
224
CAPITOLUL 16. OJI 2004 CLASA A IX-A 225
Dac toate elementele îndeplinesc aceast condiµie, expresia este un num r natural ³i se trece
la a³are.
Se poate renunµa la vectorul de 30000 de elemente, p strându-se în locul acestuia un vector
în care se memoreaz numerele prime mai mici decât 30000 ³i un vector care arat la ce puteri
apar aceste numere în descompunere. Aceast abordare introduce în plus operaµii pentru a g si
indicele unui anumit num r prim; se poate folosi cu succes c utarea binar . Pe de alt parte, la
descompunerea în factori primi se va testa numai împ rµirea prin numere prime.
Analiza complexit µii Ó
Descompunerea unui num r x în factori primi are ordinul de complexitate O x, dac nu se
folose³te lista de numere prime.
Ó Pasul de descompunere ³i completare a vectorului P are deci ordinul de complexitate O n
30000.
Citirea datelor, vericarea dac expresia este un num r natural ³i a³area au ordinul de com-
plexitate O n.
În concluzie, ordinul de complexitate
Ó al algoritmului de rezolvare a acestei probleme este O n,
dac facem abstracµie de constanta 30000.
44 begin
45 inc(dp);
46 p[dp] := i;
47 end;
48 i := i+2;
49 end;
50 end;
51
52 begin
53 cit;
54 prime;
55
56 for i := 1 to dp do
57 f[i] := 0;
58 for i := 1 to n do
59 begin
60 j := 1;
61 while x[i]<>1 do
62 begin
63 while x[i] mod p[j]=0 do
64 begin
65 inc(f[j]);
66 x[i] := x[i] div p[j];
67 end;
68 inc(j);
69 end;
70 end;
71 sw := true;
72 for i := 1 to dp do
73 if f[i] mod m<>0 then
74 begin
75 sw := false;
76 break;
77 end;
78
79 assign(ff, ’exp.out’); rewrite(ff);
80 if not sw then
81 writeln(ff, 0)
82 else
83 begin
84 writeln(ff, 1);
85 for i := 1 to dp do
86 if f[i]>0 then
87 writeln(ff, p[i], ’ ’, f[i] div m);
88 end;
89 close(ff);
90 end.
Prima variant :
A doua variant :
43 while(x[i]!=1)
44 {
45 while(x[i]%p[j]==0) { e[j]++; x[i]/=p[j]; }
46 j++;
47 }
48 }
49 ok=true;
50 for(i=1;i<=nnp;i++)
51 if(e[i]%m==0) e[i]=e[i]/m; else {ok=false; break;}
52 }
53
54 static void prime()
55 {
56 int i,j;
57 p[1]=2; p[2]=3; nnp=2;
58 i=5;
59 while(i<valmax)
60 {
61 if(estePrim(i)) p[++nnp]=i;
62 i+=2;
63 }
64 }
65
66 static boolean estePrim(int nr) // folosind lista numerelor prime !
67 {
68 int i=1;
69 while((p[i]*p[i]<nr)&&(nr%p[i]!=0)) i++;
70 if(p[i]*p[i]>nr) return true; return false;
71 }
72 }
A treia variant :
42 ok=true;
43 for(i=0;i<nf;i++)
44 if(e[i]%m==0) e[i]=e[i]/m; else {ok=false; break;}
45 }
46
47 static void interclasare() // (f cu ff) SI (e cu ee)
48 {
49 int i;
50 if(nf==0)
51 {
52 int[] ff=new int[nfc], ee=new int[nfc];
53 for(i=0;i<nfc;i++) {ff[i]=fc[i]; ee[i]=ec[i];}
54 f=ff; e=ee; nf=nfc; return;
55 }
56 int j, nft=nf+nfc,n;
57 int[] ff=new int[nft], ee=new int[nft];
58 i=0; j=0; n=0; // primul indice in care incarc este 0=zero !!!
59 while((i<nf)&&(j<nfc))
60 {
61 n++;
62 if(f[i]<fc[j])
63 {
64 ff[n-1]=f[i];
65 ee[n-1]=e[i];
66 i++;
67 }
68 else if(f[i]>fc[j])
69 {
70 ff[n-1]=fc[j];
71 ee[n-1]=ec[j];
72 j++;
73 }
74 else
75 {
76 ff[n-1]=f[i];
77 ee[n-1]=e[i]+ec[j];
78 i++; j++;
79 }
80 }
81 while(i<nf) {n++; ff[n-1]=f[i]; ee[n-1]=e[i]; i++;}
82 while(j<nfc) {n++; ff[n-1]=fc[j]; ee[n-1]=ec[j]; j++;}
83 if(n==nft) {f=ff; e=ee; nf=n;}
84 else
85 {
86 int[] fff=new int[n], eee=new int[n];
87 for(i=0;i<n;i++) {fff[i]=ff[i]; eee[i]=ee[i];}
88 f=fff; e=eee; nf=n;}
89 }
90
91 static void descfact(int nr)
92 {
93 // if((nr==0)||(nr==1)) return nr;
94 nfc=0;
95 int d=2;
96 if(nr%d==0)
97 {
98 nfc++; fc[nfc-1]=d; ec[nfc-1]=0;
99 while(nr%d==0) {ec[nfc-1]++; nr=nr/d;}}
100 d=3;
101 while((d*d<=nr)&&(nr!=1))
102 {
103 if(nr%d==0)
104 {
105 nfc++;
106 fc[nfc-1]=d;
107 ec[nfc-1]=0;
108 while(nr%d==0) {ec[nfc-1]++; nr=nr/d;}
109 }
110 d=d+2;
111 }
112 if(nr!=1) {nfc++; fc[nfc-1]=nr; ec[nfc-1]=1;}
113 }// descfact
114 }//class
CAPITOLUL 16. OJI 2004 CLASA A IX-A 230
16.2 Reactivi
Într-un laborator de analize chimice se utilizeaz N reactivi.
Se ³tie c , pentru a evita accidentele sau deprecierea reactivilor, ace³tia trebuie s e stocaµi
în condiµii de mediu speciale. Mai exact, pentru ecare reactiv x, se precizeaz intervalul de
temperatur minx , maxx în care trebuie s se încadreze temperatura de stocare a acestuia.
Reactivii vor plasaµi în frigidere.
Orice frigider are un dispozitiv cu ajutorul c ruia putem stabili temperatura (constant ) care
va în interiorul acelui frigider (exprimat într-un num r întreg de grade Celsius).
Cerinµ
Scrieµi un program care s determine num rul minim de frigidere necesare pentru stocarea
reactivilor chimici.
Date de intrare
Fi³ierul de intrare react.in conµine:
pe prima linie num rul natural N , care reprezint num rul de reactivi;
pe ecare dintre urm toarele N linii se a min max (dou numere întregi separate printr-un
spaµiu); numerele de pe linia x 1 reprezint temperatura minim , respectiv temperatura maxim
de stocare a reactivului x.
Date de ie³ire
Fi³ierul de ie³ire react.out va conµine o singur linie pe care este scris num rul minim de
frigidere necesar.
Restricµii ³i preciz ri
a 1&N & 8000
a 100 & minx & maxx & 100 (numere întregi, reprezentând grade Celsius), pentru orice x de
la 1 la N
a un frigider poate conµine un num r nelimitat de reactivi
Exemple
react.in react.out react.in react.out react.in react.out
3 2 4 3 5 2
-10 10 25 -10 10
-25 57 10 12
20 50 10 20 -20 10
30 40 7 10
78
Timp maxim de execuµie: 1 secund /test
Facem o prim observaµie: pentru orice soluµie optim exist o soluµie cu acela³i num r de
puncte (frigidere), în care ecare punct s e sfâr³itul unui interval. Aceasta se poate obµine
mutând ecare punct spre dreapta, pân când ar ajunge la sfâr³itul intervalului care se termin
cel mai repede, dintre intervalele care îl conµin. Se observ c noua soluµie respect restricµiile din
enunµ.
În continuare ne vom concentra pe g sirea unei soluµii de acest tip.
Sort m reactivii dup sfâr³itul intervalului. Pentru intervalul care se termin cel mai repede,
alegem ultimul punct al s u ca temperatur a unui frigider. Se observ c aceast alegere este
cea mai bun , dintre toate alegerile unui punct în intervalul respectiv, în sensul c mulµimea
intervalelor care conµin punctul este mai mare (conform relaµiei de incluziune), decât mulµimea
corespunz toare oric rei alte alegeri. Acest fapt este adev rat, deoarece mutarea punctului mai la
stânga nu duce la selectarea unor noi intervale.
CAPITOLUL 16. OJI 2004 CLASA A IX-A 231
Intervalele care conµin punctul respectiv sunt eliminate (reactivii corespunz tori pot plasaµi
într-un frigider), iar procesul continu cu intervalele r mase, în acela³i mod.
Analiza complexit µii
Not m cu D num rul de temperaturi întregi din intervalul care conµine temperaturile din
enunµ. Se observ c D este cel mult 201.
Citirea datelor de intrare are ordinul de complexitate O N .
Sortarea intervalelor dup cap tul din dreapta are ordinul de complexitate O N logN .
Urmeaz F pa³i, unde F este num rul de frigidere selectate. Deoarece ecare frigider este
setat la o temperatur întreag , F & D.
În cadrul unui pas, determinarea intervalului care se termin cel mai repede, pe baza vectorului
sortat, are ordinul de complexitate O 1. Eliminarea intervalelor care conµin un anumit punct
(sfâr³itul intervalului care se termin cel mai repede) are ordinul de complexitate O N .
A³area rezultatului are ordinul de complexitate O 1.
În concluzie, ordinul de complexitate al algoritmului de rezolvare a acestei probleme este O N
D N logN ; deoarece în general D % logN , consider m ordinul de complexitate ca ind O N D.
45 End;
46 End;
47
48 Procedure Intersectie(j: Integer; min, max: ShortInt);
49 Begin
50 f[j].min := Maxim(min, f[j].min);
51 f[j].max := Minim(max, f[j].max)
52 End;
53
54 procedure QuickSortCresc(Lo, Hi: Integer);
55
56 procedure Sort(Stanga, Dreapta: Integer);
57 var i, j, x: integer;
58 y: Frigider;
59 begin
60 i := Stanga; j := Dreapta; x := r[(Stanga+Dreapta) DIV 2].min;
61 repeat
62 while r[i].min < x do i := i + 1;
63 while x < r[j].min do j := j - 1;
64 if i <= j then
65 begin
66 y := r[i]; r[i] := r[j]; r[j] := y;
67 i := i + 1; j := j - 1;
68 end;
69 until i > j;
70 if Stanga < j then Sort(Stanga, j);
71 if i < Dreapta then Sort(i, Dreapta);
72 end;
73
74 begin {QuickSort};
75 Sort(Lo,Hi);
76 end;
77
78 procedure QuickSortDescresc(Lo, Hi: Integer);
79
80 procedure Sort(Stanga, Dreapta: Integer);
81 var i, j, x: integer;
82 y: Frigider;
83 begin
84 i := Stanga; j := Dreapta; x := r[(Stanga+Dreapta) DIV 2].max;
85 repeat
86 while r[i].max > x do i := i + 1;
87 while x > r[j].max do j := j - 1;
88 if i <= j then
89 begin
90 y := r[i]; r[i] := r[j]; r[j] := y;
91 i := i + 1; j := j - 1;
92 end;
93 until i > j;
94 if Stanga < j then Sort(Stanga, j);
95 if i < Dreapta then Sort(i, Dreapta);
96 end;
97
98 begin {QuickSort};
99 Sort(Lo,Hi);
100 end;
101
102 Begin
103 Assign(Fisier, ’reactivi.in’); Reset(Fisier);
104 ReadLn(Fisier, N);
105 For i := 1 To N Do
106 ReadLn(Fisier, r[i].min, r[i].max);
107 Close(Fisier);
108
109 QuickSortCresc(1, N);
110
111 i := 1; j := i+1;
112 While j<=N Do
113 Begin
114 While (r[j].min=r[i].min) And (j<=N) Do Inc(j);
115 QuickSortDescresc(i, j-1);
116 i := j; j := i+1
117 End;
118
119 f[1].min := r[1].min; f[1].max := r[1].max; Cate := 1;
120 For i := 2 To N Do
CAPITOLUL 16. OJI 2004 CLASA A IX-A 233
121 Begin
122 min := r[i].min; max := r[i].max;
123 j := Cauta(min, max);
124 If j>0 Then
125 Intersectie(j, min, max)
126 Else
127 Begin
128 Inc(Cate);
129 f[Cate].min := min;
130 f[Cate].max := max
131 End
132 End;
133 Assign(Fisier, ’reactivi.out’); ReWrite(Fisier);
134 WriteLn(Fisier, Cate);
135 Close(Fisier)
136 End.
30 Begin
31 Cauta := -1;
32 For i := 1 To Cate Do
33 Begin
34 If (f[i].max>=min) And (f[i].max<=max) Then
35 Begin Cauta := i; Break End
36 Else
37 If (f[i].min>=min) And (f[i].min<=max) Then
38 Begin Cauta := i; Break End
39 Else
40 If (f[i].min<=min) And (f[i].max>=max) Then
41 Begin Cauta := i; Break End
42 Else
43 If (f[i].max<min) Or (f[i].min>max) Then
44 Cauta := -1
45 End;
46 End;
47
48 Procedure Intersectie(j: Integer; min, max: ShortInt);
49 Begin
50 f[j].min := Maxim(min, f[j].min);
51 f[j].max := Minim(max, f[j].max)
52 End;
53
54 Procedure Ordoneaza;
55 Var i, j, ptmin: Integer;
56 tmax, tmin: ShortInt;
57 Begin
58 For i := 1 To N-1 Do
59 Begin
60 tmin := r[i].min; tmax := r[i].max; ptmin := i;
61 For j := i+1 To N Do
62 If r[j].min<tmin Then
63 Begin
64 tmax := r[j].max; tmin := r[j].min; ptmin := j
65 End
66 Else
67 If r[j].min=tmin Then
68 If r[j].max>tmax Then
69 Begin
70 tmax := r[j].max; tmin := r[j].min; ptmin := j
71 End;
72 r[ptmin].min := r[i].min; r[ptmin].max := r[i].max;
73 r[i].min := tmin; r[i].max := tmax
74 End
75 End;
76
77
78 Begin
79 Assign(Fisier, ’reactivi.in’); Reset(Fisier);
80 ReadLn(Fisier, N);
81 For i := 1 To N Do
82 ReadLn(Fisier, r[i].min, r[i].max);
83 Ordoneaza;
84 f[1].min := r[1].min; f[1].max := r[1].max; Cate := 1;
85 For i := 2 To N Do
86 Begin
87 min := r[i].min; max := r[i].max;
88 j := Cauta(min, max);
89 If j>0 Then
90 Intersectie(j, min, max)
91 Else
92 Begin
93 Inc(Cate);
94 f[Cate].min := min;
95 f[Cate].max := max
96 End
97 End;
98 Close(Fisier);
99 Assign(Fisier, ’reactivi.out’); ReWrite(Fisier);
100 WriteLn(Fisier, Cate);
101 Close(Fisier)
102 End.
CAPITOLUL 16. OJI 2004 CLASA A IX-A 236
17.1 Text
Vasile lucreaz intens la un editor de texte. Un text este format din unul sau mai multe
paragrafe. Orice paragraf se termin cu Enter ³i oricare dou cuvinte consecutive din acela³i
paragraf sunt separate prin spaµii (unul sau mai multe). În funcµie de modul de setare a paginii,
num rul maxim de caractere care încap în pagin pe o linie este unic determinat (Max).
Funcµia pe care Vasile trebuie s o implementeze acum este alinierea în pagin a ec rui
paragraf din text la stânga ³i la dreapta. Pentru aceasta el va trebui s împart ecare paragraf
în linii separate de lungime Max (ecare linie terminat cu Enter).
Împ rµirea se realizeaz punând num rul maxim posibil de cuvinte pe ecare linie, f r împ r-
µirea cuvintelor în silabe.
Pentru aliniere stânga-dreapta, Vasile trebuie s repartizeze spaµii în mod uniform între cu-
vintele de pe ecare linie, astfel încât ultimul caracter de pe linie s e diferit de spaµiu, iar
num rul total de caractere de pe linie s e egal cu Max. Excepµie face numai ultima linie din
paragraf, care r mâne aliniat la stânga (cuvintele ind separate printr-un singur spaµiu, chiar
dac linia nu este plin ).
În general, este puµin probabil ca alinierea s e realizabil prin plasarea aceluia³i num r de
spaµii între oricare dou cuvinte consecutive de pe linie. Vasile consider c este mai elegant ca,
dac între unele cuvinte consecutive trebuie plasat un spaµiu în plus faµ de alte perechi de cuvinte
consecutive, acestea s e plasate la începutul liniei.
Cerinµ
Scrieµi un program care s citeasc lungimea unei linii ³i textul dat ³i care s alinieze textul la
stânga ³i la dreapta.
Date de intrare
Fi³ierul de intrare text.in conµine pe prima linie Max, lungimea maxim a unui rând. Pe
urm toarele linii este scris textul.
Date de ie³ire
Fi³ierul de ie³ire text.out conµine textul aliniat stânga-dreapta.
Restricµii ³i preciz
uri
a 2 & Max & 1000.
a Lungimea maxim a oric rui cuvânt din text este 25 caractere ³i nu dep ³e³te Max.
a Lungimea unui paragraf nu dep ³e³te 1000 de caractere.
a Soluµia este unic .
Exemple
text.in text.out
20 Vasile are multe
Vasile are multe bomboane bune. bomboane bune.
Explicaµie
Pe prima linie au fost plasate câte 3 spaµii între cuvintele consecutive.
237
CAPITOLUL 17. OJI 2003 CLASA A IX-A 238
text.in text.out
20 Ana are mere.
Ana are mere. Ion are multe pere
Ion are multe pere galbene? galbene?
Explicaµie
Între Ion ³i are exist 2 spaµii, între are ³i multe - 2 spaµii, iar între multe ³i pere - 1 spaµiu.
Observaµi c paragraful Ana are mere. (care are lungimea mai mic decât 20) a r mas aliniat
la stânga, iar ultima linie din ecare paragraf r mâne aliniat la stânga, cuvintele consecutive
ind separate printr-un singur spaµiu.
Timp maxim de executare: 1 secund /test.
Fiecare paragraf se preia într-un vector de string-uri, elementele vectorului conµinând cuvintele
din paragraf. Se parcurge acest vector, începând cu prima poziµie, determinând cel mai mare
indice i1 care permite plasarea cuvintelor de pe poziµiile 1, ..., i1 pe acela³i rând. Se destribuie
spaµiile disponibile, conform cerinµei problemei ³i se a³eaz aceast linie. Se continu prelucrarea
vectorului începând cu poziµia i1 1, ³i a³a mai departe!
21
E cerul sus
Ca niste-ntinse brate
N-au crengile de ce sa se agate
0000:0000 32 31 0D 0A 45 20 63 65 72 75 6C 20 73 75 73 0D
0000:0010 0A 43 61 20 6E 69 73 74 65 2D 6E 74 69 6E 73 65
0000:0020 20 62 72 61 74 65 0D 0A 4E 2D 61 75 20 63 72 65
0000:0030 6E 67 69 6C 65 20 64 65 20 63 65 20 73 61 20 73
0000:0040 65 20 61 67 61 74 65 0D 0A 1A
23 fin>>Max;
24 fin.get();
25
26 int gata=0;
27 while (!gata)
28 {
29 fin.getline(prg,NMax);
30 if (!fin.good())
31 gata=1;
32 else
33 afiseaza_paragraf();
34 }
35
36 fin.close();
37 fout.close();
38 return 0;
39 }
40
41 void afiseaza_paragraf()
42 {
43 char *p;
44 int LgCuv;
45 LgLinie=-1;
46 nrl=0;
47 p=strtok(prg," ");
48
49 while (p)
50 {
51 LgCuv=strlen(p);
52 if (LgLinie+LgCuv+1<=Max)
53 {
54 strcpy(cuv[nrl],p);
55 nrl++;
56 LgLinie+=LgCuv+1;
57 }
58 else
59 {
60 afiseaza_linie(0);
61 nrl=1;
62 LgLinie=LgCuv;
63 strcpy(cuv[0],p);
64 }
65
66 p=strtok(NULL," ");
67 }
68
69 afiseaza_linie(1);
70 }
71
72 void afiseaza_linie(int u)
73 {
74 int i, j, cate, rest, nrsp;
75
76 if (u)
77 for (i=0; i<nrl-1; i++)
78 fout<<cuv[i]<<’ ’;
79 else
80 {
81 cate=Max-LgLinie;
82 rest=cate%(nrl-1);
83 nrsp=cate/(nrl-1);
84
85 for (i=0; i<nrl-1;i++)
86 {
87 fout<<cuv[i];
88 for (j=0; j<=nrsp;j++)
89 fout<<’ ’;
90 if (rest)
91 {
92 fout<<’ ’;
93 rest--;
94 }
95 }
96 }
97
98 if (nrl>0)
CAPITOLUL 17. OJI 2003 CLASA A IX-A 240
99 fout<<cuv[nrl-1]<<endl;
100 else
101 fout<<endl;
102 }
63 for(i=cs;i<cd;i++) nsp[i]=1+nsf;
64 for(i=1;i<=nsr;i++) nsp[cs+i-1]++;
65 for(i=cs;i<=cd-1;i++)
66 {
67 out.print(s[i]);
68 for(j=1;j<=nsp[i];j++) out.print(" ");
69 }
70 out.println(s[cd]);
71 }
72 }
73
74 static void ultimulRand() throws IOException
75 {
76 int i;
77 out.print(s[cs]);
78 for(i=cs+1;i<=cd;i++) out.print(" "+s[i]);
79 out.println();
80 }
81 }
17.2 Numere
Gigel este un mare pasionat al cifrelor. Orice moment liber ³i-l petrece jucându-se cu numere.
Jucându-se astfel, într-o zi a scris pe hârtie 10 numere distincte de câte dou cifre ³i a observat
c printre acestea exist dou submulµimi disjuncte de sum egal .
Desigur, Gigel a crezut c este o întâmplare ³i a scris alte 10 numere distincte de câte dou
cifre ³i spre surpriza lui, dup un timp a g sit din nou dou submulµimi disjuncte de sum egal .
Cerinµ
Date 10 numere distincte de câte dou cifre, determinaµi num rul de perechi de submulµimi
disjuncte de sum egal care se pot forma cu numere din cele date, precum ³i una dintre aceste
perechi pentru care suma numerelor din ecare dintre cele dou submulµimi este maxim .
Date de intrare
Fi³ierul de intrare numere.in conµine pe prima linie 10 numere naturale distincte separate
prin câte un spaµiu x1 x2 ... x10 .
Date de ie³ire
Fi³ierul de ie³ire numere.out conµine trei linii. Pe prima linie se a num rul de perechi de
submulµimi de sum egal , precum ³i suma maxim obµinut , separate printr-un spaµiu. Pe linia
a doua se a elementele primei submulµimi, iar pe linia a treia se a elementele celei de a doua
submulµimi, separate prin câte un spaµiu.
NrSol Smax NrSol - num rul de perechi; Smax - suma maxim
x1 ... xk elementele primei submulµimi
y1 ... yp elementele celei de a doua submulµimi
Restricµii ³i preciz ri
a 10 & xi , yi & 99, pentru 1 & i & 10.
a 1 & k, p & 9.
a Ordinea submulµimilor în perechi nu conteaz .
a Perechea de submulµimi determinat nu este obligatoriu unic .
Exemplu
numere.in numere.out
60 49 86 78 23 97 69 71 32 10 130 276
78 97 69 32
60 49 86 71 10
Explicaµie:
130 de soluµii; suma maxim este 276; s-au folosit 9 din cele 10 numere; prima submulµime are
4 elemente, a doua are 5 elemente.
Timp maxim de executare: 1 secund /test
CAPITOLUL 17. OJI 2003 CLASA A IX-A 242
Num rul mic al numerelor (numai 10 numere distincte) permite generarea tuturor submulµi-
milor, vericarea condiµiilor din problem pentru ecare pereche de submulµimi ³i determinarea
informaµiilor cerute.
58 cati1+=(vi[i]+vj[i]);
59
60 if (cati1>UzMax)
61 if (si>Smax)
62 {
63 UzMax=cati1;
64 Smax=si;
65 for (i=1; i<=10; i++)
66 s1max[i]=vi[i];
67 for (i=1; i<=10; i++)
68 s2max[i]=vj[i];
69 }
70 }
71 }
72 }
73 }
74 }
75
76 void afisare()
77 {
78 int i;
79
80 g<<solutii<<" "<<Smax<<endl;
81
82 for(i=1; i<=10; i++)
83 if (s1max[i])
84 g<<a[i]<<’ ’;
85 g<<endl;
86
87 for(i=1; i<=10; i++)
88 if (s2max[i])
89 g<<a[i]<<’ ’;
90 g<<endl;
91 g.close();
92 }
93
94 int main()
95 {
96 citire();
97 rezolva();
98 afisare();
99 return 0;
100 }
25 {
26 smax=sumaia;
27 iamax=ia;
28 ibmax=ib;
29 }
30 }
31 }
32 out.println(nsol+" "+smax);
33 afis(iamax);
34 afis(ibmax);
35 out.close();
36 t2=System.currentTimeMillis();
37 System.out.println(t2-t1);
38 }// main
39
40 static int suma(int i)
41 {
42 int s=0,k=0;
43 for(k=0;k<=9;k++) if( (i&(1<<k)) != 0 ) s+=x[k];
44 return s;
45 }
46
47 static void afis(int i)
48 {
49 int k=0;
50 while(i!=0)
51 {
52 if(i%2!=0) out.print(x[k]+" ");
53 k++;
54 i/=2;
55 }
56 out.println();
57 }
58 }// class
Capitolul 18
18.1 Poarta
Se consider harta universului ca ind o matrice cu 250 de linii ³i 250 de coloane. În ecare
celul se g se³te o a³a numit poart stelar , iar în anumite celule se g sesc echipaje ale porµii
stelare.
La o deplasare, un echipaj se poate deplasa din locul în care se a în oricare alt loc în care
se g se³te o a doua poart , în cazul nostru în orice alt poziµie din matrice.
Nu se permite situarea simultan a mai mult de un echipaj într-o celul . La un moment dat
un singur echipaj se poate deplasa de la o poart stelar la alta.
Cerinµ
Dându-se un num r p (1 $ p $ 5000) de echipaje, pentru ecare echipaj ind precizate po-
ziµia iniµial ³i poziµia nal , determinaµi num rul minim de deplas ri necesare pentru ca toate
echipajele s ajung din poziµia iniµial în cea nal .
Datele de intrare
Se citesc din ³ierul text poarta.in în urm torul format:
pe prima linie num rul natural p reprezentând num rul de echipaje,
pe urm toarele p linii câte 4 numere naturale, primele dou reprezentând coordonatele
poziµiei iniµiale a unui echipaj (linie coloan ), urm toarele dou reprezentând coordonatele poziµiei
nale a aceluia³i echipaj (linie coloan ).
Datele de ie³ire
Pe prima linie a ³ierului text poarta.out se scrie un singur num r reprezentând num rul
minim de deplas ri necesar.
Restricµii ³i preciz ri
coordonatele poziµiilor iniµiale ³i nale ale echipajelor sunt numere naturale din intervalul
1, 250;
poziµiile iniµiale ale celor p echipaje sunt distincte dou câte dou ;
poziµiile nale ale celor p echipaje sunt distincte dou câte dou .
Exemplu
poarta.in poarta.out
3 4
1234
6539
3412
245
CAPITOLUL 18. OJI 2002 CLASA A IX-A 246
Fie NrStationare num rul echipajelor staµionare (care au poziµiile iniµiale ³i nale egale) ³i
NrCircuite num rul circuitelor grafului orientat format astfel: nodurile sunt echipajele ³i exist
arc de la echipajul i la echipajul j dac ³i numai dac poziµia nal a echipajului i coincide cu
poziµia iniµial a echipajului j .
Atunci NrMinDeplasari=p+NrCircuite-NrStationare.
18.2 Mouse
Un experiment urm re³te comportarea unui ³oricel pus într-o cutie dreptunghiular , împ rµit
în m n c m ruµe egale de form p trat . Fiecare c m ruµ conµine o anumit cantitate de hran .
oricelul trebuie s porneasc din colµul 1, 1 al cutiei ³i s ajung în colµul opus, mâncând cât
mai mult hran . El poate trece dintr-o camer în una al turat (dou camere sunt al turate dac
au un perete comun), m nânc toat hrana din c m ruµ atunci când intr ³i nu intr niciodat
într-o camer f r hran .
Cerinµ
Stabiliµi care este cantitatea maxim de hran pe care o poate mânca ³i traseul pe care îl poate
urma pentru a culege aceast cantitate maxim .
Datele de intrare
Fi³ierul de intrare mouse.in conµine pe prima linie dou numere m ³i n reprezentând num rul
de linii respectiv num rul de coloane ale cutiei, iar pe urm toarele m linii cele m n numere
reprezentând cantitatea de hran existent în ecare c m ruµ , câte n numere pe ecare linie,
separate prin spaµii. Toate valorile din ³ier sunt numere naturale între 1 ³i 100.
Datele de ie³ire
În ³ierul de ie³ire mouse.out se vor scrie
a pe prima linie dou numere separate printr-un spaµiu: num rul de c m ruµe vizitate ³i
cantitatea de hran maxim culeas ;
a pe urm toarele linii un traseu posibil pentru cantitatea dat , sub form de perechi de numere
(linie coloan ) începând cu 1 1 ³i terminând cu m n.
Exemplu
CAPITOLUL 18. OJI 2002 CLASA A IX-A 248
mouse.in mouse.out
24 7 21
1263 1 1
3412 2 1
2 2
1 2
1 3
1 4
2 4
Explicaµie
Dac m ³i n sunt pare atunci num rul de c m ruµe vizitate este mn 1 iar cantitatea de hran
maxim culeas este suma cantit µilor de hran din toate c m ruµele cu excepµia celei care are
cea mai mic cantitate ³i se a pe linia i ³i coloana j ³i i j este num r impar. Traseul este
determinat de o parcurgere pe vertical sau orizontal ³i ocolirea acelei c m ruµe.
Dac m este impar atunci num rul de c m ruµe vizitate este mn iar cantitatea de hran
maxim culeas este suma cantit µilor de hran din toate c m ruµele. Traseul este determinat de
o parcurgere pe orizontal .
Analog pentru situaµia în care n este impar.
16 st.nextToken();n=(int)st.nval;
17 a=new int[m+1][n+1];
18
19 for(i=1;i<=m;i++)
20 for(j=1;j<=n;j++) {st.nextToken(); a[i][j]=(int)st.nval;}
21
22 s=0;
23 for(i=1;i<=m;i++)
24 for(j=1;j<=n;j++) s=s+a[i][j];
25
26 if(m%2==1) mimpar();
27 else if(n%2==1) nimpar();
28 else mnpare();
29 out.close();
30 }//main
31
32 static void mimpar()
33 {
34 int i,j;
35 out.println(m*n+" "+s);
36 i=1;
37 while(i+1<m)
38 {
39 for(j=1;j<=n;j++) out.println(i+" "+j);
40 i++;
41 for(j=n;j>=1;j--) out.println(i+" "+j);
42 i++;
43 }
44 for(j=1;j<=n;j++) out.println(m+" "+j);
45 }
46
47 static void nimpar()
48 {
49 int i,j;
50 j=1;
51 out.println(m*n+" "+s);
52 while(j+1<n)
53 {
54 for(i=1;i<=m;i++) out.println(i+" "+j);
55 j++;
56 for(i=m;i>=1;i--) out.println(i+" "+j);
57 j++;
58 }
59 for(i=1;i<=m;i++) out.println(i+" "+n);
60 }
61
62 static void mnpare()
63 {
64 int i,j;
65 imin=0;jmin=0;min=101;
66 for(i=1;i<=m;i++)
67 for(j=1;j<=n;j++)
68 if((i+j)%2==1)
69 if(a[i][j]<min) { min=a[i][j]; imin=i; jmin=j; }
70 out.println((m*n-1)+" "+(s-a[imin][jmin]));
71
72 j=1;
73 while(j+1<jmin) // stanga
74 {
75 for(i=1;i<=m;i++) out.println(i+" "+j);
76 j++;
77 for(i=m;i>=1;i--) out.println(i+" "+j);
78 j++;
79 }
80
81 i=1;
82 while(i+1<imin) // sus
83 {
84 out.println(i+" " +j);
85 out.println(i+" " +(j+1));
86 out.println((i+1)+" " +(j+1));
87 out.println((i+1)+" " +j);
88 i=i+2;
89 }
90
91 out.println(i+" "+j); // patratel
CAPITOLUL 18. OJI 2002 CLASA A IX-A 250
251
Capitolul 19
ONI 2019
19.1 amat
Problema 1 - amat 100 de puncte
Pasionat de informatic ³i de puzzle-uri, Dorel a construit o matrice A de dimensiunea N M
lipind mai multe piese dreptunghiulare de diferite dimensiuni. Fiecare pies este compus din
elemente de dimensiunea 1 1 ³i reµin o aceea³i valoare (vezi exemplele). Matricea rezultat nu
are spaµii libere, iar piesele din care este compus nu se suprapun. Nu exist dou piese cu aceea³i
valoare.
De³i iniµial p rea c acest design este unul inedit, nu a durat mult pân când Dorel s-a plictisit.
Astfel, acum el dore³te s upgradeze matricea construit . Dorel alege o submatrice delimitat
de coordonatele x1, y1 - colµul stânga-sus, x2, y2 - colµul dreapta-jos (1 & x1 & x2 & N ,
1 & y1 & y2 & M ), unde cre³te toate valorile elementelor submatricei cu valoarea V .
Dorel efectueaz în ordine Q operaµii de upgrade, operaµii numerotate de la 1 la Q. La
nalizarea celor Q operaµii de upgrade, toate elementele din matrice au valoarea mai mare sau
egal cu K . Dup o operaµie de upgrade, structura iniµial a matricei se modic .
Cerinµe
Cum priceperea lui Dorel este proverbial , trebuie s îl ajutaµi în rezolvarea urm toarelor
cerinµe:
1) determinarea coordonatelor piesei cu num r maxim de elemente înainte ca Dorel s efectueze
operaµiile de upgrade;
2) determinarea num rului minim de operaµii de upgrade dup care toate elementele matricei
au valoarea mai mare sau egal cu K .
Date de intrare
Datele de intrare se citesc din ³ierul amat.in, care are urm toarea structur :
a pe prima linie se a num rul natural C , care poate egal cu 1 sau 2, în funcµie de cerinµa
ce trebuie rezolvat ;
a pe linia urm toare se a dou numerele naturale N ³i M cu semnicaµia din enunµ;
a pe urm toarele N linii se g sesc elementele matricei A.
a dac C 2 atunci ³ierul de intrare mai conµine:
- pe linia N 2 numerele naturale Q K cu semnicaµiile din enunµ;
- pe urm toarele Q linii descrierea submatricelor asupra c rora se efectueaz operaµii de
upgrade de forma: x1 y1 x2 y2 V
Date de ie³ire
Datele de ie³ire se vor scrie în ³ierul amat.out, astfel:
Dac C 1 se vor scrie, separate prin spaµiu patru numere naturale nenule x1 y1 x2 y2 ce
reprezint coordonatele colµului stânga-sus, respectiv colµului dreapta-jos unde este plasat piesa
cu num r maxim de elemente înainte de upgrade. Dac exist mai multe astfel de piese, atunci
vor scrise coordonatele piesei pentru care coordonatele colµului stânga-sus are valoarea liniei cea
mai mare, iar la linii egale, se va alege piesa cu coordonata coloanei cea mai mare.
Dac C 2 se va scrie num rul natural nenul N R ce reprezint num rului minim de operaµii
de upgrade dup care toate elementele matricei au valoarea mai mare sau egal cu K .
252
CAPITOLUL 19. ONI 2019 253
Restricµii ³i preciz ri
a 2 & N, M & 1000; 1 & Q & 100000; 1 & V & 1000
a 1000 & elementele matricei A înainte de upgrade & 1000
a Operaµiile de upgrade se efectueaz obligatoriu în ordinea citirii
a Pentru teste în valoare de 30 de puncte, C 1
a Pentru teste în valoare de 30 de puncte, C 2 ³i N, M, Q & 250
a Pentru teste în valoare de 50 de puncte, C 2 ³i Q & 4000
a Pentru teste în valoare de 70 de puncte, C 2.
Exemple
24 int main()
25 {
26 int optiune;
27 fin >> optiune >> n >> m;
28
29 for(int i = 1; i <= n; i++)
30 for(int j = 1; j <= m; j++)
31 fin >> init[i][j];
32
33 fin >> qq >> k;
34
35 for(int i = 1; i <= qq; i++)
36 fin >> q[i].x1 >> q[i].y1 >> q[i].x2 >> q[i].y2 >> q[i].val;
37
38 int st = 1;
39 int dr = qq;
40 int rasp = 0;
41 while(st <= dr)
42 {
43 int mij = (st + dr) / 2;
44 int ok = 1;
45 for(int i = 1; i <= mij; i++)
46 dp[q[i].x1][ q[i].y1 ] += q[i].val,
47 dp[q[i].x2 + 1][ q[i].y2 + 1] += q[i].val,
48 dp[q[i].x1][ q[i].y2 + 1 ] -= q[i].val,
49 dp[q[i].x2 + 1][ q[i].y1] -= q[i].val;
50
51 for(int i = 1; i <= n; i++)
52 for(int j = 1; j <= m; j++)
53 {
54 dp[i][j] += dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1];
55 if(dp[i][j] + init[i][j] < k)
56 ok = 0;
57 }
58
59 for(int i = 1; i <= n; i++)
60 for(int j = 1; j <= m; j++)
61 dp[i][j] = 0;
62
63 if(ok)
64 rasp = mij, dr = mij - 1;
65 else
66 st = mij + 1;
67 }
68
69 fout << rasp << ’\n’;
70 return 0;
71 }
25 {
26 int optiune;
27 fin >> optiune >> n >> m;
28
29 for(int i = 1; i <= n; i++)
30 for(int j = 1; j <= m; j++)
31 fin >> init[i][j];
32
33 fin >> qq >> k;
34
35 for(int i = 1; i <= qq; i++)
36 fin >> q[i].x1 >> q[i].y1 >> q[i].x2 >> q[i].y2 >> q[i].val;
37
38 int st = 1;
39 int dr = qq;
40 int rasp = 0;
41 while(st <= dr)
42 {
43 int mij = (st + dr) / 2;
44 int ok = 1;
45 for(int i = 1; i <= mij; i++)
46 for(int j = q[i].x1; j <= q[i].x2; j++)
47 dp[j][ q[i].y1 ] += q[i].val,
48 dp[j][ q[i].y2 + 1] -= q[i].val;
49
50 for(int i = 1; i <= n; i++)
51 for(int j = 1; j <= m; j++)
52 {
53 dp[i][j] += dp[i][j - 1];
54 if(dp[i][j] + init[i][j] < k)
55 ok = 0;
56 }
57
58 for(int i = 1; i <= n; i++)
59 for(int j = 1; j <= m; j++)
60 dp[i][j] = 0;
61
62 if(ok)
63 rasp = mij, dr = mij - 1;
64 else
65 st = mij + 1;
66 }
67
68 fout << rasp << ’\n’;
69 return 0;
70 }
103 }
104 else
105 {
106
107 f >> q >> K;
108 for(i = 1; i <= q; ++i)
109 {
110 f >> x1 >> y1 >> x2 >> y2 >> x;
111 Q[i] = {x1, y1, x2, y2, x};
112 }
113
114 i = 1, j = q;
115 while (i <= j)
116 {
117 int mij = (i+j) >> 1;
118 int k = verif(mij);
119 if (k)
120 j = mij - 1;
121 else
122 i = mij + 1;
123 }
124
125 g << i << "\n";
126 }
127
128 return 0;
129 }
46
47 for(int i = 1; i <= n && ok; i++)
48 for(int j = 1; j <= m && ok; j++)
49 {
50 if(init[i][j] < k)
51 ok = 0;
52 }
53
54 if(ok)
55 {
56 fout << mij << ’\n’;
57 return 0;
58 }
59 }
60
61 return 0;
62 }
56 {
57 fout << mij << ’\n’;
58 return 0;
59 }
60 }
61
62 return 0;
63 }
31 {
32 int val = a[i][j] + 2000;
33 if (lt[val] == -1 || lt[val] > j) lt[val] = j;
34 if (rt[val] == -1 || rt[val] < j) rt[val] = j;
35 if (up[val] == -1 || up[val] > i) up[val] = i;
36 if (dw[val] == -1 || dw[val] < i) dw[val] = i;
37 }
38 }
39
40 tuple<int, int, int, int> best = make_tuple(-1, -1, -1, -1);
41
42 for (int i = 0; i < kMax; ++i)
43 {
44 tuple<int, int, int, int> now = make_tuple(
45 (rt[i] - lt[i] + 1) * (dw[i] - up[i] + 1), up[i], lt[i], i);
46
47 best = max(best, now);
48 }
49
50 int col = get<3>(best);
51 cout << up[col] + 1 << " " << lt[col] + 1 << " " <<
52 dw[col] + 1 << " " << rt[col] + 1 << endl;
53
54 }
55 else
56 {
57 int q, k; cin >> q >> k;
58
59 vector<tuple<int, int, int, int, int>> ops;
60
61 for (int i = 0; i < q; ++i)
62 {
63 int u, l, d, r, x; cin >> u >> l >> d >> r >> x;
64 ops.emplace_back(u, l, d, r, x);
65 }
66
67 int sol = 0;
68 for (int step = 1, adv = 1; step; adv ? step *= 2 : step /= 2)
69 {
70 if (sol + step > q)
71 {
72 adv = 0;
73 }
74 else
75 {
76 vector<vector<int>> mars(n + 1, vector<int>(m + 1, 0));
77
78 for (int i = sol; i < sol + step; ++i)
79 {
80 int u, l, d, r, x; tie(u, l, d, r, x) = ops[i];
81 mars[u - 1][l - 1] += x;
82 mars[u - 1][r] -= x;
83 mars[d][l - 1] -= x;
84 mars[d][r] += x;
85 }
86
87 bool bad = false;
88 for (int i = 0; i < n; ++i)
89 {
90 for (int j = 0; j < m; ++j)
91 {
92 if (i > 0) mars[i][j] += mars[i - 1][j];
93 if (j > 0) mars[i][j] += mars[i][j - 1];
94 if (i > 0 && j > 0) mars[i][j] -= mars[i - 1][j - 1];
95
96 if (mars[i][j] + a[i][j] < k)
97 {
98 bad = true;
99 }
100 }
101 }
102 /*
103 cerr << sol + step << endl;
104 for (int i = 0; i < n; ++i) {
105 for (int j = 0; j < m; ++j)
106 cerr << a[i][j] + mars[i][j] << " ";
CAPITOLUL 19. ONI 2019 264
46 {
47 if (aux[i][j] == 1) continue;
48
49 crt = mat[i][j];
50 cnt = 0;
51 for (lin = i ; lin <= n ; lin++)
52 {
53 if (mat[lin][j] != crt) break;
54 for (col = j ; col <= m ; col++)
55 {
56 if (mat[lin][col] != crt) break;
57 aux[lin][col] = 1;
58
59 cnt++;
60 }
61 }
62
63 if (cnt >= maxCnt)
64 {
65 subAns.x1 = i;
66 subAns.y1 = j;
67 subAns.x2 = lin - 1;
68 subAns.y2 = col - 1;
69
70 maxCnt = cnt;
71 }
72 }
73 }
74
75 fout << subAns.x1 << ’ ’ << subAns.y1 << ’ ’ <<
76 subAns.x2 << ’ ’ << subAns.y2 << ’\n’;
77 }
78
79 int solve(int nrQ)
80 {
81 int val;
82 memset(aux, 0, sizeof(aux));
83
84 for (i = 1 ; i <= nrQ ; i++)
85 {
86 val = queries[i].v;
87 aux[queries[i].x1][queries[i].y1] += val;
88 aux[queries[i].x1][queries[i].y2 + 1] += -val;
89 aux[queries[i].x2 + 1][queries[i].y1] += -val;
90 aux[queries[i].x2 + 1][queries[i].y2 + 1] += val;
91 }
92
93 for (i = 1 ; i <= n ; i++)
94 for (j = 1 ; j <= m ; j++)
95 aux[i][j] += aux[i][j - 1];
96
97 for (j = 1 ; j <= m ; j++)
98 for (i = 1 ; i <= n ; i++)
99 aux[i][j] += aux[i - 1][j];
100
101 /**
102 cout << nrQ << ’\n’;
103 DEBUG_endmatrix();
104 cout << "-----------------\n";
105 */
106
107 for (i = 1 ; i <= n ; i++)
108 for (j = 1 ; j <= m ; j++)
109 if (aux[i][j] + mat[i][j] < k) return 0;
110
111 return 1;
112 }
113
114 void maintask()
115 {
116 int ls = 1, ld = q, mij, best = q;
117 while (ls <= ld)
118 {
119 mij = (ls + ld) / 2;
120
121 if (solve(mij))
CAPITOLUL 19. ONI 2019 266
122 {
123 best = mij;
124 ld = mij - 1;
125 }
126 else
127 {
128 ls = mij + 1;
129 }
130 }
131
132 fout << best;
133 }
134
135 int main()
136 {
137 fin >> c;
138 fin >> n >> m;
139
140 assert(c == 1 || c == 2);
141 assert(2 <= n && n <= NMAX);
142 assert(2 <= m && m <= NMAX);
143
144 for (i = 1 ; i <= n ; i++)
145 for (j = 1 ; j <= m ; j++)
146 {
147 fin >> mat[i][j];
148
149 assert(VALMIN <= mat[i][j] && mat[i][j] <= 1000);
150 }
151
152 if (c == 1)
153 {
154 subtask();
155 }
156 else
157 {
158 fin >> q >> k;
159 assert(VALMIN <= k && k <= VALMAX);
160 assert(1 < q && q <= 100000);
161
162 for (i = 1 ; i <= q ; i++)
163 {
164 fin >> queries[i].x1 >> queries[i].y1 >>
165 queries[i].x2 >> queries[i].y2 >> queries[i].v;
166
167 assert(1 <= queries[i].x1 && queries[i].x1 <= n);
168 assert(1 <= queries[i].y1 && queries[i].y1 <= m);
169 assert(1 <= queries[i].x2 && queries[i].x2 <= n);
170 assert(1 <= queries[i].y2 && queries[i].y2 <= m);
171 assert(queries[i].x1 <= queries[i].x2 &&
172 queries[i].y1 <= queries[i].y2);
173 }
174
175 maintask();
176 }
177
178 return 0;
179 }
19.2 Comun
Problema 2 - Comun 100 de puncte
Tocmai ai primit un ³ir v de K numere naturale nenule distincte. Plecând de la acest ³ir, te-ai
gândit s construie³ti un ³ir w de N numere naturale distincte, astfel încât un num r x este în
³irul w dac ³i numai dac exista iniµial în ³irul v sau se pot alege cel puµin dou numere din ³irul
v astfel încât x este cel mai mare divizor comun al acelor numere.
De exemplu, dac v r4, 6, 7x atunci w r1, 2, 4, 6, 7x.
Uimit de propriet µile matematice frumoase ale noului ³ir w, ai uitat din p cate ³irul original
v de la care ai pornit.
Cerinµe
CAPITOLUL 19. ONI 2019 267
Dându-se ³irul w, s se g seasc un ³ir posibil iniµial v având un num r minim de elemente.
Date de intrare
Fi³ierul de intrare comun.in conµine pe prima linie un num r natural N . Pe cea de-a doua
linie se a N numere naturale nenule distincte, în ordine strict cresc toare, reprezentând
³irul w.
Date de ie³ire
Fi³ierul de ie³ire comun.out va conµine pe prima linie num rul minim K de elemente ale ³irului
v . Pe cea de-a doua linie se vor aa K numere naturale distincte, în ordine strict cresc toare,
reprezentând ³irul propriu-zis.
Restricµii ³i preciz ri
a Toate valorile din ³ierul de intrare sunt numere naturale nenule mai mici sau egale cu
100000.
a Pentru teste în valoare de 15 puncte, toate valorile din ³ierul de intrare sunt mai mici sau
egale cu 20.
a Pentru teste în valoare de 50 de puncte, toate valorile din ³ierul de intrare sunt mai mici
sau egale cu 2000.
a Se garanteaz c exist m car o soluµie.
a Dac exist mai multe ³iruri iniµiale cu num r minim de elemente, oricare este acceptat.
Exemple
comun.in comun.out Explicaµii
5 3 1 = cmmdc(6, 7) = cmmdc(4, 6, 7).
12467 467 2 = cmmdc(4, 6).
Se poate demonstra c orice alt ³ir cu proprietatea cerut are
m car 3 elemente.
4 4 Nu exist niciun ³ir de mai puµin de 4 elemente cu proprietatea
2 4 8 16 2 4 8 16 cerut .
Soluµie 15p
Exist o multitudine de soluµii care se încadreaz în aceste limite. în continuare va prezentat
una dintre posibilele soluµii.
O prim observaµie este c cel mai mare num r se reg se³te mereu în ³ir, deoarece nu se poate
obµine aplicând c.m.m.d.c. asupra altor numere. Mai mult, dac un num r din w este cel mai
mare divizor comun al altor numere din w, nu are sens s îl includem în soluµie, deoarece orice
num r pe care l-ar putea genera x îl putem genera, în schimb, cu numerele care îl genereaz .
Din aceste considerente, se poate deduce c soluµia de lungime minim este unic . Un algoritm
pentru a o calcula este urm torul: dac exist un num r x care este c.m.m.d.c. al altor numere
înc neeliminate, îl elimin m. Algoritmul se va opri atunci când nu se mai pot elimina numere.
N
O implementare naiv a acestui algoritm are complexitate O 2 N ³i ar trebui s obµin
minimum 15 puncte. în continuare vom optimiza algoritmul pentru a rula mai rapid.
Soluµie 50p
Observaµia cheie este c , în cadrul raµionamentului de mai sus, este sucient s consider m
doar perechi de câte dou numere.
Un algoritm este urm torul: pentru ecare pereche x, y de numere distincte din ³irul de
intrare, calcul m d cmmdc x, y ³i îl ³tergem din ³ir. ³tergerea se poate face folosind un vector
caracteristic.
CAPITOLUL 19. ONI 2019 268
2
O astfel de soluµie are complexitate O N log V (unde V este valoarea maxim din ³irul de
intrare) ³i ar trebui s obµin minimum 50 de puncte.
Soluµie 100p
O alt modalitate de a optimiza algoritmul menµionat anterior este c , pentru a ne decide
dac un num r trebuie eliminat sau nu, este de ajuns s calcul m cel mai mare divizor comun al
multiplilor s i din ³ir.
În acest caz, putem menµine ³irul într-un vector caracteristic ³i s veric m ecare num r
folosind un algoritm foarte asem n tor ciurului lui Eratostene.
2
Aceast soluµie, de³i la prima vedere are complexitate O N V log V , se poate demonstra
c complexitatea este de fapt O N V log V . Demonstraµia este l sat ca exerciµiu. O astfel
de soluµie ar trebui s obµin punctajul maxim.
Soluµie alternativ
Se poate demonstra c , în loc s consider m toµi multiplii unui num r x, putem considera doar
perechile de multipli în care unul dintre cele dou este cel mai mic multiplu al lui x din ³ir.
În acest caz, complexitatea soluµiei este tot O N V log V , din acelea³i considerente ca ³i
soluµia precedent .
6 {
7 while (b)
8 {
9 int r = a % b;
10 a = b;
11 b = r;
12 }
13 return a;
14 }
15
16 int main()
17 {
18 ifstream cin("comun.in");
19 ofstream cout("comun.out");
20
21 int n; cin >> n;
22
23 vector<int> v(n);
24
25 int maxx = 0;
26 for (auto& x : v)
27 {
28 cin >> x;
29 maxx = max(maxx, x);
30 }
31
32 vector<bool> w(maxx + 1);
33 for (auto x : v)
34 w[x] = true;
35
36 for (int x = maxx; x >= 1; --x)
37 {
38 if (w[x] == false) continue;
39
40 for (int pos = 0; pos < (int)v.size(); ++pos)
41 {
42 int y = v[pos];
43 int gc = gcd(x, y);
44 if (gc < x && gc < y)
45 w[gc] = false;
46 }
47 }
48
49 v.clear();
50
51 for (int i = 1; i <= maxx; ++i)
52 if (w[i])
53 v.push_back(i);
54
55 cout << v.size() << endl;
56
57 for (auto x : v)
58 cout << x << " ";
59 cout << endl;
60
61 return 0;
62 }
16 {
17 for (int i = 1; i < (int)vals.size(); ++i)
18 {
19 if (!vals[i]) continue;
20 int all_gcd = 0;
21 for (int j = i + i; j < (int)vals.size(); j += i)
22 {
23 if (vals[j])
24 all_gcd = all_gcd ? gcd(all_gcd, j % all_gcd) : j;
25 }
26 if (all_gcd == i)
27 vals[i] = false;
28 }
29 return vals;
30 }
31
32 int main()
33 {
34 ifstream cin("comun.in");
35 ofstream cout("comun.out");
36
37 int n;
38 cin >> n;
39
40 vector<bool> v(100001, false);
41
42 for (int i = 0; i < n; ++i)
43 {
44 int x; cin >> x; v[x] = true;
45 }
46
47 v = Sparsify(v);
48 vector<int> out;
49
50 for (int i = 0; i < (int)v.size(); ++i)
51 if (v[i])
52 out.push_back(i);
53
54 cout << out.size() << endl;
55 for (auto x : out)
56 cout << x << " ";
57 cout << endl;
58
59 return 0;
60 }
28
29 if (all_gcd == i)
30 vals[i] = false;
31 }
32 return vals;
33 }
34
35 int main()
36 {
37 ifstream cin("comun.in");
38 ofstream cout("comun.out");
39
40 int n;
41 cin >> n;
42
43 vector<bool> v(100001, false);
44
45 for (int i = 0; i < n; ++i)
46 {
47 int x; cin >> x; v[x] = true;
48 }
49
50 v = Sparsify(v);
51 vector<int> out;
52
53 for (int i = 0; i < (int)v.size(); ++i)
54 if (v[i])
55 out.push_back(i);
56
57 cout << out.size() << endl;
58 for (auto x : out)
59 cout << x << " ";
60 cout << endl;
61
62 return 0;
63 }
37 ifstream cin("comun.in");
38 ofstream cout("comun.out");
39
40 int n;
41 cin >> n;
42 vector<bool> v(100001, false);
43
44 for (int i = 0; i < n; ++i)
45 {
46 int x; cin >> x; v[x] = true;
47 }
48
49 v = Sparsify(v);
50 vector<int> out;
51 for (int i = 0; i < (int)v.size(); ++i)
52 if (v[i])
53 out.push_back(i);
54
55 cout << out.size() << endl;
56 for (auto x : out)
57 cout << x << " ";
58 cout << endl;
59
60 return 0;
61 }
19.3 pro3
Problema 3 - pro3 100 de puncte
Se consider 3 progresii aritmetice de numere naturale nenule.
Not m cu Pi , 1 & i & 3, mulµimile formate cu elementele progresiei i.
Fie P P1 < P2 < P3 reuniunea mulµimilor P1 , P2 , P3 .
Cerinµe
S se determine cardinalul mulµimii P .
Date de intrare
Fi³ierul de intrare pro3.in conµine 3 linii.
Pe linia i, 1 & i & 3 se vor g si câte 3 numere naturale ai , ri , ni , separate prin câte un spaµiu,
ce reprezint în aceast ordine primul termen, raµia ³i num rul de termeni ai progresiei P i.
Date de ie³ire
Fi³ierul de ie³ire pro3.out va conµine pe prima linie cardinalul mulµimii P .
Restricµii ³i preciz ri
Pentru teste în valoare de 40 puncte, 0 $ ai , ri & 10 ³i 0 $ ni & 10 , 1 & i & 3
2 6
a
Pentru teste în valoare de 72 puncte, 0 $ ai , ri & 10 ³i 0 $ ni & 10 , 1 & i & 3
2 9
a
Pentru teste în valoare de 100 puncte, 0 $ ai , ri & 10 ³i 0 $ ni & 10 , 1 & i & 3
6 9
a
Exemple
pro3.in pro3.out Explicaµii
2 2 10 24 Prima progresie are primul termen 2, raµia 2 ³i 10 termeni.
348 A doua progresie are primul termen 3, raµia 4 ³i 8 termeni.
1 3 12 A treia progresie are primul termen 1, raµia 3 ³i 12 termeni.
A³adar:
P1 r2, 4, 6, 8, 10, 12, 14, 16, 18, 20x
P2 r3, 7, 11, 15, 19, 23, 27, 31x
P3 r1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34x
Reuniunea termenilor celor trei progresii este mulµimea
P r1, 2, 3, 4, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 22, 23,
, 25, 27, 28, 31, 34x ³i cardinalul mulµimii P este 24.
CAPITOLUL 19. ONI 2019 275
Soluµie 20p
Se poate utiliza un vector de frecvenµ pentru a determina dac un num r natural cuprins
între 1 ³i cel mai mare element dintre cele 3 progresii face parte din m car o progresie.
Soluµia necesit un spaµiu de memorie foarte mare ³i nu poate utilizat pentru valori mari ale
num rului de termeni ale unei progresii, dar va obµine aproximativ 20 30 de puncte, în funcµie
de diverse optimiz ri de memorie.
Soluµie 40p
Se poate realiza o interclasare concomitent a celor 3 ³iruri, f r a mai construi un vector cu
rezultatele reuniuni. La ecare pas al interclas rii se va determina elementul minim al celor trei
progresii ³i se va incrementa indicele corespunz tor.
Dup ce unul dintre cele 2 ³iruri se va âtermina se va testa care dintre ³iruri s-a terminat
³i se va acµiona asem n tor pe dou ³iruri apoi pe un singur ³ir.
Aceast soluµie are complexitate O n1 n2 n3 ³i ar trebui s obµin minimum 40 de puncte.
Soluµie 72p
Observaµia cheie este c elementele comune a dou sau mai multe progresii aritmetice, dac
exist , formeaz tot o progresie aritmetic .
Astfel, observ m c este mai u³or ³i mai ecient s calcul m elementele comune a dou /trei
progresii ³i s folosim principiul includerii ³i excluderii pentru a calcula r spunsul.
Deoarece în acest caz termenii iniµiali ³i raµiile progresiilor sunt cel mult egale cu 100, se pot
g si primii doi termeni ai progresiei comune (³i, implicit, raµia acesteia), vericând pe rând valori
candidat, în ordine cresc toare. Dac exist termeni comuni, se poate demonstra c primul dintre
ei ³i raµia nu pot dep ³i 2 1003.
3 3
Aceast soluµie are complexitate O r1 r2 r3 a1 a2 a3 ³i ar trebui s obµin
minimum 72 de puncte.
Soluµie 100p
în soluµia anterioar ne-am bazat pe faptul c primul termen ³i raµia progresiei comune a dou
progresii a1 Xr1 ³i a2 Xr2 sunt mai mici sau egale cu a1 r1 a2 r2 . în loc s veric m
ecare candidat pe rând, vom itera doar prin elementele progresiei 1. Astfel, num rul de pa³i este
O a1 r1 a2 r2 © a1 r1 O a2 r2 . Este esenµial c aceast complexitate nu depinde
de parametrii progresiei 1, astfel c intersecµia celor trei progresii se poate calcula intersectând
progresiv progresia 1 cu progresia 2 ³i rezultatul cu progresia 3.
Complexitatea acestei soluµii este O r1 r2 r3 a1 a2 a3 ³i ar trebui s obµin 100 de
puncte.
87 }
148
149 if (t%d==0) // ecuatia are solutii
150 {
151 //determin primul element comun celor doua progresii
152 i=1;j=1;x0=0;y0=0;
153 while (i<=n12 && j<=n3)
154 {
155 if (a12+r12*(i-1) < a3+r3*(j-1)) i++;
156 if (a12+r12*(i-1) > a3+r3*(j-1)) j++;
157 if (a12+r12*(i-1) == a3+r3*(j-1)) {x0 = i; y0 = j; break;}
158 }
159
160 if (x0 == 0) {a123 = 0; r123 = 0; n123 = 0;}
161 else
162 {
163 // g << a12 << " " << r12 << " " << x0 <<" " << a123 << "\n";
164 a123 = a12 + r12*(x0 - 1);
165 r123 = (r12*r3)/d;
166 if (an12 < an3)
167 n123 = (an12 - a123)/r123 + 1;
168 else
169 n123 = (an3 - a123)/r123 + 1;
170 //g<< x0<<" "<< y0 <<"\n";
171 }
172 }
173 else
174 {a123 = 0; r123 = 0; n123 = 0;}
175 }
176 else
177 {a123 = 0; r123 = 0; n123 = 0;}
178
179 // aplic PINEX
180 //g<< " ------------------------------------------"<<"\n";
181
182 g << n1 + n2 + n3 - n12 - n13 - n23 + n123;
183
184 f.close();
185 g.close();
186
187 return 0;
188 }
7 struct Prog
8 {
9 long long a, r, n;
10 };
11
12 long long gcd(long long a, long long b)
13 {
14 while (b)
15 {
16 long long r = a % b;
17 a = b;
18 b = r;
19 }
20 return a;
21 }
22
23 Prog Merge(Prog p1, Prog p2)
24 {
25 if (p1.n == 0) return p1;
26 long long new_r = p1.r * p2.r / gcd(p1.r, p2.r);
27 for (int i = 0; i < p2.a + p2.r && i < p1.n; ++i)
28 {
29 long long x = p1.a + p1.r * i;
30 x -= p2.a;
31 if (x % p2.r == 0)
32 {
33 x /= p2.r;
34 if (x >= 0 && x < p2.n)
35 {
36 long long maxx = min(p1.a + p1.r * (p1.n - 1),
37 p2.a + p2.r * (p2.n - 1));
38 maxx -= p1.a + p1.r * i;
39 if (maxx < 0) break;
40 maxx /= new_r;
41 return {p1.a + p1.r * i, new_r, maxx + 1};
42 }
43 }
44 }
45 return {0, 0, 0};
46 }
47
48 ostream& operator<<(ostream& out, Prog prog)
49 {
50 out << "(" << prog.a << " + " << prog.r << " x " << prog.n << ")";
51 return out;
52 };
53
54 long long Calc(vector<Prog> progs)
55 {
56 // for (auto x : progs) cerr << x << " ";
57 Prog ret{0, 1, (long long)2e18};
58
59 for (auto prog : progs)
60 {
61 ret = Merge(ret, prog);
62 }
63 // cerr << " -> " << ret << endl;
64 return ret.n;
65 }
66
67 int main()
68 {
69 ifstream cin("pro3.in");
70 ofstream cout("pro3.out");
71
72 auto read = [&](){
73 Prog ret;
74 cin >> ret.a >> ret.r >> ret.n;
75 return ret;
76 };
77
78 Prog a = read(), b = read(), c = read();
79
80 cout << Calc({a}) + Calc({b}) + Calc({c}) -
81 Calc({a, b}) - Calc({a, c}) - Calc({b, c})
82 + Calc({a, b, c}) << endl;
CAPITOLUL 19. ONI 2019 282
83
84 return 0;
85 }
19.4 Cub
Problema 4 - Cub 100 de puncte
Ionel are de rezolvat o nou problem . El trebuie s construiasc un ³ir de N numere naturale.
Numerele din ³ir pot avea ca divizori primi doar numere prime de o cifr . Dup construirea ³irului,
Ionel a constatat c exist subsecvenµe în ³ir pentru care produsul elementelor este cubul unui
num r natural.
Cerinµe
Ionel vrea s determine num rul subsecvenµelor din ³irul construit care au produsul elementelor
o valoare ce este cubul unui num r natural.
Date de intrare
Fi³ierul de intrare cub.in va conµine pe prima linie num rul natural N , iar pe linia urm toare
se vor aa N numere naturale separate prin câte un spaµiu, elementele ³irului construit de Ionel.
Date de ie³ire
Fi³ierul de ie³ire cub.out va conµine pe prima linie un num r natural reprezentând num rul
subsecvenµelor din ³irul construit care au produsul elementelor egal cu o valoare ce este cubul unui
num r natural.
Restricµii ³i preciz ri
aN ³i elemente ³irului sunt numere naturale din intervalul 2, 1000000
aPrin subsecvenµ a unui ³ir se înµelege o succesiune de unul sau mai mulµi termeni din ³ir
aaµi pe poziµii consecutive.
a Pentru teste în valoare de 20 de puncte, N & 1000.
a Pentru teste în valoare de 40 de puncte, N & 10000.
Exemple
cub.in cub.out Explicaµii
8 6 Sunt 6 subsecvenµe în ³ir cu produsul elementelor egal cu o va-
15 3 5 15 7 63 21 125 loare care este cubul unui num r natural:
15 3 5 15
7 63 21
125
15 3 5 15 7 63 21
7 63 21 125
15 3 5 15 7 63 21 125
41 s[0]=1;r=0;
42 while(s[r]<=1000000)
43 {
44 r++;
45 s[r]=s[r-1]*7;
46 }
47
48 r--;
49 //g<<"i2="<<i<<" i3="<<j<<" i5="<<k<<" i7="<<r<<"\n"; //19 12 8 7
50 // calculez numerele mai mici decat 1000000 ce sunt divizibile
51 // doar cu 2, 3 ,5 sau 7
52 for(i1=0;i1<=i;i1++)
53 for(j1=0;j1<=j;j1++)
54 for(k1=0;k1<=k;k1++)
55 for(r1=0;r1<=r;r1++)
56 {
57 p=d[i1]*t[j1]*c[k1]*s[r1];
58 if(p<=1000000)
59 {
60 ex2[p]=i1;
61 ex3[p]=j1;
62 ex5[p]=k1;
63 ex7[p]=r1;
64 //w++;
65 }
66 }
67
68 //g<<"nr numere ="<<w<<"\n";// 1273
69 // citesc numerele si formez exponentii cumulati
70 // ai lui 2, 3 ,5 si 7
71 e2=0;e3=0;e5=0;e7=0;
72 f>>n;
73 for(i=1;i<=n;i++)
74 f>>v[i];
75 for(i=1;i<=n;i++)
76 {
77 x=v[i]; ;
78 e2=(e2+ex2[x])%3;
79 e3=(e3+ex3[x])%3;
80 e5=(e5+ex5[x])%3;
81 e7=(e7+ex7[x])%3;
82 cod=e2*27+e3*9+e5*3+e7;//scriu in baza 3
83 viz[cod]++;
84 }
85
86 sol=viz[0];
87 for(i=0;i<=80;i++)
88 sol=sol+viz[i]*(viz[i]-1)/2;
89
90 g<<sol<<’\n’ ;
91 g.close();
92 return 0;
93 }
20 i++;
21 d[i]=d[i-1]*2;
22 }
23
24 i--;
25 t[0]=1;
26 j=0;
27 while(t[j]<=1000000)
28 {
29 j++;
30 t[j]=t[j-1]*3;
31 }
32
33 j--;
34 c[0]=1;
35 k=0;
36 while(c[k]<=1000000)
37 {
38 k++;
39 c[k]=c[k-1]*5;
40 }
41
42 k--;
43 s[0]=1;
44 r=0;
45 while(s[r]<=1000000)
46 {
47 r++;
48 s[r]=s[r-1]*7;
49 }
50 r--;
51 //g<<"i2="<<i<<" i3="<<j<<" i5="<<k<<" i7="<<r<<"\n"; //19 12 8 7
52 // calculez numerele mai mici decat 1000000 ce sunt divizibile
53 // doar cu 2, 3 ,5 sau 7
54 for(i1=0;i1<=i;i1++)
55 for(j1=0;j1<=j;j1++)
56 for(k1=0;k1<=k;k1++)
57 for(r1=0;r1<=r;r1++)
58 {
59 p=1ll*d[i1]*t[j1]*c[k1]*s[r1];
60 if(p<=1000000)
61 {
62 ex2[p]=i1;
63 ex3[p]=j1;
64 ex5[p]=k1;
65 ex7[p]=r1;
66 //w++;
67 }
68 }
69 //g<<"nr numere ="<<w<<"\n";// 1273
70 // citesc numerele si formez exponentii cumulati
71 // ai lui 2, 3 ,5 si 7
72
73 e2=0; e3=0; e5=0; e7=0;
74 f>>n;
75 for(i=1;i<=n;i++)
76 f>>v[i];
77
78 for(i=1;i<=n;i++)
79 {
80 x=v[i]; ;
81 e2=(e2+ex2[x])%3;
82 e3=(e3+ex3[x])%3;
83 e5=(e5+ex5[x])%3;
84 e7=(e7+ex7[x])%3;
85 cod=e2*27+e3*9+e5*3+e7;//scriu in baza 3
86 viz[cod]++;
87 }
88
89 sol=viz[0];
90 for(i=0;i<=80;i++)
91 sol=sol+viz[i]*(viz[i]-1)/2;
92
93 g<<sol<<’\n’ ;
94 g.close();
95 return 0;
CAPITOLUL 19. ONI 2019 288
96 }
19.5 bofrac
Problema 5 - bofrac 100de puncte
Fie ³irul Fibonacci dat prin F1 1, F2 1 ³i relaµia de recurenµ Fk Fk1 Fk2 , k ' 3.
Se consider un num r natural N .
Cerinµe
S se scrie un program care determin num rul F al fracµiilor diferite ireductibile subunitare,
ce se pot forma utilizând primii N termeni ai ³irului Fibonacci.
Date de intrare
Fi³ierul de intrare bofrac.in conµine pe prima linie num rul N .
Date de ie³ire
Fi³ierul de ie³ire bofrac.out va conµine pe prima linie num rul F ,cu semnicaµia de mai sus.
Restricµii ³i preciz ri
a Pentru teste în valoare de 24 puncte, 0 $ N $ 80
a Pentru teste în valoare de 40 puncte, 0 $ N $ 1101
a Pentru teste în valoare de 56 puncte, 0 $ N $ 50001
a Pentru teste în valoare de 100 puncte, 0 $ N $ 1000000
a Dou fracµii ireductibile a©b ³i c©d sunt diferite dac a j c sau b j d.
0&F $2
63
a
Exemple
bofrac.in bofrac.out Explicaµii
7 14 N=7; Primii 7 termeni ai ³irului Fibonacci sunt: 1, 1, 2, 3, 5, 8,
13 Se pot forma 14 fracµii diferite ireductibile subunitare:
, , , , 1 , 2, 2, 2 , 3, 3, 3 , 5, 5 , 8 .
1 1 1 1
2 3 5 8 13 3 5 13 5 8 13 8 13 13
2019 1547722 Se pot forma 1547722 fracµii diferite ireductibile subunitare uti-
lizând primii 2019 termeni ai ³irului Fibonacci.
500000 94988288219 Se pot forma 94988288219 fracµii diferite ireductibile subunitare
utilizând primii 500000 termeni ai ³irului Fibonacci.
Soluµia 1
Gener m termenii ³irului Fibonacci ³i form m toate perechile posibile F a©F b cu F a $ F b.
Pentru ecare pereche calcul m F a, F b ³i contoriz m pentru acele perechi care au (Fa, Fb) = 1.
Deoarece termenii ³irului Fibonacci cresc repede se obµin erori pentru N % 80. Soluµia are ordin de
2
complexitate O n ³i obµine aproximativ 24 puncte. Pentru obµinerea unor puncte suplimentare
s-ar putea lucra cu numere mari.
Soluµia 2
Dac o fracµie F a©F b este ireductibil atunci F a, F b este 1. Se cunoa³te îns c F a, F b =
F a, b. Cum F a, F b trebuie s e 1, rezult c F a, b poate F 1 sau F 2, pentru c F 1 1
CAPITOLUL 19. ONI 2019 289
28 for(i=2;i<n;i++)
29 for(j=i+1;j<=n;j++)
30 if (cmmdc(i,j)==1 || cmmdc(i,j)==2) sol++;
31 g<<sol<<" ";
32
33 f.close();
34 g.close();
35
36 return 0;
37 }
63 ciur(n);
64
65 // calculez fi(i) in O(sqrt(n))
66 for(i=1;i<=n;i++)
67 {
68 fi[i]=i;
69 desc(i);
70 for(j=1;j<=nf;j++)
71 {
72 fi[i]=fi[i]/b[j];
73 fi[i]=fi[i]*(b[j]-1);
74 }
75 }
76
77 for(i=1;i<=n/2;i++)
78 T+=2*fi[i];
79
80 for(i=n/2+1;i<=n;i++)
81 T+=fi[i];
82
83 g<<T - (n-2) - 3<<"\n";
84
85 f.close();
86 g.close();
87
88 return 0;
89 }
19.6 telefon
Problema 6 - telefon 100 de puncte
Dorel, plictisit de puzzle-ul pe care l-a upgradat ieri, a decis s mearg afar cu ceilalµi copii.
El îi prive³te pe cei N copii cum joac âtelefonul f r r.
Jocul decurge în felul urm tor:
- Iniµial, copiii se a³az pe axa Ox, copilul i la distanµa Xi metri faµ de origine.
- Copilul cel mai aproape de origine alege un cuvânt secret ³i îl transmite celui din dreapta lui;
cel din dreapta lui îl transmite urm torului ³i a³a mai departe pân se ajunge la ultimul copil.
Pentru a transmite cuvântul, ecare copil trebuie s mearg pân la copilul din dreapta lui.
Toµi copiii se deplaseaz cu viteza constant de 1 metru/secund .
Cu toate acestea, pentru a evita deplasarea ecare copil dispune de un dispozitiv de tip walkie-
talkie ce permite transmiterea unui cuvânt mai departe. Toate staµiile walkie-talkie au o raz de
acµiune R, setat la începutul unei runde de joc (exprimat în metri) ce nu poate modicat
pe parcursul jocului. Staµiile sunt conectate la aceea³i surs de alimentare care are B unit µi de
energie.
în funcµie de raza de acµiune setat , copiii pot sau nu s foloseasc sistemul walkie-talkie pentru
a nu se mai deplasa. Mai exact, dac un copil ar trebui s parcurg o distanµ mai mic sau egal
cu R ca s transmit cuvântul celui din dreapta sa ³i bateria sursei are cel puµin R unit µi de
energie r mase, acesta poate folosi sistemul walkie-talkie ca s transmit instantaneu cuvântul
secret, iar bateria se va desc rca cu R unit µi de energie. Cu toate acestea, chiar ³i cu sistemul
walkie-talkie, un copil nu are voie s transmit mesajul decât primului copil situat în dreapta lui.
Copiii doresc ca jocul s se termine cât mai repede, a³a c vor seta o raz de acµiune convenabil
³i vor alege s foloseasc sau nu sistemul walkie-talkie, pentru a minimiza timpul necesar ca toµi
cei N copii s ae cuvântul secret.
Dorel dore³te s se al ture jocului, a³a c în a doua parte a jocului va intra ³i el în rând. Dorel
se va a³eza pe axa Ox, undeva între primul ³i ultimul copil, la o anumit distanµ de origine unde
nu se a un alt copil.
Cerinµe
CAPITOLUL 19. ONI 2019 294
Date de intrare
Fi³ierul de intrare telefon.in conµine pe prima linie dou numere naturale N ³i B cu semni-
caµia din enunµ. Pe cea de-a doua linie se a N numere naturale nenule distincte Xi , în ordine
strict cresc toare, unde Xi reprezint distanµa copilului i faµ de origine, 1 & i & N .
Date de ie³ire
Fi³ierul de ie³ire telefon.out va conµine dou numere naturale C1 C2, separate printr-un
spaµiu, unde C1 reprezint r spunsul la cerinµa 1 iar C2 r spunsul la cerinµa 2.
Restricµii ³i preciz ri
a 2N 105
a 1B109, 1Xi109
a Se garanteaz c Dorel are cel puµin o poziµie liber pe care se poate a³eza
a Un copil poate alege între a se deplasa sau a folosi walkie-talkie pentru a transmite un mesaj
a Copiii pot seta o noua raz de acµiune a walkie-talkie când Dorel intr în joc
a Pentru prima cerinµ se acord 40 puncte
a Pentru a doua cerinµ se acord 60 puncte
a Pentru teste în valoare de 15 puncte N, B & 10
2
Exemple
telefon.in telefon.out Explicaµii
6 15 86 N=6, B=15
7 9 12 16 21 27 X[1-6]=[7,9,12,16,21,27]
Pentru a rezolva cerinµa 1 e sucient s consider m c R poate lua valori doar din mulµimea
distanµelor dintre oricare 2 copii.
CAPITOLUL 19. ONI 2019 295
Pentru a rezolva a 2-a cerinµ trebuie s observ m c R poate s nu aparµin din mulµimea
distanµelor dintre oricare 2 copii. De asemenea, trebuie s îl a³ez m pe Dorel astfel încât s
spargem o distanµ în dou buc µi. Mai exact, noi am vrea o distanµ X mai mare decât R (raza
noastra curent ) pe care s o âsp rgem în 2 buc µi, de lungimi R respectiv X R. Mereu
vom folosi distanµa de lungime R dar dac ne uit m mai atent observ m ca exist cazuri în care
am dori s folosim ³i o bucat de lungime X R a³a c vom c uta cea mai mare distanµa X cu
proprietatea c X & 2R (pentru a maximiza X R). Pentru a nu c uta liniar acest X putem
menµine un pointer în faµ .
Soluµie - 15 puncte
Se observ c pentru o valoare xat a lui R strategia optim este s lu m cele mai mari
distanµe mai mici sau egale cu R. Astfel, prima dat vom calcula distanµele între oricare 2 copii
consecutivi ³i le vom sorta cresc tor. Având acest vector sortat, pentru ecare valoare a lui R în
intervalul 1, B c ut m cea mai mare distanµ mai mic sau egal cu R ³i vom verica cât de
mult ne putem extinde în stânga acestei distanµe (în limita bateriei) pentru a minimiza cât mai
mult durata jocului.
2
Aceast soluµie are complexitate O N B
Soluµie - 50 puncte
Pentru a optimiza soluµia anterioar observ m c pentru o valoare xat a lui R este sucient
o singur parcurge a vectorului de distanµe folosind 2 pointeri. Pointerul din dreapta ne spune cea
mai mare distanµ mai mic sau egal cu R iar pointerul din stânga cat de mult ne putem extinde.
De ecare dat când incrementam pointerul din dreapta vom verica dac dap ³im limita bateriei,
caz în care vom incrementa ³i pointerul din stânga.
Complexitate: O N B
Soluµie - 70 puncte
Optimizând în continuare algoritmul, observ m c nu trebuie s iteram prin toate valorile pe
care le poate lua R. În schimb, vom începe cu R 1 ³i vom incrementa R în funcµie de distanµa
maxim pe care o consider m la momentul actual(pointerul din dreapta).
Pentru a 2-a cerinta este necesar sa testam toate valorile pe care le poate lua R si nu doar din
multimea distantelor.
Complexitate: O N log N B
Soluµie - 100 puncte
Continuând soluµia anterioar , algoritmul optim nu va lua în considerare pentru R toate valorile
din intervalul 1, B ci doar valorile din mulµimea r1, 2, 3, 4, 5, ...., sqrt B , B, B ©2, B ©3, B ©4, B ©5, .., B ©sqrt B x.
Astfel reducând cardinalul mulµimii de valori pentru R de la B la 2 sqrt B .
Complexitate: O N log N sqrt B
Soluµie alternativ - 100 puncte
O mic optimizare a soluµiei anterioare const în observaµia c nu sunt necesare decât cei mai
mari N candidaµi dintre cei 2sqrt B (în esenµ , B , B ©2, B ©3, ..., B ©N ). Astfel se obµine o soluµie
de complexitate O N log N , independent de B .
12
13 int32_t main()
14 {
15 ifstream cin("telefon.in");
16 ofstream cout("telefon.out");
17
18 cin >> n >> m;
19 for(int i = 1; i <= n; i++)
20 {
21 int a;
22 cin >> a;
23 v.push_back(a);
24 }
25
26 for(int i = 0; i < v.size() - 1; i++)
27 {
28 dist.push_back(v[i + 1] - v[i]);
29 vals.push_back(v[i + 1] - v[i]);
30 total += v[i + 1] - v[i];
31 }
32
33 sort(dist.begin(), dist.end());
34
35 int i;
36 for(i = 1; i*i <= m; i++)
37 vals.push_back(i),vals.push_back(m/i);
38
39 vals.push_back(i), vals.push_back(i + 1);
40
41 sort(vals.begin(), vals.end());
42
43 int first = 0;
44 int semnal = 0;
45 int second = 0;
46 int extra = 0;
47 current = dist[0];
48
49 while(first < dist.size())
50 {
51 while(semnal + 1 < vals.size() && vals[semnal] < dist[first])
52 semnal++;
53
54 if(vals[semnal] < dist[first])
55 break;
56
57 long long delta = vals[semnal];
58
59 while((first - second + 1) * delta > m)
60 current -= dist[second], second++;
61
62 while(extra+1 < dist.size() && dist[extra+1] - delta <= delta)
63 extra++;
64
65 if(extra == first && extra + 1 < dist.size())
66 extra++;
67
68 int aux = second;
69 long long size = (first-second+1) * delta;
70 if(extra != first)
71 {
72 long long z = current;
73 long long plus = dist[extra] - delta;
74
75 if(size + delta <= m)
76 size += delta, z += delta;
77 else
78 if(aux <= first)
79 z += delta - dist[aux], aux++;
80
81 if(size + delta <= m)
82 size += plus, z += delta;
83 else
84 if(aux <= first && dist[aux] < plus)
85 z += plus - dist[aux];
86
87 best = max(z, best);
CAPITOLUL 19. ONI 2019 297
88 }
89
90 nokid = max(current, nokid);
91 best = max(current, best);
92 if(first + 1 == dist.size())
93 first++;
94 else
95 if(semnal+1 < vals.size() && vals[semnal+1] < dist[first+1])
96 semnal++;
97 else
98 first++,current+= dist[first];
99 }
100
101 long long z = 0;
102 cout<<max(z,total-nokid) << ’ ’;
103 cout<<max(z,total-best) << ’\n’;
104 }
56 answer = numeric_limits<int>::max();
57 N = X.size();
58 for (int cover = N + 1, end = -1, magic = 0; cover > 0; --cover)
59 {
60 int max_cover = B / cover;
61 // 3 ways
62 // we cover cover of already existant values
63 // we cover cover - 1 of already existent values + some part
64 // of the biggest
65 // we cover cover - 2 of already + the biggest <= 2 * max_cover
66
67 while (end + 1 < N && X[end + 1] <= max_cover)
68 {
69 ++end;
70 }
71
72 if (end == -1)
73 continue;
74
75 while (magic + 1 < N && X[magic + 1] <= 2 * max_cover)
76 ++magic;
77
78 // ignore Dorel
79 int now = partial[N - 1] - partial[end];
80 if (end - cover >= 0)
81 now += partial[end - cover];
82
83 answer = min(answer, now);
84
85 // Dorel once
86 if (cover > 0)
87 {
88 now = partial[N - 1] - partial[end];
89 if (end - (cover - 1) >= 0)
90 now += partial[end - (cover - 1)];
91
92 if (end < N - 1)
93 now -= min(max_cover, X[N - 1]);
94
95 answer = min(answer, now);
96 }
97
98 // Dorel twice
99 if (cover > 1)
100 {
101 now = partial[N - 1] - partial[end];
102 if (end - (cover - 2) >= 0)
103 now += partial[end - (cover - 2)];
104
105 if (end < magic)
106 now -= X[magic];
107
108 answer = min(answer, now);
109 }
110 }
111
112 cout << answer << "\n";
113 }
15
16 int magic = sqrt(v) + 2;
17 vector<int> cands = dists;
18
19 if (!opts.count("cands_are_dists"))
20 {
21 cands.clear();
22 for (int i = 1; i <= magic && i <= v; ++i)
23 {
24 cands.push_back(i);
25 cands.push_back(v / i);
26 }
27
28 sort(cands.rbegin(), cands.rend());
29
30 for (auto& x : cands)
31 x = v / x;
32 }
33 else
34 {
35 for (auto x : dists)
36 if (x > 1)
37 cands.push_back(x / 2);
38
39 sort(cands.begin(), cands.end());
40 }
41
42 vector<long long> bests(3, 0);
43
44 long long now = 0;
45 int l = 0, r = 0, p = -1;
46
47 for (auto delta : cands)
48 {
49 // bests[0] = bests[1] = bests[2] = 0;
50
51 int phones = v / delta;
52 while (r < n && dists[r] <= delta)
53 {
54 now += dists[r];
55 ++r;
56 }
57
58 while (r - l > phones)
59 {
60 now -= dists[l];
61 ++l;
62 }
63
64 bests[0] = max(bests[0], now);
65 if (phones >= 1 && r < n)
66 {
67 long long xnow = now + delta;
68 if (r - l == phones) xnow -= dists[l];
69 bests[1] = max(bests[1], xnow);
70 }
71
72 while (p + 1 < n && dists[p + 1] <= 2 * delta)
73 ++p;
74
75 if (phones >= 2 && p >= r)
76 {
77 long long xnow = now + dists[p];
78 if (r - l >= phones - 1) xnow -= dists[l];
79 if (r - l == phones) xnow -= dists[l + 1];
80 bests[2] = max(bests[2], xnow);
81 }
82
83 /*
84 for (auto x : dists) cerr << x << " "; cerr << endl;
85 cerr << "delta: " << delta << endl;
86 cerr << "(phones: " << phones << ")" << endl;
87 cerr << "bests: " << bests[0] << " " << bests[1]
88 << " " << bests[2] << endl;
89 cerr << endl;
90 */
CAPITOLUL 19. ONI 2019 300
91 }
92
93 long long ans = 0;
94
95 ans = max(ans, bests[0]);
96 ans = max(ans, bests[1]);
97 ans = max(ans, bests[2]);
98
99 return make_pair(sum - bests[0], sum - ans);
100 }
101
102 int32_t main()
103 {
104 ifstream cin("telefon.in");
105 ofstream cout("telefon.out");
106
107 int n, v; cin >> n >> v;
108 int last = -1;
109
110 vector<int> dists;
111
112 for (int i = 0; i < n; ++i)
113 {
114 int x; cin >> x;
115 if (i) dists.push_back(x - last);
116 last = x;
117 }
118
119 auto p = Solve(v, dists, {});
120 cout << p.first << " " << p.second << endl;
121
122 return 0;
123 }
40 split = ld + 1;
41 while (split < d.size() && d[split] <= 2 * signals[k])
42 split++; /// Fixate split
43
44 bonus[0] = bonus[1] = 0;
45 if (split > 0 && ld != d.size())
46 {
47 bonus[0] = min(signals[k], d[split - 1]);
48 bonus[1] = max(d[split - 1] - signals[k], 0LL);
49 if (bonus[1] > signalSize) bonus[1] = 0;
50 }
51
52 saved = 0;
53 int spaceLeft = b / signalSize - (ld - ls);
54 if (spaceLeft <= 0)
55 {
56 for (int r = ls ; r < ld ; r++)
57 {
58 if (r - ls == 0 || r - ls == 1)
59 saved += (bonus[r - ls] > d[r] ? bonus[r - ls] : d[r]);
60 else
61 saved += d[r];
62 }
63 }
64 else if (spaceLeft == 1)
65 {
66 for (int r = ls ; r < ld ; r++)
67 {
68 if (r - ls == 0)
69 saved += (bonus[1] > d[r] ? bonus[1] : d[r]);
70 else
71 saved += d[r];
72 }
73
74 saved += bonus[0];
75 }
76 else
77 {
78 for (int r = ls ; r < ld ; r++)
79 saved += d[r];
80
81 saved += bonus[0] + bonus[1];
82 }
83
84 best = max(best, saved);
85 }
86
87 fout << total - best;
88 }
89
90 int32_t main()
91 {
92 fin >> n >> b;
93 fin >> x;
94
95 for (i = 2 ; i <= n ; i++)
96 {
97 fin >> y;
98 d.push_back(y - x);
99 total += y - x;
100
101 x = y;
102 }
103
104 sort(d.begin(), d.end());
105 for (i = 0 ; i < d.size() ; i++)
106 {
107 cout << d[i] << ’ ’;
108 }
109
110 for (i = 1 ; i <= sqrt(b) ; i++)
111 signals.push_back(i);
112
113 for (i = int32_t(sqrt(b)) ; i >= 1 ; i--)
114 signals.push_back(b / i);
115
CAPITOLUL 19. ONI 2019 302
116 subtask();
117 solve();
118
119 return 0;
120 }
Capitolul 20
ONI 2018
20.1 bazaf
Problema 1 - bazaf 100 de puncte
În matematic factorialul unui num r natural nenul K este notat cu K! ³i este egal cu produsul
numerelor naturale nenule mai mici sau egale cu K .
Exemple: 1! 1; 2! 1 2 2; 3! 1 2 3 6, ... , K! 1 2 3 ... K .
Orice num r natural N poate descompus cu ajutorul numerelor factoriale astfel:
Cerinµe
1. S se determine descompunerea în baz factorial a unui num r natural X dat.
2. Cunoscând o descompunere oarecare a unui num r natural Y s se determine descompunerea
în baz factorial a acestuia.
Date de intrare
Fi³ierul de intrare este bazaf.in
Acesta conµine pe primul rând un num r natural V care poate avea doar valorile 1 sau 2 cu
urm toarea semnicaµie:
a dac valoarea lui V este 1, pe a doua linie a ³ierului de intrare se g se³te un num r natural
X cu semnicaµia de mai sus;
a dac valoarea lui V este 2, pe a doua linie a ³ierului de intrare se g se³te o descompunere
a unui num r Y sub forma unui ³ir de valori naturale în care primul termen este m, urmat de m
valori fi , care respect condiµiile fi ' 0, cu 1 & i $ m ³i fm j 0, desp rµite prin câte un spaµiu, cu
semnicaµia de mai sus
Date de ie³ire
Fi³ierul de ie³ire este bazaf.out
Dac valoarea V este 1 atunci ³ierul de ie³ire va conµine descompunerea în baza factorial a
num rului X iar dac valoarea V este 2 atunci ³ierul de ie³ire va conµine descompunerea în baza
factorial a num rului Y .
Descompunerea în baz factorial presupune scrierea în ³ierul de ie³ire a unei singure linii
sub forma unui ³ir de valori naturale în care primul termen este m, urmat de m valori fi , care
respect condiµiile 0 & fi & i, cu 1 & i $ m ³i 0 $ fm & m, desp rµite prin câte un spaµiu, având
semnicaµia de mai sus.
Restricµii ³i preciz ri
303
CAPITOLUL 20. ONI 2018 304
2 & X & 10
15
a
a 1 $ m & 100 000
a 0 & fi & 10
9
a Pentru rezolvarea corect a primei cerinµ se va acorda 30% din punctaj, iar pentru cea de-a
doua cerinµ se va acorda 70% din punctaj.
Exemple:
bazaf.in bazaf.out Explicaµii
1 3122 V 1, deci se rezolv doar prima cerinµ
17 X 17
Descompunerea num rului X 17 în baz factorial conµine 3
termeni ³i este format din coecienµii 1, 2, 2 (17 = 1! 1 + 2!
2 + 3! 2);
2 2 10 5 3013 V 2, deci se rezolv doar a doua cerinµ
Descompunerea 2 10 5 este o descompunere cu 2 termeni având
coecienµii 10, 5 ³i corespunde num rului Y 20.
Descompunerea în baz factorial a num rului
Y = 20 va 3 0 1 3 (20 = 1! 0 + 2! 1 + 3! 3)
Timp maxim de executare/test: 0.8 secunde
Memorie: total 128 MB din care pentru stiv 32 MB
Dimensiune maxim a sursei: 10 KB
Pentru rezolvarea primei cerinµe se construie³te un vector cu toate valorile lui k! pentru k & 20
apoi printr-o strategie Greedy se determin care este cel mai apropiat factorial mai mic decât
num rul dat, se calculeaz coecientul acelui termen, se scade din num rul dat termenul respectiv,
se memoreaz în vectorul de descompuneri coecientul calculat ³i se reia operaµia pân când
num rul curent devine 0.
Pentru rezolvarea celei de-a doua cerinµe se observ înc de la început c o soluµie care s
calculeze num rul Y ³i apoi s determine descompunerea în baz factorial folosind ideea de la
cerinµa anterioar nu poate obµine puncte deoarece descompunerea dat are un num r foarte mare
de termeni ³i corespunde unui num r Y foarte mare.
Soluµia const într-o observaµie matematic ³i anume c se poate parcurge vectorul descom-
punerii ³i dac un coecient este mai mare decât limita impus vom calcula cât din valoarea
respectiv va transportat c tre urm torul coecient.
Se actualizeaz astfel atât coecientul curent cât ³i cel urm tor ³i în cazul c nd ultimul coe-
cient este mai mare decât limita impus se adaug noi coecienµi.
O astfel de soluµie nu presupune calcularea num rului asociat descompunerii.
Exemplu: Pentru descompunerea 4 7 12 14 9 se trece prin urm toarele etape
4 7 12 14 9 (7 1! = 1 + 3 2!)
4 1 15 14 9 (15 2! = 0 + 5 3!)
4 1 0 19 9 (19 3! = 3 + 4 4!)
4 1 0 3 13 (13 4! = 3 + 2 5!) s-a mai ad ugat un termen
5 1 0 3 3 2
71 printf("\n");
72 }
73
74 int main ()
75 {
76 freopen("bazaf.in","r",stdin);
77 freopen("bazaf.out","w",stdout);
78
79 scanf("%d", &p);
80 assert(1 <= p && p <= 2);
81 if(p == 1)
82 {
83 solve1();
84 }
85 else
86 {
87 solve2();
88 }
89
90 return 0;
91 }
52
53 for(i=1;i<=m;i++)
54 fin >> fi[i];
55
56 for(i=1;i<=m-1;i++)
57 {
58 c=fi[i]/(i+1);
59 r=fi[i]%(i+1);
60 fi[i]=r;
61 fi[i+1]+=c;
62 }
63
64 while (fi[m]>m)
65 {
66 c=fi[m]/(m+1);
67 r=fi[m]%(m+1);
68 fi[m]=r;
69 fi[++m]+=c;
70 }
71
72 fout << m <<" ";
73 for(i=1;i<=m;i++)
74 fout << fi[i]<<" ";
75 fout << "\n";
76 }
77
78 fout.close();
79 fin.close();
80 return 0;
81 }
37 }
38 v=v%f[j];
39 }
40 fout<<nx;
41
42 for(int j=1;j<=nx;j++)
43 fout<<" "<<x[j];
44 }
45
46 if (p==2)
47 {
48 fin >> m;
49 long long s=0;
50 for(i=1;i<=m;i++)
51 {
52 fin >> fi[i];
53 s+=fi[i]*f[i];
54 }
55
56 v=s;
57 nx=0;
58 for(int j=20;j>=1;j--)
59 {
60 x[j]=v/f[j];
61 if(x[j]>0 && nx==0)
62 {
63 nx=j;
64 }
65 v=v%f[j];
66 }
67 fout<<nx;
68
69 for(int j=1;j<=nx;j++)
70 {
71 fout<<" "<<x[j];
72 }
73
74 fout << "\n";
75 }
76
77 fout.close();
78 fin.close();
79 return 0;
80 }
20.2 mexitate
Problema 2 - mexitate 100 de puncte
Se d o matrice A cu N linii ³i M coloane cu elemente numere naturale nu neap rat distincte.
Pentru o submatrice denim mex-ul acesteia ca ind cea mai mic valoare natural nenul care
nu apare în aceasta.
Cerinµe
S se calculeze produsul mex-urilor tuturor submatricelor având K linii ³i L coloane ale matricei
A.
Date de intrare
Fi³ierul mexitate.in conµine pe prima linie patru numere naturale N , M , K ³i L separate
printr-un spaµiu cu semnicaµia din enunµ.
Pe ecare dintre urm toarele N linii se a câte M numere naturale nenule, desp rµite prin
câte un spaµiu, reprezentând valorile matricei.
Date de ie³ire
Fi³ierul mexitate.out va conµine un singur num r natural reprezentând produsul mex-urilor
tuturor submatricelor având K linii ³i L coloane ale matricei modulo 1 000 000 007.
Restricµii ³i preciz ri
CAPITOLUL 20. ONI 2018 310
Exemple:
mexitate.in mexitate.out Explicaµii
3 4 2 3 400 N = 3 ³i M = 4
1 2 3 2 K = 2 ³i L = 3
2 3 1 4 Submatricile cu 2 linii ³i 3 coloane sunt:
1 1 2 6
1 2 3 cu mex-ul 4
231
2 3 2 cu mex-ul 5
314
2 3 1 cu mex-ul 4
112
3 1 4 cu mex-ul 5
126
Soluµie 20 de puncte:
Pentru ecare submatrice de K * L, se parcurg elementele ³i se pun într-un vector de frecvenµ .
Pentru a determina r spunsul (primul element lips ), este sucient s parcurgem vectorul de
frecvent si s a m prima poziµie cu frecvenµa 0.
Observ m c mutarea la stânga-dreapta o facem de ordinul O(N * M), iar mutarea în jos
de ordinul O(N). Complexitatea pân în acest punct devine O(N * M * K + N * L), ignorând
momentan partea în care trebuie s determin m rapid mex-ul din vectorul de frecvenµ .
2. Avem restrictia N * M <= 400.000
=> K * L <= 400.000
=> min(K, L) <= sqrt(400.000)
Daca K <= L
=> k <= sqrt(400.000) = sqrt(VMAX)
=> complexitatea devine O(N * M * sqrt(VMAX) + N * L)
În schimb, dac K > L este nevoie s rotim matricea ³i s aplic m acela³i procedeu, comple-
xitatea devenind O(N * M * L + M * K), adic O(N * M * sqrt(VMAX) + M * K).
Aplicând acest hibrid, complexitatea devine O(min(N * M * sqrt(VMAX) + N * L, N * M
*sqrt(VMAX) + M * K)). Din moment ce N * L respectiv M * K sunt irelevante, complexitatea
nal va : O(N * M * sqrt(VMAX)).
3. R mâne de v zut cum putem determina rapid care este mex-ul cu ajutorul vectorului de
frecvenµ (din moment ce acesta este foarte mare, nu putem merge element cu element).
Aplicând primele 2 observaµii, deducem c avem O(N * M * sqrt(VMAX)) valori care se
modic (update-uri), respectiv O(N * M) interog ri de mex (query-uri).
Putem echilibra aceast complexitate dac am avea o structur ce foloseste O(1) pe update ³i
O(sqrt(VMAX)) pe query. Putem µine buc µi de dimensiune sqrt(VMAX) pe vectorul de frec-
venµ , ecare bucat având marcat câte elemente apar cel puµin o dat . Vectorul de frecvenµ
³i informaµia pentru ecare bucat de radical se pot menµine u³or la update în O(1). La query,
pentru ecare bucat de radical putem s o s rim dac toate elementele apar în acel interval,
respectiv s aplicam un brute-force dac r spunsul este în interiorul acelui interval. Mai exact, s -
rim elemente din radical în radical (vom face asta de maxim sqrt(VMAX) ori), respectiv c utam
element cu element intr-un interval de lungime radical. Astfel, vom putea determina valoarea
mex-ului în maxim sqrt(VMAX) pa³i.
102
103 int aux = n;
104 n = m;
105 m = aux;
106
107 aux = l;
108 l = k;
109 k = aux;
110 }
111 else
112 {
113 for(int i = 1; i <= n; i++)
114 {
115 matrix[i].push_back(0);
116 for(int j = 1; j <= m; j++)
117 {
118 matrix[i].push_back(matrix2[i][j]);
119 }
120 }
121 }
122
123 int last = 1;
124 for(int i = 1; i <= n * m; i++)
125 {
126 indexB[i] = last;
127 if(i % bucket == 0)
128 last++;
129 }
130
131 initializeaza();
132 for(int i = 1; i <= n - k + 1; i++)
133 {
134 sign = ((i&1) ? +1 : -1);
135 if(sign == 1)
136 {
137 for(int j = 2; j <= m - l + 1; j++)
138 {
139 deleteElements(i, j - 1, i + k - 1, j - 1);
140 addElements(i, j + l - 1, i + k - 1, j + l - 1);
141 query();
142 }
143
144 if(i <= n - k)
145 {
146 deleteElements(i, m - l + 1, i, m);
147 addElements(i + k, m - l + 1, i + k, m);
148 query();
149 }
150 }
151 else
152 {
153 for(int j = m - l; j >= 1; j--)
154 {
155 deleteElements(i, j + l, i + k - 1, j + l);
156 addElements(i, j, i + k - 1, j);
157 query();
158 }
159
160 if(i <= n - k)
161 {
162 deleteElements(i, 1, i, l);
163 addElements(i + k, 1, i + k, l);
164 query();
165 }
166 }
167 }
168
169 printf("%lld\n", answer);
170
171 return 0;
172 }
2 Narcis Gemene
3 */
4 #include <iostream>
5 #include <cstdio>
6 #include <vector>
7 #include <cassert>
8
9 using namespace std;
10
11 const int MOD = 1000000007;
12
13 void Update(vector<int>&frecv, vector<int>&buckets, int bucket, int i, int val)
14 {
15 if (frecv[i] == 0)
16 buckets[i/bucket]++;
17 frecv[i] += val;
18 if (frecv[i] == 0)
19 buckets[i/bucket]--;
20 }
21
22 int Query(vector<int>&frecv,vector<int>&buckets, int bucket)
23 {
24 int i;
25 for(i = 0; buckets[i] == bucket; i++);
26 for(i = bucket*i;frecv[i] != 0; i++);
27 return i;
28 }
29
30 int main()
31 {
32 freopen("mexitate.in", "r", stdin);
33 freopen("mexitate.out", "w", stdout);
34
35 int n, m, k, l;
36
37 cin >> n >> m >> k >> l;
38 assert(1 <= n*m && n*m <= 400000);
39
40 vector<vector<int>>a(n, vector<int>(m,0));
41 vector<int>frecv(n * m + 5), buckets(n * m + 5);
42
43 int bucket = 1;
44 for(;bucket*bucket < n*m ;bucket++);
45
46 Update(frecv, buckets, bucket, 0, 1);
47
48 for(auto&line: a)
49 for(auto &elem: line)
50 {
51 cin >> elem;
52 assert(1 <= elem && elem <= n * m);
53 }
54
55 if(k > l)
56 {
57 vector<vector<int>> b = a;
58
59 swap(n, m);
60 swap(k, l);
61
62 a = vector<vector<int>>(n, vector<int>(m,0));
63
64 for (int i = 0; i < n; i++)
65 for (int j = 0; j < m; j++)
66 a[i][j] = b[j][i];
67 }
68
69 for(int i = 0; i < k; i++)
70 {
71 for (int j = 0;j < l;j ++)
72 {
73 Update(frecv, buckets, bucket, a[i][j], 1);
74 }
75 }
76
77 const int left[] = {0, m - 1};
CAPITOLUL 20. ONI 2018 315
20.3 plaja
Problema 3 - plaja 100 de puncte
Zizi î³i va petrece concediul în aceast var într-o frumoas staµiune de la Marea Neagr . Acolo
va sta N zile. Zilele sunt numerotate de la 1 la N . În ecare dintre cele N zile de concediu, ea
intenµioneaz s fac plaj un num r cât mai mare de unit µi de timp. Va trebui s µin seama
totu³i de prognoza meteo, care este nefavorabil în K dintre cele N zile, respectiv în zilele z1 , z2 ,
..., zk . În ecare dintre aceste K zile va ploua sau va prea mult soare, iar Zizi va trebui s -³i
limiteze timpii de plaj la cel mult t1 , t2 , ..., tk unit µi de timp.
Deasemenea, din motive de confort zic, Zizi dore³te ca diferenµa în valoare absolut a timpilor
de plaj între oricare dou zile consecutive s nu dep ³easc T .
Cerinµe
Cunoscând zilele z1 , z2 , ..., zk în care exist limit rile t1 , t2 , ..., tk pentru timpul de plaj ³i
valoarea T , s se determine num rul maxim de unit µi de timp pe care Zizi le poate petrece la
plaj într-o singur zi dintre cele N zile de concediu.
Date de intrare
Fi³ierul plaja.in conµine pe prima linie trei numere naturale N K ³i T separate printr-un
spaµiu, reprezentând num rul de zile de concediu, num rul de zile în care exist limit ri pentru
timpul de plaj ³i diferenµa maxim admis a timpilor de plaj pentru oricare dou zile consecutive.
CAPITOLUL 20. ONI 2018 316
Pe ecare dintre urm toarele K linii se a câte dou numere z ³i t, desp rµite printr-un spaµiu,
reprezentând num rul de ordine al unei zile cu limit ri pentru timpul de plaj , respectiv limita
de timp pentru ziua respectiv .
Valorile z1 , z2 , ..., zk sunt în ordine strict cresc toare.
Date de ie³ire
Fi³ierul plaja.out va conµine pe prima linie un singur num r natural tmax, reprezentând
num rul maxim de unit µi de timp pe care Zizi le poate petrece f când plaj într-una din cele N
zile de concediu.
Restricµii ³i preciz ri
a 1 & N & 1 000 000 000
a 1 & K & 100 000
a 1 & t1 , t2 , ..., tk & 100 000
a 1 & z1 $ z2 $ ... $ zk & N
a 2 & T & 1 000 000
a Pentru 20% din punctajul total exist teste cu 1 & N, K & 1 000
a Pentru 65% din punctajul total exist teste cu 1 & N, K & 100 000
Exemple:
plaja.in plaja.out Explicaµii
313 8 În ziua 1 timpul de plaj este limitat la 2 unit µi de timp. În
12 ziua a doua timpul maxim de plaj este 2 + 3, iar în ziua a
treia, timpul maxim este 2 + 3 + 3 = 8 unit µi de timp.
5 2 11 16 În ziua 2 timpul de plaj este limitat la 2 unit µi de timp, iar în
22 zilele 1 ³i 3 nu exist limitare. Atunci timpul maxim de plaj
45 pentru zilele 1 sau 3 este 2 + 11 = 13.
În ziua 4 timpul de plaj este limitat la 5 unit µi de timp, iar în
ziua 5 nu exist limitare. Deci în ziua 5 timpul maxim de plaj
este 5 + 11 = 16.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 128 MB din care pentru stiv 32 MB
Dimensiune maxim a sursei: 10 KB
un ³ir de dimensiune N , ceea ce duce la dep ³ire de memorie pentru testele cu N foarte mare.
Punctaj acordat: aproximativ 65 de puncte.
Soluµie O(K * log T)
Se observ c parcurgând zilele cu limit ri pentru timpul de plaj , este posibil s g sim o zi
d[i] cu restricµia de timp t[i], care face imposibil faptul ca în ziua d[i + 1] s se ating valoarea t[i
+ 1].
Astfel, vom parcurge cele K zile cu restricµii ³i pentru ecare valoare t[i] vom reduce valoarea
t[i + 1] la o nou valoare posibil a atins . Apoi acela³i lucru se va face pornind de la sfâr³itul
³irului t c tre începutul s u.
În etapa urm toare se poate c uta binar r spunsul pentru ecare pereche de zile de forma (d[i],
d[i + 1]), iar vericarea posibilit µii de a se atinge o valoare propus t0, de face printr-o testare
relativ simpl :
d[i + 1] - d[i] >= (t0 - t[i] + T - 1) / T + (t0 - t[i + 1] + T - 1) / T;
Punctaj acordat: 100 de puncte
Solutie O(k) (Balµatu Andrei-Mircea)
Iniµial se iau cele k zile restricµionate ³i se aduc la valorile maximale posibile, adic pentru o zi
1 <= i <= m cu valoarea initial t(i) ³i pozitia x(i), dac exist o alt zi j ³i t(j) + T * abs(x(i)
- x(j)) < t(i), atunci t(i) se scade deoarece este restricµionat de alte zile. (abs - funcµia modul).
Apoi observ m c putem aa r spunsul între oricare dou zile consecutive în O(1). Având cele
dou zile (X - în stanga, Y - în dreapta), ³tim c ecare va cre³te cu T în drumul spre ziua maxim .
Astfel, aducem pe minimul dintre ele, adic min(t(X), t(Y)) la un num r nr <= max(t(X), t(Y))
cât mai mare, dup care ambele încep s creasc cu T alternativ, spre o pozitia P necunoscut .
În funcµie de paritatea secventei de zile r mase dup ce am crescut minimul dintre ele, putem
aa poziµia de valoare maxim (P) în funcµie de paritatea secvenµei de zile r mase. Punctaj: 100
de puncte
26 d = t = VLL(K + 1);
27
28 for (int i = 1; i <= K; ++i)
29 fin >> d[i] >> t[i];
30
31 for (int i = 1; i < K; ++i)
32 t[i + 1] = min(t[i + 1], t[i] + (d[i + 1] - d[i]) * T);
33
34 for (int i = K - 1; i >= 1; --i)
35 t[i] = min(t[i], t[i + 1] + (d[i + 1] - d[i]) * T);
36
37 LL res = 0, l, r, m, tmp;
38
39 for (int i = 1; i < K; ++i)
40 {
41 l = max(t[i], t[i + 1]), r = 1LL * N * T;
42 while (l <= r)
43 {
44 m = (l + r) / 2;
45 if (Try(m, i))
46 {
47 l = m + 1;
48 tmp = m;
49 }
50 else
51 r = m - 1;
52 }
53 res = max(res, tmp);
54 }
55 res = max(res, max(t[K] + (N - d[K]) * T, t[1] + (d[1] - 1) * T));
56 fout << res;
57
58 }
59
60 bool Try(LL t0, int i)
61 {
62 return d[i+1] - d[i] >= (t0 - t[i] + T-1) / T + (t0 - t[i+1] + T-1) / T;
63 }
35 t.push_back(time);
36 }
37
38 long long l = 0, r = (1LL << 35), m;
39 long long res = 0;
40
41 while (l <= r)
42 {
43 m = (l + r) / 2;
44 if (Try(m))
45 {
46 res = m;
47 l = m + 1;
48 }
49 else
50 r = m - 1;
51 }
52
53 fout << res;
54 }
55
56 bool Try(long long t0)
57 {
58 vector <Entry> e;
59
60 e.push_back( {1, 0} );
61 e.push_back({N + 1, -1});
62
63 int a, b;
64 for (int i = 0; i < K; i++)
65 if (t[i] < t0)
66 {
67 long long x = (t0 - t[i] - 1) / T;
68 a = max(d[i] - x, 1LL);
69 b = min(d[i] + x + 1, (long long)(N + 1));
70
71 e.push_back({a, 1});
72 e.push_back({b, -1});
73 }
74
75 sort(e.begin(), e.end());
76
77 long long cnt = 0;
78 for (int i = 0; i < e.size(); i++)
79 {
80 cnt += e[i].sgn;
81 if (cnt <= 0 && e[i].day <= N)
82 return true;
83 }
84
85 return false;
86 }
21 {
22 fin >> N >> K >> T;
23 int day, time;
24 for (int i = 0; i < K; ++i)
25 {
26 fin >> day >> time;
27 d.push_back(day);
28 t.push_back(time);
29 }
30
31 long long l = 0, r = (1LL * N * T), m;
32 long long res = 0;
33
34 while (l <= r)
35 {
36 m = (l + r) / 2;
37 if (Try(m))
38 {
39 res = m;
40 l = m + 1;
41 }
42 else
43 r = m - 1;
44 }
45
46 fout << res;
47 }
48
49 bool Try(long long t0)
50 {
51 vector <int> e(N + 2);
52 e[1] = 0;
53 e[N + 1] = -1;
54 int a, b;
55
56 for (int i = 0; i < K; i++)
57 if (t[i] < t0)
58 {
59 long long x = (t0 - t[i] - 1) / T;
60 a = max(d[i] - x, 1LL);
61 b = min(d[i] + x + 1, (long long)(N + 1));
62
63 e[a]++;
64 e[b]--;
65 }
66
67 long long cnt = 0;
68 for (int i = 1; i <= N; i++)
69 {
70 cnt += e[i];
71 if (cnt <= 0)
72 return true;
73 }
74 return false;
75 }
20.4 bsrec
Problema 4 - bsrec 100 de puncte
Fie un vector v sortat cresc tor cu N elemente naturale nenule
distincte pe care nu le cunoa³tem, dar pe care ne propunem s le
determin m.
Având la dispoziµie acest vector v , cu ajutorul urm torului algo-
ritm de c utare binar (vezi Figura 1) putem r spunde la query-uri
de forma:
Dându-se un num r X ³i un interval a, b se cere s se determine
cel mai mic element mai mare decât X aat în intervalul determinat
de indicii a ³i b, interval din vectorul v .
Se cunosc pa³ii pe care algoritmul de cautare binar i-a urmat
pentru diferite valori ale tripletului X, a, b.
CAPITOLUL 20. ONI 2018 324
Cerinµe
Dându-se N (lungimea vectorului), Q (num rul de query-uri apelate) ³i cele Q query-uri, s
se determine vectorul iniµial. Dac exist mai multe soluµii se va a³a soluµia minim lexicograc .
Dac nu exist soluµie se va a³a valoarea -1.
Un vector V 1 se consider mai mic lexicograc decât un alt vector V 2 dac exist un indice i
astfel încât: V 11 V 21, V 12 V 22, ..., V 1i 1 V 2i 1 ³i V 1i $ V 2i.
Cele Q query-uri sunt formate din:
Date de intrare
Fi³ierul bsrec.in conµine pe prima linie o valoare T reprezentând num rul de teste ce vor
efectuate.
Pentru ecare din cele T teste se va citi de pe prima linie valoarea N (num rul de elemente
ale vectorului), respectiv Q (num rul de query-uri), desp rµite prin câte un spaµiu.
Urm toarele linii descriu cele Q query-uri.
În cadrul unui query, prima linie va conµine o pereche de numere (X , M ) desp rµite printr-un
spaµiu, unde X reprezint valoarea c utat în vector, iar M num rul de pa³i efectuaµi în c utarea
binar a celei mai mici valori din vector care este mai mare decât X .
Pe urm toarea linie a query-ului se g se³te perechea de valori (a, b) având semnicaµia de mai
sus.
Urm toarele M 1 linii conµin perechi (st, dr) de valori naturale desp rµite prin câte un
spaµiu care reprezint indicii stânga, respectiv dreapta ce sunt a³aµi în urma ec rei iteraµii a
algoritmului de mai sus.
Date de ie³ire
Fi³ierul bsrec.out va conµine T linii, linia i conµinând r spunsul pentru testul i. Dac testul
admite soluµie, se vor a³a N numere naturale nenule strict cresc toare ce vor reprezenta valorile
vectorului v .
Deoarece exist mai multe soluµii, se va a³a soluµia minim lexicograc . Dac testul NU
admite soluµie, se va a³a -1.
Restricµii ³i preciz ri
a 1 & T & 10
a 1 & N, Q & 1000
a 1 & X & 1 000 000 000
a 1 & st & dr & N , cu excepµia ultimei perechi din c utarea binar unde st % dr
a Pentru 20% din punctajul total exist teste cu 1 & N, Q & 10 ³i soluµia minim lexicograc
admite valori pân în 20
a Se garanteaz c M & 15
Exemple:
Parcurgem toate iteraµiile c utarilor binare. Pentru o valoare X (pe care o c utam binar) ³i
o pereche (lef t, right) din c utarea binar se poate deduce o restricµionare de valoare pentru
elementul din mijloc mid lef t right©2, în funcµie de alegerea f cut de iteraµia urm toare.
Mai exact, pentru o pereche (lef t, right) urmat de o pereche (lef t2, right2) avem urm toarele
2 cazuri:
1. left == left2 ³i right2 < right: acest caz presupune c conditia v[mid] < X este fals , deci
v[mid] >= x
2. left < left2 ³i right2 == right: cazul presupune faptul c cond itia v[mid] < x este adevarat ,
deci v[mid] <= x - 1
În urma tuturor acestor relaµii, putem deduce c pentru ecare element v[i] din vector (i de
la 1 la N ), aceast valoare este m rginit inferior de o valoare downi, respectiv superior de o
valoare upi. Dac elementul nu este m rginit, downi este automat 0, iar upi = INF.
Ultima restricµie pe care trebuie s o impunem este faptul c v[i - 1] < v[i], pentru orice i de
la 2 la N.
Pentru a determina soluµia minim lexicograc, aplic m o strategie Greedy parcurgând vectorul
de la stânga la dreapta. Presupunând c am calculat deja soli, soluµia pentru elementul i,
soli 1 va maximul dintre soli 1 ³i downi 1. La nal, r mâne de vericat dac soli
<= upi pentru ecare i de la 1 la N . Dac toate restricµiile se respect , avem soluµie ³i o as m.
Altfel, r spunsul e -1.
71 {
72 for(int i = 1; i <= n; i++)
73 printf("%d ", sol[i]);
74 printf("\n");
75 }
76 }
77
78 return 0;
79 }
64 }
65 else
66 fout << "-1\n";
67 }
68
69 return 0;
70 }
20.5 numinum
Problema 5 - numinum 100 de puncte
Se consider urm toarea structur de date:
Cerinµe
Cunoscând num r torul, respectiv numitorul a dou fracµii ireductibile diferite din struc-
tur , determinaµi num rul minim de segmente de dreapt cu care putem conecta în structura
dat , cele dou fracµii.
Date de intrare
Pe prima linie a ³ierului de intrare numinum.in se g se³te un num r natural N .
Pe ecare dintre urm toarele N linii se g sesc câte 4 numere naturale xi , yi , ai , bi , 1 & i & N ,
desp rµite prin câte un spaµiu unde xi , yi reprezint num r torul, respectiv numitorul primei
fracµii de pe linia i 1, iar ai , bi reprezint num r torul, respectiv numitorul celei de-a doua
fracµii de pe linia i 1.
Date de ie³ire
Fi³ierul de ie³ire numinum.out va conµine N linii. Pe linia i se va scrie num rul minim de
segmente de dreapt necesare pentru a conecta, pe structura dat , fracµia xyi cu fracµia ab i .
i i
Restricµii ³i preciz ri
a 1 & N & 10 000
a 1 & xi , yi , ai , bi & 1 000 000 000, 1 & i & N
Exemple:
numinum.in numinum.out Explicaµii
1 6 N=1
4325 x1 4, y1 3; a1 2, b1 5.
Pentru a conecta fracµia 34 cu fracµia 25 avem nevoie de minim 6
segmente, dup cum urmeaz :
4/3 1/3 1/2 1/1 2/1 2/3 2/5
Timp maxim de executare/test: 0.2 secunde
Memorie: total 128 MB din care pentru stiv 32 MB
Dimensiune maxim a sursei: 10 KB
CAPITOLUL 20. ONI 2018 329
Ce putem deduce în schimb este faptul c dac am determina prima pereche din cele comune
celor 2 perechi, aceasta pereche ar o pereche care se poate determina în mod direct din punctul
de întâlnire.
Denim c dintr-o pereche (a,b) putem ajunge în mod direct în alt pereche (c,d) dac putem
aplica algoritmul de sc deri repetate doar pentru una din variabile (ori a = c ³i modic m doar b,
ori b = d ³i modicam doar a).
Astfel, pornind de la 2 perechi (a,b) ³i (c,d), am redus problema la alte 2 perechi (a2, b2) ³i
(c2, d2), perechi care se pot întâlni în mod direct într-un punct comun. Din acest punct, putem
determina în O 1 distanµa dintre cele 2 perechi aplicând formule simple în funcµie de cazuri.
Exemplu de caz:
A2 < B2, C2 > D2 - din acest caz deducem c prin sc deri repetate A2 r mâne pe loc în timp
ce B2 scade cu c te A2, respectiv D2 r mâne pe loc ³i C2 scade cu câte D2.
Din moment ce ³tim c aceste perechi se vor întâlni într-un punct comun avem relaµiile:
a B2 - k1 * A2 = D2
a C2 - k2 * D2 = A2
Din aceste 2 relaµii putem determina k1 (distanµa primei perechi pân în punctul comun)
respectiv k2 (distanµa celei de a doua perechi pân în punctul comun. Distanµa între cele 2
perechi este desigur k1 + k2.
Restul cazurilor r mâne tema de gandire!
Soluµia 4: prof. Marcel Dr gan - Colegiul Naµional Samuel Von Brukenthal, Sibiu
Pentru complexitate liniar folosim sc deri repetate asupra ambelor fracµii parcurgând astfel
structura înapoi spre vârf. La ecare pas transform m fracµia în componenta c reia intr valoarea
numeric mai mare (la num rator sau numitor) ³i num r m pa³ii realizaµi.
Ne oprim atunci când cele dou fracµii devin identice.
Pentru complexitate logaritmic folosim în loc de sc deri repetate restul împ rµirii (la fel
ca în Algoritmul lui Euclid). La aceast modalitate trebuie s avem grij la situaµia în care
transformarea fracµiei trece dincolo de prima fracµie comun celor dou ³iruri de transform ri
neobµinând astfel num rul minim de segmente. Pentru aceasta la ecare pas veric m dac
fracµiile nu au ajuns cumva pe aceea³i ramur :
p1==p2 ³i (q1-q2)%p1==0 sau q1==q2 ³i (p1-p2)%q1==0.
Dac au ajuns calcul m num rul de segmente dintre cele dou fracµii:
(p1-p2)/q1 sau (q1-q2)/p1
³i ajust m num rul total de segmente.
22
23 for(k=1;k<=T;k++)
24 {
25 fin >> a1 >> b1 >> a2 >> b2;
26 assert(a1>=1 && a1<=1000000000);
27 assert(b1>=1 && b1<=1000000000);
28 assert(a2>=1 && a2<=1000000000);
29 assert(b2>=1 && b2<=1000000000);
30
31 // prima fractie.......................................................
32 // determin fractia continua atasata primei fractii
33 d = a1;i = b1; r = d%i; k1 = 0;
34 if (r==0) w1[++k1] = d/i;
35 while (r)
36 {
37 r = d%i;
38 c = d/i;
39 w1[++k1] = c;
40 d = i;
41 i = r;
42 }
43
44 // daca lungimea secventei este un numar par mai adaug un termen de 1
45 if (k1%2==0)
46 {w1[++k1]=1;w1[k1-1]--;}
47
48 //calculez suma elementelor vectorului fractiei continue
49 ok1=0;
50 for(i=1;i<=k1;i++)
51 ok1+=w1[i];
52
53
54 // fractia a doua..........................................
55 // determin fractia continua atasata cele de-a doua fractii
56 d = a2;i = b2; r = d%i; k2 = 0;
57 if (r==0) w2[++k2] = d/i;
58 while (r)
59 {
60 r = d%i;
61 c = d/i;
62 w2[++k2] = c;
63 d = i;
64 i = r;
65 }
66
67 // daca lungimea secventei este un numar par mai adaug un termen de 1
68 if (k2%2==0)
69 {
70 w2[++k2]=1;
71 w2[k2-1]--;
72 }
73
74 //calculez suma elementelor vectorului fractiei continue
75 ok2=0;
76 for(i=1;i<=k2;i++)
77 ok2+=w2[i];
78
79 // determin secventa comuna celor doi vectori ai fractiilor continue
80 i=k1;j=k2;s=0;
81 while (i>=1 and j>=1)
82 {
83 if (w1[i]==w2[j])
84 {
85 s=s+2*w1[i];
86 i--;
87 j--;
88 }
89 else
90 {
91 if (w1[i]<w2[j])
92 s=s+2*w1[i];
93 else
94 s=s+2*w2[j];
95
96 break;
97 }
CAPITOLUL 20. ONI 2018 332
98 }
99
100 // afisez rezultatul
101 fout << ok1 + ok2 - s << "\n";
102 }
103
104 fin.close();
105 fout.close();
106
107 return 0;
108 }
62 {
63 return (value < 0 ? -value : value);
64 }
65
66 int main ()
67 {
68
69 freopen("numinum.in","r",stdin);
70 freopen("numinum.out","w",stdout);
71
72 scanf("%d",&T);
73
74 for(int k=1;k<=T;k++)
75 {
76
77 scanf("%d%d%d%d",&a,&b,&c,&d);
78
79 getList(1,a,b);
80 getList(2,c,d);
81
82 int lca=0, lim1=mylist[1].size(), lim2=mylist[2].size();
83 while(lca < lim1 && lca < lim2 &&
84 mylist[1][lca] == mylist[2][lca])
85 lca++;
86
87
88 int ans = 0;
89 for(int i = lim1 - 1; i > lca; i--)
90 ans += mylist[1][i].dist;
91
92 for(int i = lim2 - 1; i > lca; i--)
93 ans += mylist[2][i].dist;
94
95 if(lca == lim1)
96 {
97 int A = mylist[2][lca].x;
98 int B = mylist[2][lca].y;
99 int C;
100 if(A < B)
101 {
102 C = mylist[2][lca - 1].x;
103 ans += (B - C) / A;
104 }
105 else
106 {
107 C = mylist[2][lca - 1].y;
108 ans += (A - C) / B;
109 }
110
111 printf("%d\n",ans);
112 clearAll();
113 continue;
114 }
115
116 if(lca == lim2)
117 {
118 int A = mylist[1][lca].x;
119 int B = mylist[1][lca].y;
120 int C;
121
122 if(A < B)
123 {
124 C = mylist[1][lca - 1].x;
125 ans += (B - C) / A;
126 }
127 else
128 {
129 C = mylist[1][lca - 1].y;
130 ans += (A - C) / B;
131 }
132
133 printf("%d\n", ans);
134 clearAll();
135 continue;
136 }
137
CAPITOLUL 20. ONI 2018 334
Cerinµe
S se calculeze aria maxim a unei submatrice care respect specicaµiile din enunµ, pentru
ecare din cele Q sarcini date de c tre bunic.
Date de intrare
Fi³ierul rosiimici.in conµine pe prima linie trei numere naturale N , M ³i Q separate printr-un
spaµiu, având semnicaµia din enunµ.
Pe ecare dintre urm toarele N linii se a câte M numere naturale desp rµite prin câte un
spaµiu, reprezentând valorile matricei.
Pe urm toarele Q linii se a câte un num r natural x, reprezentând dimensiunea unei ro³ii.
Date de ie³ire
Fi³ierul rosiimici.out va conµine pe primele Q linii câte un num r natural, reprezentând aria
maxim cerut pentru ecare sarcin , în ordinea în care acestea apar în ³ierul de intrare.
Restricµii ³i preciz ri
CAPITOLUL 20. ONI 2018 335
Exemple:
Rezolvare 30 de puncte:
Pentru 30 de puncte putem precalcula r spunsul pentru ecare valoare.
Astfel, pentru o valoare x calcul m inaltime[i] = num rul de elemente mai mici sau egale cu
x de pe coloane i. Având vectorul de în lµimi calculat putem folosi o abordare de tip greedy.
În primul rând sortam coloanele dup în lµime. Apoi, pentru o coloan i, aria maxim a unui
dreptunghi este inaltime[i] * num rul de coloane care au în lµimea mai mare sau egal cu în lµimea
coloanei, soluµia ind coloana care maximizeaz expresia de mai sus.
O abordare similar este calcularea vectorului inaltime pentru ecare query în parte.
2 2
Complexit µi : O n m Q sau O Q n m
Rezolvare 50 de puncte:
Pentru aproximativ 50 de puncte ne vom folosi de faptul c ecare coloan este sortat .
Astfel, vom folosi algoritmul descris în problema bsrec pentru calcularea în m*log(n) pa³i a
vectorui inaltime.
CAPITOLUL 20. ONI 2018 336
O alt aborare este parcurgerea matricei în ordinea sortat a elementelor ³i menµinerea vec-
torului inaltime sortat la ecare pas, deoarece ad ugarea elementului duce la modicarea unei
singure poziµii în vector, ³i anume inaltimej .
2 2
Complexit µi : O n logn m Q sau O Q mlogn sau O n m Q
ONI 2017
21.1 arhipelag
Problema 1 - arhipelag 100 de puncte
În regiunea Ionia a lumii grece³ti antice, regiune ce corespunde teritoriului actual al M rii
Egee, exist mai multe insule. Harta m rii este reprezentat de o matrice de dimenisuni N M ,
având valori de 1 ³i 0, iar ecare element din matrice reprezint o zon de dimensiune 1 1 din
mare. Liniile matricei sunt numerotate de la 1 la N , de sus în jos, iar coloanele de la 1 la M , de
la stânga la dreapta. Astfel, colµul din stânga sus al matricei este asociat zonei (1, 1), iar colµul
din dreapta jos corespunde zonei (N , M ).
Un element care conµine valoarea 0 reprezint faptul c în acea zon se a ap . O insul este
determinat de un dreptunghi format în totalitate din valori de 1. Se garanteaz faptul c toate
zonele care conµin valoarea 1 formeaz dreptunghiuri valide ³i c oricare dou insule sunt separate
de ap . De exemplu, Figura 1 de mai jos reprezint o hart valid , în timp ce Figura 2 ³i Figura
3 NU reprezint o hart valid .
Cerinµe
Ionienii, ind oameni practici, doresc construirea unui far-bibliotec (a³ezat pe o platform 1
1), într-o zon acoperit de ap . Poziµia platformei va aleas într-o celul C astfel încât suma
distanµelor dintre toate insulele ³i C s e minim .
Distanµa dintre o celul C ³i o insul este denit ca ind minimul dintre distanµele Manhattan
dintre C ³i ecare celul care aparµine insulei (distanµa poate trece atât prin alte insule, cât ³i
prin zone acoperite de ap ).
Distanµa Manhattan dintre dou celule aate pe linia x1 ³i coloana y1, respectiv pe linia x2 ³i
coloana y2, este denit ca |x1 - x2| + |y1 - y2|, unde |x| reprezint valoarea absolut a lui x.
Date de intrare
Fi³ierul de intrare arhipelag.in conµine, pe prima linie, valorile N ³i M , având semnicaµia din
enunµ. Urm toarele N linii conµin câte M valori binare, separate de câte un spaµiu, reprezentând
harta m rii.
Date de ie³ire
339
CAPITOLUL 21. ONI 2017 340
Restricµii ³i preciz ri
a Pentru teste în valoare de 15 puncte, 1 & N, M & 50
a Pentru alte teste în valoare de 20 de puncte, 1 & N, M & 300, iar num rul de insule din
arhipelag nu dep ³e³te 300
a Pentru alte teste în valoare de 20 de puncte, 1 & N, M & 300
a Pentru restul de teste, 1 & N, M & 1000
a Se garanteaz c exist cel puµin o zon acoperit de ap
Exemple:
arhipelag.in arhipelag.out Explicaµii
7 7 23
Notând cu D(x1, y1, x2, y2) insula determinat de dreptunghiul
0 1 0 1 0 1 1având colµul stânga sus în (x1, y1) ³i colµul dreapta jos în (x2,
0 1 0 1 0 1 1y2), arhipelagul conµine urm toarele insule: D1(1, 2, 2, 2), D2(1,
0 0 0 1 0 0 04, 7, 4), D3(1, 6, 2, 7), D4(6, 1, 7, 2) ³i D5(6, 6, 7, 7). Notând
0 0 0 1 0 0 0cu dist(D) distanµa dintre celula (2, 3) ³i insula D, distanµele
0 0 0 1 0 0 0sunt urm toarele:
1 1 0 1 0 1 1dist(D1) = min |2 - 1| + |3 - 2|, |2 - 2| + |3 - 2| = 1, dist(D2)
1 1 0 1 0 1 1= 1, dist(D3) = 3, dist(D4) = 5 ³i dist(D5) = 7.
4 4 12 Pentru ecare dintre celulele (1, 2), (2, 2), (3, 2), (4, 3) si (4, 4),
0
11 0 distanµa dintre celul ³i singura insul existent în acest exemplu
0
11 0 este aceea³i. Se va alege cea care are linia minim , iar în caz de
0
11 0 egalitate se va alege cea care are coloana minim . Astfel, celula
0
00 0 (1, 2) reprezint soluµia.
Timp maxim de executare/test: 0.3 secunde
Memorie: total 32 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 15 KB
În descrierea soluµiei, C x, y reprezint o celul aat pe linia x ³i coloana y , iar D x1, y1, x2, y2
reprezint o insul care are colµul stânga sus în x1, y1 ³i colµul dreapta jos în x2, y2.
Soluµia 1 (15 puncte)
Se itereaz toate celulele care conµin ap ³i pentru ecare dintre acestea se calculeaz suma
distanµelor c tre toate insulele. Distanµa dintre o celul C si o insul se calculeaz iterând toate
celulele care aparµin insulei ³i p strând distanµa Manhattan minim dintre o astfel de celul ³i
celula C .
2 2
Complexitate: O N M .
Soluµia 2 (35 de puncte)
Se procedeaz asemanator ca în soluµia 1, observând faptul c distanµa dintre o celul C x, y
³i o insul D x1, y1, x2, y2 se poate calcula în O 1 astfel:
Dist C, D dx dy , unde:
a dx =
` x1 - x, dac x < x1
` x - x2, dac x > x2
` 0, altfel
a dy =
` y1 - y, dac y < y1
` y - y2, dac y > y2
` 0, altfel
CAPITOLUL 21. ONI 2017 341
Complexitate: O N M N R_IN SU LE
Soluµia 3 (55 de puncte)
Se observ faptul c pentru o celul C x, y , avem dou costuri asociate: costul implicat de
alegerea liniei x ³i costul implicat de alegerea coloanei y ; aceste dou costuri sunt independente (nu
depind unul de cel lalt). Astfel, se precalculeaz 2 vectori total_dxx (1 & x & N ) ³i total_dy y
(1 & y & M ), reprezentând costul asociat cu alegerea liniei x, respectiv a coloanei y , iar apoi se
itereaz toate celulele care conµin ap ³i se alege cea care are total_dx total_dy minim.
Valoarea total_dxx se calculeaz astfel: se itereaza toate insulele, iar pentru ecare insul
D x1, y1, x2, y2, se adaug la total_dxx valoarea dx, denit la fel ca in solutia 2. Analog, se
calculeaz valorile total_dy y .
Complexitate: O N N R_IN SU LE M N R_IN SU LE
Solutia 4 (100 de puncte)
Se procedeaz asem n tor ca în soluµia 3, cu excepµia modalit µii de calculare a vectorilor
total_dxx ³i total_dy y .
Cum se calculeaz total_dxx (total_dy y se calculeaz în mod similar):
a se calculeaz intervalele închise x1i, x2i, liniile pe care se intinde insula i
a total_dx1 se calculeaz ca în soluµia 3, în O N R_IN SU LE
a se itereaz x de la 2 la N , la ecare pas µinând minte 2 variabile:
28 }
29 }
30
31 int main() {
32 ifstream cin("arhipelag.in");
33 ofstream cout("arhipelag.out");
34
35 cin >> N >> M;
36 for(int i = 1; i <= N; ++i)
37 for(int j = 1; j <= M; ++j)
38 cin >> A[i][j];
39
40 for(int i = 1; i <= N; ++i)
41 {
42 for(int j = 1; j <= M; ++j)
43 {
44 if(A[i][j] == 1)
45 {
46 int xl = i;
47 int xr = i;
48
49 while(A[xr + 1][j])
50 ++xr;
51
52 int yl = j;
53 int yr = j;
54 while(A[i][yr + 1])
55 ++yr;
56
57 for(int k = xl; k <= xr; ++k)
58 for(int h = yl; h <= yr; ++h)
59 A[k][h] = -1;
60
61 ++startX[xl];
62 ++endX[xr];
63
64 ++startY[yl];
65 ++endY[yr];
66 }
67 }
68 }
69
70 computeCostForCoordinate(N, cx, startX, endX);
71 computeCostForCoordinate(M, cy, startY, endY);
72
73 int bestTotalDistance = 0x3f3f3f3f;
74 for(int i = 1; i <= N; ++i)
75 {
76 for(int j = 1; j <= M; ++j)
77 {
78 if(!A[i][j] && cx[i] + cy[j] < bestTotalDistance)
79 {
80 bestTotalDistance = cx[i] + cy[j];
81 xs = i;
82 ys = j;
83 }
84 }
85 }
86
87 cout << xs << " " << ys << "\n";
88 // printf("Best total disance = %d\n", bestTotalDistance);
89
90 return 0;
91 }
9
10 int el[kMaxN][kMaxN];
11
12 struct Rectangle
13 {
14 int x, y, lx, ly;
15 Rectangle() : x(0), y(0), lx(0), ly(0) { }
16 };
17
18 vector<Rectangle> rectangles;
19
20 void AddRectangle(int x, int y)
21 {
22 Rectangle r;
23 r.x = x;
24 r.y = y;
25
26 while (el[x][y + r.ly] == 1)
27 r.ly += 1;
28
29 while (el[x + r.lx][y] == 1)
30 r.lx += 1;
31
32 rectangles.push_back(r);
33 }
34
35 int lazy_x[kMaxN];
36 int lazy_y[kMaxN];
37
38 int X[kMaxN];
39 int Y[kMaxN];
40
41 int main()
42 {
43 ifstream cin("arhipelag.in");
44 ofstream cout("arhipelag.out");
45
46 int n, m;
47 cin >> n >> m;
48 for (int i = 1; i <= n; i += 1)
49 for (int j = 1; j <= m; j += 1)
50 cin >> el[i][j];
51
52 for (int i = 1; i <= n; i += 1)
53 for (int j = 1; j <= m; j += 1)
54 if (el[i][j] and el[i - 1][j] == 0 and el[i][j - 1] == 0)
55 AddRectangle(i, j);
56
57 int sum_x = 0, sum_y = 0;
58 int lazy_x_sum = 0;
59 int lazy_y_sum = 0;
60
61 for (auto itr : rectangles)
62 {
63 lazy_x_sum -= 1;
64 lazy_x[itr.x + 1] += 1;
65 sum_x += itr.x;
66
67 lazy_x[itr.x + itr.lx] += 1;
68
69 lazy_y_sum -= 1;
70 lazy_y[itr.y + 1] += 1;
71 sum_y += itr.y;
72 lazy_y[itr.y + itr.ly] += 1;
73 }
74
75 for (int i = 1; i <= n; i += 1)
76 {
77 lazy_x_sum += lazy_x[i];
78 sum_x += lazy_x_sum;
79 X[i] = sum_x;
80 }
81
82 for (int i = 1; i <= m; i += 1)
83 {
84 lazy_y_sum += lazy_y[i];
CAPITOLUL 21. ONI 2017 344
85 sum_y += lazy_y_sum;
86 Y[i] = sum_y;
87 }
88
89 int mn = 1e9;
90 int rx = -1, ry = -1;
91 for (int i = 1; i <= n; i += 1)
92 {
93 for (int j = 1; j <= m; j += 1)
94 {
95 if (el[i][j] == 1)
96 continue;
97
98 if (X[i] + Y[j] < mn)
99 {
100 mn = X[i] + Y[j];
101 rx = i;
102 ry = j;
103 }
104 }
105 }
106
107 cout << rx << ’ ’ << ry << ’\n’;
108 return 0;
109 }
21.2 mirror
Problema 2 - mirror 100 de puncte
Numim oglinda num rului natural nenul a, num rul b, obµinut prin modicarea ec rei cifre din
reprezentarea sa binar , de exemplu pentru a 22 10 10110 2 se obµine 01001 2 9 10 b.
Cerinµe
Cunoscându-se numerele naturale N , K ³i cele N numere natural nenule, scrieµi un program
care:
1) Transform în baza doi termenii ³irului dat obµinându-se un nou ³ir format din alipirea
cifrelor binare. Din acest ³ir se vor determina ³i a³a, separate prin câte un spaµiu, toate repre-
zent rile în baza 10 corespunz toare secvenµelor al turate de exact K cifre binare, parcurse de la
stânga la drepta. Dac ultima secvenµ nu are exact K cifre binare, atunci aceasta nu se va mai
lua în considerare.
2) S aplice K transform ri asupra ³irului iniµial, înlocuind la ecare pas orice termen cu
oglinda sa. Asupra termenilor care devin zero nu se vor mai efectua alte operaµii. Dup efec-
tuarea celor K transform ri, s se determine cea mai lung secvenµ de numere care au cifra 1
pe aceea³i poziµie în reprezentarea lor în baza doi. Dac sunt mai multe astfel de secvenµe având
lungimea maxim , se va a³a cea mai din stânga.
Date de intrare
Fi³ierul de intrare mirror.in conµine pe primul rând num rul C , reprezentând cerinµa. Pe al
doilea rând se a scrise numerele naturale N ³i K . Pe rândul al treilea sunt cele N numere ale
³irului separate prin câte un spaµiu.
Date de ie³ire
Dac C 1, atunci în ³ierul de ie³ire mirror.out se vor scrie separate prin câte un spaµiu,
toate numerele cerute în enunµ.
Dac C 2, atunci în ³ierul de ie³ire mirror.out se va scrie pe prima linie lungimea maxim
a secvenµei determinate, iar pe urm toarea linie separate prin spaµiu, poziµia primului ³i ultimului
termen din secvenµ (prima poziµie este 1).
Restricµii ³i preciz ri
a 1 & N &100 000
a 0 & K & 30
a Elementele ³irului sunt mai mici decât 2 000 000 001;
a Pentru 30% din teste cerinµa va C 1.
CAPITOLUL 21. ONI 2017 345
Exemple:
mirror.in mirror.out Explicaµii
1 330111 7 10 111 2 ; 8 10 1000 2 ; 2 10 10 2 ; 11 10 1011 2 ;
42 Sirul format este: 1111000101011 ³i grupate câte 2 avem nume-
7 8 2 11 rele:
11 2 3 10 ; 11 2 3 10 ; 00 2 0 10 ; 01 2 1 10 ; 01 2
1 10 ; 01 2 1 10 ;
2 3 Dup o transformare numerele în baza 2 sunt:
51 13
37 72 101 50
116
19 nr=v[i];
20 if(masca==0)
21 masca=1;
22
23 while(masca<nr)
24 masca<<=1;
25
26 if(masca>nr)masca>>=1;
27
28 while(masca)
29 {
30 if(masca&nr)
31 x=x+y;
32 y/=2;
33 if(y==0)
34 {
35 fout<<x<<" ";
36 y=1<<k-1;
37 x=0;
38 }
39 masca>>=1;
40 }
41 }
42 fout<<’\n’;
43 }
44
45 int lungime(int &st, int &dr)
46 {
47 int ok,l,lmax=0,masca=1,ddr,i;
48 do
49 {
50 ok=0;//pp ca nu mai sunt cifre binare de 1
51 l=0;
52 for(i=st; i<=dr; i++)
53 {
54 if(masca<v[i])
55 ok=1;
56 if(masca&v[i])
57 l++;
58 else
59 {
60 if(l>lmax)
61 {
62 lmax=l;
63 ddr=i-1;
64 }
65 l=0;
66 }
67 }
68
69 if(l>lmax)
70 {
71 lmax=l;
72 ddr=dr;
73 }
74 masca<<=1;
75 }
76
77 while(ok==1);
78 dr=ddr;
79 st=ddr-lmax+1;
80 return lmax;
81 }
82
83 void secventa()
84 {
85 int st=0,dr,i,lung,lmax=0,sst,ddr;
86 i=1;
87
88 while(v[i]==0&&i<=n)
89 i++;
90
91 if(i<=n)
92 for( ; i<=n; i++)
93 if(v[i]!=0)
94 if(st==0)
CAPITOLUL 21. ONI 2017 347
95 st=dr=i;
96 else
97 dr++;
98 else
99 {
100 if(st)
101 {
102 lung=lungime(st,dr);
103 if(lung>lmax)
104 {
105 lmax=lung;
106 sst=st;
107 ddr=dr;
108 }
109 st=0;
110 }
111 }
112
113 if(st)
114 {
115 lung=lungime(st,dr);
116 if(lung>lmax)
117 {
118 lmax=lung;
119 sst=st;
120 ddr=dr;
121 }
122 }
123
124 fout<<lmax<<’\n’<<sst<<" "<<ddr<<’\n’;
125 }
126
127 int main()
128 {
129 int x=1,i,j,masca;
130 fscanf(fin,"%d%d%d",&ct,&n,&k);
131 for(i=1; i<=n; i++)
132 fscanf(fin,"%d",&v[i]);
133
134 if(ct==1)
135 {
136 rezolva1();
137 return 0;
138 }
139
140 // transformare cautand cifrele care se modifica si tinand cont
141 // de paritatea lui k
142 int u[33],nr,p,l,r;
143 if(k)
144 for(r=1; r<=n; r++)
145 {
146 masca=1;
147 masca<<=30;
148 while((masca&v[r])==0)
149 masca>>=1;
150 nr=0;
151
152 //pun cifrele binare in vector
153 while(masca)
154 {
155 if(masca&v[r])
156 u[++nr]=1;
157 else
158 u[++nr]=0;
159
160 masca>>=1;
161 }
162
163 int cont=0;//numara de cate ori se schimba cifrele binare
164 int cifbin=1;
165 for(j=1; j<=nr; j++)
166 if(u[j]!=cifbin)
167 {
168 cont++;
169 if(cifbin==1)
170 cifbin=0;
CAPITOLUL 21. ONI 2017 348
171 else
172 cifbin=1;
173 }
174
175 if(cont<k)
176 v[r]=0;
177 else
178 {
179 // modific toate cifrele odata daca k impar,
180 // altfel cifrele raman la fel
181 if(k%2==1)
182 for(j=1; j<=nr; j++)
183 if(u[j]==0)
184 u[j]=1;
185 else
186 u[j]=0;
187
188 //elimin cifrele care se pierd la transformare
189 i=1;
190 cont=0;
191 while(cont<k&&i<=nr)
192 {
193 i++;
194 if(u[i]!=u[i-1])
195 cont++;
196 }
197
198 if(i>nr)
199 v[r]=0;
200 else
201 {
202 p=1;
203 x=0;
204 for(j=nr; j>=i; j--)
205 {
206 x=x+p*u[j];
207 p<<=1;
208 }
209
210 v[r]=x;
211 }
212 }
213 }
214
215 secventa();
216 return 0;
217 }
26 p=p2;
27 nc=0;
28 while(nr<n)
29 {
30 s=0; i=0;
31 while(s<k && nr<n)
32 {
33 in>>x; nr++; j=0;
34 while(x!=0)
35 {
36 a[i][++j]=x%2;
37 x=x/2;
38 }
39
40 a[i][0]=j;
41 s=s+j;
42 i++;
43 }
44
45 x=r;
46 for(l=0;l<i;l++)
47 for(j=a[l][0];j>0;j--)
48 {
49 x=x+a[l][j]*p;
50 p=p/2;
51 nc++;
52 if(nc==k)
53 {
54 out<<x<<" ";
55 x=0;
56 p=p2;
57 nc=0;
58 }
59 }
60 r=x;
61 }
62 }
63 else
64 { //cer 2
65 for(i=0;i<n;i++)
66 {
67 in>>x; nc=0;
68 if(x==0)
69 nc=1;
70
71 while(x!=0)
72 {
73 x2[nc++]=x%2;
74 x=x/2;
75 }
76
77 for(j=1;j<=k;j++)
78 {
79 r=j%2;
80 nc--;
81 if(nc>=1)
82 while(x2[nc-1]==r && nc>0)
83 nc--;
84 }
85
86 if(nc>max)
87 max=nc;
88
89 for(j=0;j<nc;j++)
90 {
91 if(k%2==1)
92 A[i][j]=!x2[j];
93 else
94 A[i][j]=x2[j];
95 }
96 }
97
98 //det secv de 1 cu lung max pe col si poz inc si sf
99 lmax=0;
100 psf=1;
101 psfmin=n;
CAPITOLUL 21. ONI 2017 350
102 for(j=0;j<max;j++)
103 {
104 l=0;
105 for(i=0;i<n;i++)
106 {
107 if(A[i][j]==1)
108 l++;
109 else
110 {
111 if(l>lmax)
112 {
113 lmax=l;
114 psf=i;
115 psfmin=i;
116 }
117
118 if(l==lmax)
119 psf=i;
120
121 if(psf<psfmin)
122 psfmin=psf;
123
124 l=0;
125 }
126 }
127
128 i=i-1;
129 if(A[i][j]==1 && l>lmax)
130 {
131 lmax=l;
132 psf=i+1;
133 psfmin=psf;
134 }
135 }
136
137 out<<lmax<<’\n’; out<<psfmin+1-lmax<<’ ’<<psfmin<<’\n’;
138 }
139
140 in.close();
141 out.close();
142 return 0;
143 }
67 x=0;
68 }
69 masca>>=1;
70 }
71 }
72 fout<<’\n’;
73 }
74
75 int lungime(int &st, int &dr)
76 {
77 int ok,l,lmax=0,masca=1,ddr,i;
78 do
79 {
80 ok=0;//pp ca nu mai sunt cifre binare de 1
81 l=0;
82 for(i=st; i<=dr; i++)
83 {
84 if(masca<=v[i])
85 ok=1;
86 if(masca&v[i])
87 l++;
88 else
89 {
90 if(l>lmax)
91 {
92 lmax=l;
93 ddr=i-1;
94 }
95 l=0;
96 }
97 }
98 if(l>lmax)
99 {
100 lmax=l;
101 ddr=dr;
102 }
103 masca<<=1;
104 } while(ok==1);
105
106 dr=ddr;
107 st=ddr-lmax+1;
108 return lmax;
109 }
110
111 void secventa()
112 {
113 int st=0,dr=0,i,lung,lmax=0,sst,ddr;
114 i=1;
115 while(v[i]==0&&i<=n)
116 i++;
117
118 if(i<=n)
119 for( ; i<=n; i++)
120 if(v[i]!=0)
121 if(st==0)
122 st=dr=i;
123 else
124 dr++;
125 else
126 {
127 if(st)
128 {
129 lung=lungime(st,dr);
130 if(lung>lmax)
131 {
132 lmax=lung;
133 sst=st;
134 ddr=dr;
135 }
136 st=0;
137 }
138 }
139
140 if(dr)
141 {
142 lung=lungime(st,dr);
CAPITOLUL 21. ONI 2017 354
143 if(lung>lmax)
144 {
145 lmax=lung;
146 sst=st;
147 ddr=dr;
148 }
149 }
150
151 fout<<lmax<<’\n’<<sst<<" "<<ddr<<’\n’;
152 }
153
154 int main()
155 {
156 int x=1,i,j,masca;
157 for(i=1; i<=31; i++)
158 {
159 x=x<<1;
160 w[i]=x-1;
161 }
162 fscanf(fin,"%d%d%d",&ct,&n,&k);
163 for(i=1; i<=n; i++)
164 fscanf(fin,"%d",&v[i]);
165
166 if(ct==1)
167 {
168 rezolva1();
169 return 0;
170 }
171
172 //transformare cu cautare binara- timp mai mare?
173 for(i=1; i<=n; i++)
174 {
175 for(j=1; j<=k&&v[i]; j++)
176 v[i]=transforma(v[i]);
177 // fout<<v[i]<<" ";
178 }
179
180 secventa();
181 return 0;
182 }
33 int i,q,p,j,jmax,l,pmax;
34
35 d[0]=1;
36 for(i=1;i<=32;i++)
37 {
38 d[i]=d[i-1]*2;
39 }
40
41 fin=fopen("mirror.in","rt");
42 fscanf(fin,"%d %d %d",&C,&N,&K);
43
44 if(C==1)
45 {
46 fscanf(fin,"%d",&z);
47 x=z;
48 p=posd(x);
49 afisareK(x,p);
50 for(i=2;i<=N;i++)
51 {
52 fscanf(fin,"%d",&z);
53 y=z;
54 q=posd(y);
55 x=x*d[q]+y;
56 p+=q;
57 afisareK(x,p);
58 }
59 }
60 else
61 {
62 for(j=0;j<33;j++)
63 {
64 posL[j]=0;
65 maxL[j]=0;
66 }
67 pmax=0;
68 for(i=1;i<=N;i++)
69 {
70 fscanf(fin,"%d",&z);
71 x=z;
72 for(j=0;j<=31;j++)
73 {
74 v[j]=x%2;
75 x=x/2;
76 if(v[j]==1){
77 p=j;
78 }
79 }
80 if(p>pmax)pmax=p;
81 for(l=1;l<=K && p>=0;l++)
82 {
83 while(p>=0 && v[p]==l%2)
84 {
85 v[p]=0;
86 p--;
87 }
88 }
89 for(j=0;j<=pmax;j++)
90 {
91 q=v[j];
92 if(K%2) q=1-q;
93 if(j>p) q=0;
94
95 if(q==1)
96 {
97 L[j]++;
98 if(L[j]==1)pos[j]=i;
99 if(L[j]>maxL[j])
100 {
101 maxL[j]=L[j];
102 posL[j]=pos[j];
103 }
104 }
105 else
106 {
107 L[j]=0;
108 }
CAPITOLUL 21. ONI 2017 356
109 }
110 }
111
112 jmax=0;
113 for(j=0;j<=pmax;j++)
114 {
115 if((maxL[j]>maxL[jmax])||
116 (maxL[j]==maxL[jmax] && posL[j]<posL[jmax]))
117 {
118 jmax=j;
119 }
120 }
121
122 fout<<maxL[jmax]<<"\n";
123 fout<<posL[jmax]<<" "<<posL[jmax]+maxL[jmax]-1<<"\n";
124 }
125
126 fclose(fin);
127 fout.close();
128 return 0;
129 }
52 if (p == -1)
53 p = 0;
54
55 vector<bool> bits;
56 for (int i = 0; i <= p; i += 1)
57 bits.push_back(!!((1 << i) & a));
58
59 for (int i = 0; i < k and bits.size(); i += 1)
60 {
61 int last = bits.back();
62 while (bits.size() and bits.back() == last)
63 bits.pop_back();
64 }
65
66 k = k & 1;
67
68 int x = 0;
69 while (bits.size())
70 {
71 x *= 2;
72 x += k ^ bits.back();
73 bits.pop_back();
74 }
75
76 a = x;
77 }
78
79 void Solve2()
80 {
81 int mx = -1;
82 int where = 0;
83
84 vector<int> bits(31, 0);
85 int right = 1;
86 for (auto itr : el)
87 {
88 Mirror(itr, k);
89 for (int p = 0; p <= 30; p++)
90 {
91 if ((1 << p) & itr)
92 {
93 bits[p]++;
94 if (bits[p] > mx)
95 {
96 mx = bits[p];
97 where = right;
98 }
99 }
100 else
101 bits[p] = 0;
102 }
103
104 right++;
105 }
106
107 ofstream cout("mirror.out");
108
109 cout << mx << ’\n’;
110 cout << where - mx + 1 << ’ ’ << where << ’\n’;
111
112 return;
113 }
114
115 int main()
116 {
117 ifstream cin("mirror.in");
118 cin >> c >> n >> k;
119 el.resize(n);
120
121 for (int i = 0; i < n; i += 1)
122 cin >> el[i];
123
124 if (c == 1)
125 Solve1();
126 else
127 Solve2();
CAPITOLUL 21. ONI 2017 358
128
129 return 0;
130 }
21.3 okcpp
Problema 3 - okcpp 100 de puncte
Despre num rul natural N spunem c are proprietatea okcpp dac oricum alegem K cifre ale
sale vom g si printre ele cel puµin P cifre distincte (oricare k cel puµin p).
Cerinµe
(1) Fiind date numerele naturale K , P , A ³i B s se calculeze ³i s se a³eze num rul de
numere okcpp din intervalul A, B .
(2) Fiind date numerele naturale K , P ³i N s se calculeze ³i s se a³eze cel mai mic num r
okcpp care este mai mare sau egal cu N .
Date de intrare
Fi³ierul de intrare okcpp.in conµine pe primul rând num rul C .
Dac C 1, atunci pe al doilea rând se vor aa scrise, separate prin spaµiu, numerele naturale
K , P , A ³i B .
Dac C 2, atunci pe al doilea rând se vor aa scrise, separate prin spaµiu, numerele naturale
K , P ³i N .
Date de ie³ire
Dac C 1, atunci în ³ierul de ie³ire okcpp.out se va scrie num rul de numere okcpp din
intervalul A; B .
Dac C 2, atunci în ³ierul de ie³ire okcpp.out se va scrie cel mai mic num r natural okcpp
care este mai mare sau egal cu N .
Restricµii ³i preciz ri
a 1 & P & 10
a P & K & num rul de cifre al lui N & 18
a Pentru 20% din teste cerinµa va C 1
Pentru cerinµa C 1 vom avea 0 & A $ B $ 10 ³i B A & 10000
18
a
a Pentru cerinµa C 2 se garanteaz c exist întotdeauna soluµie
Exemple:
okcpp.in okcpp.out Explicaµii
1 3 Avem K 4 ³i P 2. în intervalul [99997;100001] sunt trei
5 2 99997 100001 numere okcpp: 99997, 99998 ³i 100001.
2 100023 Avem K 5, P 3 ³i N 99997. Se observ u³or c
5 3 99997 numerele 99997, 99998 , ..., 100022 nu corespund. Primul
num r care corespunde cerinµelor este 100023.
Timp maxim de executare/test: 0.1 secunde
Memorie: total 32 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 10 KB
32 s1=0;
33 for(i=1;i<=P-1;i++) s1=s1+w[i];
34 if((nw>=P-1 && s1<=K-1)||(nw<P-1 && s1+P-1-nw<=K-1))
35 {
36 s2=0;
37 for(i=P;i<=9;i++) s2=s2+w[i];
38
39 w[0]=1000;
40 s3=s1;
41 i=min(nw+1,P-1);
42 h=w[i];
43 while(i>=1 && (K-1-s3)/(P-i)+h>=w[i-1])
44 {
45 r=(K-1-s3)/(P-i);
46 if(r+h>w[i-1]) r=w[i-1]-h;
47 s3=s3+r*(P-i);
48 i--;
49 h=w[i];
50 }
51
52 r=(K-1-s3)/(P-i);
53 if(r+h>w[i-1]) r=w[i-1]-h;
54 h=h+r;
55 s3=s3+r*(P-i);
56 z=(K-1-s3)%(P-i)+s3+h*(10-(P-1));
57 if(z<nv) return 0;
58 return 1;
59 }
60 else
61 return 0;
62 }
63
64 int main()
65 {
66 int i,j,l,ok,r,i1,i2,ok1,aux,c;
67 fin>>C;
68
69 if(C==1)
70 {
71 fin>>K>>P>>A>>B;
72 c=0;
73 for(N=A;N<=B;N++)
74 {
75 X=N;
76 nv=0;
77 do
78 {
79 v[++nv]=X%10;
80 X=X/10;
81 } while(X);
82
83 for(i=1;i<=nv/2;i++)
84 {
85 aux=v[i];
86 v[i]=v[nv+1-i];
87 v[nv+1-i]=aux;
88 }
89
90 if(P==1 || verificare(v,nv)==1)
91 c++;
92 }
93
94 fout<<c;
95 }
96
97 if(C==2)
98 {
99 fin>>K>>P>>N;
100 X=N;
101 nv=0;
102 do
103 {
104 v[++nv]=X%10;
105 X=X/10;
106 } while(X);
107
CAPITOLUL 21. ONI 2017 361
108 for(i=1;i<=nv/2;i++)
109 {
110 aux=v[i];
111 v[i]=v[nv+1-i];
112 v[nv+1-i]=aux;
113 }
114
115 ok=0;
116 if(P==1 || verificare(v,nv)==1)
117 {
118 fout<<N<<"\n";
119 ok=1;
120 }
121
122 if(ok==0)
123 {
124 nx=0;
125 for(i=1;i<=nv;i++)
126 if(v[i]<9)
127 nx++;x[nx]=i;
128
129 i1=1; i2=nx;
130 while(i1<=i2)
131 {
132 i=(i1+i2)/2;
133 ///pastrez prefix de lungime i, crescand a i-a cifra
134 ok1=0;
135 aux=v[x[i]];
136 for(l=v[x[i]]+1;l<=9 && 0==ok1;l++)
137 {
138 v[x[i]]=l;
139 if(verificare(v,x[i])==1)
140 ok1=1;
141 }
142
143 v[x[i]]=aux;
144 if(ok1==1)
145 i1=i+1;
146 else
147 i2=i-1;
148 }
149
150 i=x[i2];
151 for(l=v[i]+1;l<=9 && i>=1 && 0==ok;l++)
152 {
153 v[i]=l;
154 if(verificare(v,i)==1)
155 {
156 for(r=i+1;r<=nv;r++)
157 {
158 v[r]=0;
159 while(verificare(v,r)==0)
160 v[r]++;
161 }
162
163 ok=1;
164 for(j=1;j<=nv;j++)
165 fout<<v[j];
166
167 fout<<"\n";
168 }
169 }
170 }
171
172 if(ok==0)
173 {
174 v[1]=1;
175 if(verificare(v,1)==1)
176 {
177 nv++;
178 for(r=2;r<=nv;r++)
179 {
180 v[r]=0;
181 while(verificare(v,r)==0)
182 v[r]++;
183 }
CAPITOLUL 21. ONI 2017 362
184 ok=1;
185 for(j=1;j<=nv;j++)
186 fout<<v[j];
187
188 fout<<"\n";
189 }
190 }
191 ///if(ok==0) fout<<-1<<"\n";
192 }
193
194 fout.close();
195 fin.close();
196 return 0;
197 }
59 S = string(S.length() + 1, ’0’);
60 S[0] = ’1’;
61 i = 0;
62 C[1]++;
63 if (!canFill(C, K, P, S.length() - 1)) return "-1";
64 }
65
66 for (i++; i < S.length(); i++)
67 for (char d = ’0’; d <= ’9’; d++)
68 {
69 C[d - ’0’]++;
70 if (canFill(C, K, P, S.length() - i - 1))
71 {
72 S[i] = d;
73 break;
74 }
75 C[d - ’0’]--;
76 }
77
78 return S;
79 }
80
81 int main()
82 {
83 ifstream f("okcpp.in");
84 ofstream g("okcpp.out");
85
86 int C, K, P, ns;
87 long long A, B, X;
88 string S;
89
90 f >> C ;
91 if(C == 1)
92 {
93 f >> K >> P >> A >> B;
94 ns = 0;
95 for( X = A; X <= B ; X ++)
96 {
97 S = to_string(X);
98 if(isGood(S, K, P))
99 {
100 ns ++;
101 }
102 g << ns << endl;
103 }
104 }
105 else
106 {
107 f >> K >> P >> S;
108 g << findNext(S, K, P) << endl;
109 }
110
111 return 0;
112 }
95
96 return;
97 }
98
99 string Solve(int k, int p, string n)
100 {
101 vector<int> digits(10, 0);
102 for (char itr : n)
103 digits[itr - ’0’] += 1;
104
105 if (IsOk(digits, k, p))
106 return n;
107
108 int to_match = 0;
109 while (n.size())
110 {
111 to_match += 1;
112 digits[n.back() - ’0’] -= 1;
113
114 bool ok = false;
115 int digit = 0;
116 SolveFixed(digits, n.back() - ’0’, k, p, to_match, ok, digit);
117 n.pop_back();
118
119 if (ok)
120 {
121 digits[digit] += 1;
122 n += char(’0’ + digit);
123 return AddStuffAtEnd(n, digits, ans);
124 }
125 }
126
127 digits = vector<int>(10, 0);
128 digits[1] += 1;
129
130 bool ok = false;
131 int digit = 0;
132 SolveFixed(digits, -1, k, p, to_match, ok, digit);
133
134 if (ok)
135 {
136 digits[digit] += 1;
137 n = "1";
138 n += char(’0’ + digit);
139 return AddStuffAtEnd(n, digits, ans);
140 }
141 else
142 return "-1";
143 }
144
145 bool IsOk(int64 n, int k, int p)
146 {
147 vector<int> digits(10, 0);
148 do
149 {
150 digits[n % 10]++;
151 n /= 10;
152 } while (n);
153
154 return IsOk(digits, k, p);
155 }
156
157 int Solve1(int k, int p, int64 left, int64 right)
158 {
159 int a = 0;
160 for (int64 i = left; i <= right; i += 1)
161 a += IsOk(i, k, p);
162
163 return a;
164 }
165
166 int main()
167 {
168 freopen("okcpp.in", "r", stdin);
169 freopen("okcpp.out", "w", stdout);
170
CAPITOLUL 21. ONI 2017 366
171 int c;
172 cin >> c;
173
174 if (c == 2)
175 {
176 int k, p;
177 string n;
178 cin >> k >> p >> n;
179 cout << Solve(k, p, n) << ’\n’;
180 }
181 else
182 {
183 int k, p;
184 int64 left, right;
185 cin >> k >> p >> left >> right;
186 cout << Solve1(k, p, left, right) << ’\n’;
187 }
188
189 return 0;
190 }
21.4 adlic
Problema 4 - adlic 100 de puncte
Pentru urm torul an ³colar admiterea celor N elevi în liceu se va face pe baza unor evalu ri
complexe.
Fiecare dintre viitorii elevi ai clasei a IX-a va primi, în urma testelor ³i probelor pe care le va
sus µine, un punctaj (num r natural nenul) cu care va participa la admiterea electronic .
Repartizarea ec rui elev în clase se face în ordinea înscrierii respectând criteriile:
a Primul elev se repartizeaz în clasa cu num rul de ordine 1.
a în clasa în care este repartizat un elev nu exist , pân la momentul repartiz rii sale, nici un
punctaj mai mare decât al s u.
a Num rul claselor s e cât mai mic posibil.
Cerinµe
Determinaµi:
1. Punctajul primului elev care nu ar mai putea repartizat în prima clas în condiµiile în
care toµi elevii î³i doresc s e repartizaµi în prima clas (se aplic doar la cerinµa 1).
2. Num rul claselor ce se vor forma respectând criteriile.
Date de intrare
Fi³ierul de intrare adlic.in conµine pe primul rând num rul C a c rui valoare poate 1 sau
2, apoi separat de un spaµiu num rul natural N .
Pe liniile urm toare se g sesc cele N punctaje ale elevilor în ordinea înscrierii, numere naturale
nenule desp rµite prin câte un spaµiu.
Date de ie³ire
Dac C 1, atunci în ³ierul de ie³ire adlic.out se va scrie soluµia cerinµei 1.
Dac C 2, atunci în ³ierul de ie³ire adlic.out se va scrie soluµia cerinµei 2.
Restricµii ³i preciz ri
a Punctajele elevilor vor avea cel mult ³ase cifre
a 1 & N & 1 000 000
a Pentru cerinµa 1 se garanteaz existenµa soluµiei
a Pentru 20% din punctaj cerinµa va C 1
a Pentru alte 20% din punctaj cerinµa va C 2 ³i N & 1000
a Pentru restul testelor C 2 ³i N & 1000 000
Exemple:
CAPITOLUL 21. ONI 2017 367
1. Se parcurge ³ierul adlic.in determinându-se primul termen mai mic decât predecesorul
s u - complexitate O n
2. Se formeaz vectorul v în care se reµine ultimul element al sub³irurilor cresc toate. V este
creat descresc tor. La citirea din ³ier elementul curent actualizeaz v înlocuind primul element
mai mic decât el. Dac un asemenea element nu exist se creaz o nou poziµie în v . C utarea în
2
v se face binar. Complexitate nlog n. În cazul c ut rii în n se obµine punctaj parµial.
39 }
40 }
41 else
42 for(i=1;i<=m;i++)
43 {
44 f>>w;
45 k=Bins(1,n,w);
46
47 if(k==n+1)
48 v[++n]= w;
49 else
50 v[k]=w;
51
52 g<<n;
53 }
54
55 return 0;
56 }
55 ultim[clasa] = punctaje[i];
56 else
57 {
58 ++nrClase;
59 ultim[nrClase] = punctaje[i];
60 }
61 }
62
63 g << nrClase << "\n";
64 }
65
66 f.close();
67 g.close();
68
69 return 0;
70 }
57 }
58
59 out<<k;
60 // cout<<k;
61 }
62
63 in.close();
64 out.close();
65 return 0;
66 }
21.5 bomboane
Problema 5 - bomboane 100 de puncte
Zeno are n cutii cu bomboane, iar în ecare cutie se g se³te un num r natural nenul de
bomboane. Zeno poate împ rµi bomboanele din toate cutiile colegilor în dou moduri: fr µe³te
sau diferenµiat. împ rµirea fr µeasc se realizeaz astfel:
- num rul de colegi care primesc bomboane din ecare cutie este acela³i (dac din prima cutie
primesc bomboane k colegi ³i din cutia 2 vor primi tot k colegi, ³i din cutia 3 tot k colegi etc).
- bomboanele din ecare cutie se împart în mod egal între cei k colegi, ace³tia primind un
num r nenul de bomboane;
- în nal în ecare cutie trebuie s r mân un num r identic de bomboane (posibil zero) care
îi revin lui Zeno. De exemplu dac n 3, iar în cutii se g sesc 14, 23 respectiv 17 bomboane, din
prima cutie ofer câte 4 bomboane pentru 3 colegi, din a doua cutie câte 7 bomboane pentru 3
colegi, iar din ultima cutie câte 5 bomboane pentru 3 colegi, iar în ecare cutie r mân 2 bomboane.
împ rµirea diferenµiat se realizeaz în felul urm tor:
- dintre colegii care primesc bomboane din aceea³i cutie ecare coleg prime³te un num r diferit
de bomboane (num r nenul), neexistând doi colegi care primesc num r identic de bomboane din
aceea³i cutie;
- din ecare cutie Zeno ofer bomboane unui num r cât mai mare de colegi.
- diferenµele în modul dintre num rul de bomboane primite consecutiv de doi colegi sunt
distincte dou câte dou . De exemplu dac n 3, iar în cutii se g sesc 14, 23 respectiv 17
bomboane, bomboanele din prima cutie se pot împ rµi astfel (3, 4, 6, 1), bomboanele din a doua
cutie (6, 2, 7, 1, 3, 4), iar bomboanele din a treia cutie se pot împ rµi astfel (2, 1, 3, 7, 4).
Cerinµe
Cunoscând n num rul de cutii ³i num rul de bomboane din ecare cutie s se scrie un program
care determin :
a) Num rul maxim de colegi care pot primi bomboane, dac Zeno alege împ rµirea fr µeasc .
b) O modalitate de împ rµire a bomboanelor din ecare cutie, dac se face împ rµirea diferen-
µiat .
Date de intrare
Fi³ierul de intrare bomboane.in conµine pe prima linie dou numere naturale p (num rul
cerinµei de rezolvat), ³i n (num rul de cutii), desp rµite printr-un spaµiu. Pe urm toarea linie se
g sesc n valori naturale, separate prin câte un spaµiu, reprezentând num rul de bomboane din
ecare cutie.
Date de ie³ire
Dac p 1 se va rezolva numai punctul a) din cerinµ . În acest caz ³ierul de ie³ire bom-
boane.out va conµine o valoare natural reprezentând num rul maxim de colegi care pot primi
bomboane, dac Zeno alege împ rµirea fr µeasc .
Dac p 2 se rezolv numai punctul b). Fi³ierul de ie³ire bomboane.out va conµine n linii. Pe
ecare linie i, prima valoare nri reprezint num rul maxim de colegi care pot primi bomboane din
cutia i, urmat de nri valori separate prin câte un spaµiu reprezentând o modalitate de împ rµire
a bomboanelor din cutia i, dac Zeno alege împ rµirea diferenµiat .
Restricµii ³i preciz ri
CAPITOLUL 21. ONI 2017 371
a 1 & p & 2;
Dac p 1 atunci 1 & n & 10 000 ³i 1 & num rul de bomboane din cutii & 10 .
6
a
a Dac p 2 atunci 1 & n & 200 ³i 1 & num rul de bomboane din cutii & 100 000.
a Dac exist mai multe soluµii se poate a³a oricare.
a Pentru rezolvarea ec rei cerinµe se acord 50% din punctaj.
Exemple:
bomboane.in bomboane.outExplicaµii
13 3 Se rezolv numai punctul a). Num rul maxim de colegi care pot
14 23 17 primi bomboane dac Zeno alege împ rµirea fr µeasc e 3.
2 3 14 23 17
43461 Se rezolv numai punctul b). Din prima cutie pot primi bom-
6 6 2 7 1 3 4 boane maxim 4 colegi. O modalitate de împ rµire astfel încât
521374 ecare coleg s primeasc un num r diferit de bomboane, iar
diferenµele dintre bomboanele primite de doi colegi consecutivi
s e distincte dou câte dou este (3,4,6,1). Este corect ³i
soluµia (1, 2, 7, 4).
Timp maxim de executare/test: 0.2 secunde
Memorie: total 16 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 10 KB
a) împ rµirea fr µeasc
e a[i] - numarul de bomboane din cutia i
Metoda 1 - 10% din punctajul cerinµei
Se genereaz toate valorile pentru num rul de colegi ³i se veric dac num rul de bomboane
din ecare cutie împ rµit la num rul de colegi d acela³i rest.
Complexitate O(N*max(a[i])
Metoda 2 - 30% din punctajul cerinµei
Se observ c num rul de bomoane care pot r mâne în ecare cutie este cuprins între 0 ³i
min(a[i]).
Complexitate O(N*min(a[i])
Metoda 3 - 100% din punctaj
e a[i] - numarul de bomboane din cutia i
Trebuie determinat un numar k astfel incat ecare a[i] sa dea acelasi rest la impartirea la k.
a[1] = x1 * k + r
a[2] = x2 * k + r
......
a[n] = x3 * k + r
Daca facem diferenta intre oricare doua elemente ale vectorului a[i] si a[j] obtinem:
a[i] - a[j] = xi * k + r - (xj * k + r) = (xi - xj) * k
Prin urmare diferenta intre doua elemente ale vectorului este multiplu de k.
Pentru k maxim acesta va cmmdc(a[1] - a[2], a[2] - a[3], a[3] - a[4] ... a[n-1] - a[n]).
Un algoritmul de rezolvare:
- pentru a evita valori negative se determina min = min(a[1], a[2] ... a[n])
- se scade min din elementele vectorului a[1] = a[1] - min, a[2] = a[2] - min ... a[n] = a[n] - min
- se determina k = cmmdc(a[1], a[2] ... a[n]).
b) împ rµirea diferenµiat
Fie ci numarul maxim de colegi care pot primi bomboane din cutia i
Pentru a determina ci se determina cea mai mare valoare pentru care
ci * (ci + 1) / 2 <= a[i]
Metoda 1 - 30% din punctaj
Se calculeaz num rul maxim de elevi care pot primi bomboane dintr-o cutie. Se observ c
pentru ca acest num r s e maxim trebuie g siµi cei mai mici termeni, respectiv 1, 2, 3 ... Se
încearc formarea unui vector cu num rul de bomboane distribuit. Se procedeaz asem n tor
CAPITOLUL 21. ONI 2017 372
sort rii prin inserµie. Se adaug ultimul termen la sfâr³itul vectorului. Dac se obµine o diferenµ
deja creat , acesta se deplaseaz spre începutul vectorului pân când diferenµele sunt distincte.
Metoda 2
Cea mai simpl modalitate de a a³a o împ rtire este
1 ci 2 ci-1 3 ci-2 .... (de exemplu pt 10 bomboane 1, 4, 2, 3)
La a³area primei perechi trebuie avut în vedere faptul c dac ci * (ci + 1) < a[i] atunci se
a³eaz 1 ³i ci + diferenµa (a[i] - ci * (ci+1) / 2
De exemplu pentru a[i] = 10 se determin ci = 4.
Împ rµirea diferenµiat 1 4 2 3
Pentru a[i] = 12 împ rµirea diferenµiat 1 6 2 3 (prima pereche 1 ³i 4 + 12 - 10)
Algoritmul
Datorit faptului c la ecare pas diferenµa între 2 elemente consecutive scade, se respect
cerinµa ca elementele consecutive s aib diferenµa distinct .
30 }
31
32 int main()
33 {
34 in >> p >> n;
35 for(i = 1; i <= n; i++) in >> a[i];
36
37 if(p == 1)
38 {
39 int vmin = a[1];
40
41 //determinam vmin = min(a[1], a[2] ... a[n])
42 for(i = 1; i <= n; i++)
43 if(vmin > a[i]) vmin = a[i];
44
45 //scadem vmin din elementele vectorului a
46 for(i = 1; i <= n; i++) a[i] = a[i] - vmin;
47
48 //dereminam k = cmmdc(a[1], a[2] ... a[n])
49 k = 0;
50 for(i = 1; i <= n; i++)
51 k = cmmdc(a[i], k);
52
53 out << k;
54 }
55 else
56 {
57 int l, r;
58 for(i = 1; i <= n; i++){
59 k = nr_max_col(a[i]); // determinam valoarea maxima pentru k,
60 // a.i k * (k + 1) / 2 <= a[i]
61
62 out << k << " ";
63 // cea mai simpla modalitate este sa se afiseze 1 k 2 k-1 3 k-2
64 // etc
65 // la afisarea primei prechi trebuie avut in vedere ca daca
66 // k * (k + 1) < n
67 //atunci se afiseaza 1 si k + diferenta (a[i] - k * (k+1) / 2
68
69 l = 1; // se porneste cu 2 indici l = 1
70 r = k; // si r = k si se afiseaza alternativ
71
72 //dupa fiecare afisare l creste, iar r scade
73 while(l <= r)
74 {
75 if(l != r)
76 {
77 out << l << " ";
78 if(r == k) out << r + a[i] - k * (k+1) / 2<< " ";
79 else out << r << " ";
80 }
81 else
82 out << l << " ";
83
84 l = l + 1;
85 r = r - 1;
86 }
87
88 out << "\n";
89 }
90 }
91
92 return 0;
93 }
9 while(a!=b)
10 if(a>b)
11 a=a-b;
12 else
13 b=b-a;
14 return a;
15 }
16
17 int main()
18 {
19 ifstream in("bomboane.in");
20 ofstream out("bomboane.out");
21
22 int p,n,i,k=0,j,nb;
23 long b[10001], c[10001], min, s, r, st, dr;
24 in>>p>>n;
25 // cout<<n<<endl;
26 if(p==1) //cerinta 1
27 {
28 in>>b[1]; min=b[1];
29 for(i=2;i<=n;i++)
30 {
31 in>>b[i];
32 if(b[i]<min)
33 min=b[i];
34 }
35
36 for(i=1;i<=n;i++)
37 b[i]=b[i]-min;
38 i=1;
39 while(b[i]==0)
40 i++;
41 k=b[i];
42 for(i=2;i<=n;i++)
43 if(b[i]!=0)
44 k=cmmdc(k,b[i]);
45 out<<k;
46 }
47 else //cerinta 2
48 {
49 for(i=1;i<=n;i++)
50 {
51 in>>b[i];
52 c[i]=sqrt(2*b[i]);
53 if(c[i]*(c[1]+1)>2*b[i])
54 c[i]--;
55
56 s=0;
57 j=0;
58 do
59 {
60 j++;
61 s=s+j;
62 } while(s<=b[i]);
63
64 if(s==b[i])
65 r=j;
66 else
67 {
68 s=s-j;
69 j--;
70 r=j+b[i]-s;
71 }
72
73 st=1;
74 dr=j;
75 p=1;
76 out<<j<<’ ’;
77 while(st<=dr)
78 {
79 if(p==1)
80 out<<1<<’ ’<<r<<’ ’;
81 else
82 if(st==dr)
83 out<<st<<’ ’;
84 else
CAPITOLUL 21. ONI 2017 375
85 out<<st<<’ ’<<dr<<’ ’;
86
87 st++;
88 dr--;
89 p++;
90 }
91
92 out<<endl;
93 }
94 }
95
96 in.close();
97 out.close();
98 return 0;
99 }
58 impf();
59 else
60 impd();
61
62 fout.close();
63 return 0;
64 }
21.6 orase
Problema 6 - orase 100 de puncte
În t râmul Jupânului exist N + 1 ora³e. Acestea au fost construite în linie dreapt , începând
cu cel în care este casa Jupânului. Între oricare 2 ora³e consecutive s-a construit câte un drum.
Pentru ecare drum, se cunoa³te lungimea lui, exprimat în metri ³i viteza cu care se poate
parcurge, exprimat în metri pe secund .
Cerinµe
Jupânul trebuie s ajung din ora³ul 0 în ora³ul N .
Acesta ³tie c poate îmbun t µi un drum, m rindu-i viteza de la V metri pe secund la V +
1 metri pe secund , cu costul de 1 dolar. Acesta poate îmbun t µi un drum de mai multe ori.
Jupânul are un buget de X dolari ³i ar vrea s -i foloseasc pentru a mic³ora timpul în care
ajunge din ora³ul 0 în ora³ul N .
Date de intrare
Fi³ierul de intrare orase.in are urm toarea structur :
a Pe prima linie se a num rul T , reprezentând tipul de restricµii pe care îl respect testul.
a Pe a doua linie, se a 2 numere naturale N ³i X .
a Pe a treia linie se a N numere naturale, al i-lea num r reprezentând distanµa între ora³ele
i 1 ³i i.
a Pe a patra linie se a N numere naturale, al i-lea num r reprezentând viteza între ora³ele
i 1 ³i i.
Date de ie³ire
Fi³ierul de ie³ire orase.out va conµine pe prima linie un num r natural R ce reprezint partea
întreag a timpului minim de parcurgere a distanµei dintre ora³ul 0 ³i ora³ul N .
Restricµii ³i preciz ri
1 & N & 5 10
4
a
a 1 & X & 10
7
4
a lungimea drumului dintre oricare 2 ora³e este un num r natural din intervalul 1, 10
4
a viteza iniµial dintre oricare 2 ora³e consecutive este un num r natural din intervalul 1, 10
Tipul 1: pentru 5% din punctaj N & 10 ³i X & 10
Tipul 2: pentru alte 10% din punctaj N & 10 ³i X & 10
3 3
Tipul 3: pentru alte 15% din punctaj 1 & N & 5 10 , 1 & X & 10 , distanµele sunt mai mici
4 4
decât 200 ³i se garanteaz c vitezele nale vor mai mici sau egale decât 1000
Tipul 4: pentru alte 20% din punctaj 1 & N & 5 10 , 1 & X & 10 ³i toate distanµele sunt
4 7
egale
Tipul 5: pentru restul de 50% din punctaj 1 & N & 5 10 ³i 1 & X & 10
4 7
Exemple:
CAPITOLUL 21. ONI 2017 377
Velea Alexandru
Structura solutiei
1) Observaµii generale
2) Soluµie în O N X - 15 puncte
3) Soluµie restricµii de tipul 3 - 15 puncte
4) Soluµie restricµii de tipul 4 - 20 puncte
5) Soluµia ocial - 100 puncte
Pentru un drum care are lungime D ³i viteza V, timpul de deplasare este de D/V
Dac m rim viteza drumului de la V la (V+1), timpul de deplasare devine D/(V+1)
Astfel, timpul salvat în urma m ririi vitezei este de (D/V) - (D/(V+1)) = D/(V*(V+1))
Se observ c prima îmbun t µire salveaz D/(V*(V+1)) secunde, a doua îmbun t µire D/((V+1)*(V+2)),
etc
Astfel, ecare îmbun t µire salveaz din ce în ce mai puµin timp.
2) Soluµie în O N X
Folosind observaµiile de la punctul 1, putem alege o strategie greedy de îmbun t µire a drumu-
rilor.
Dac am avea de f cut o singur îmbun t µire, am alege s o facem pe drumulul unde aceasta
ar salva cât mai mult timp.
Acesta ind drumul cu D/(V*(V+1)) maxim.
Astfel, putem demonstra c tot timpul este bine s alegem s îmbun t µim drumul care ne
salveaz cât mai mult timp.
Dac am avea de f cut doar o îmbun t µire, e bine s alegem acel drum. Dup ce l-am ales,
urm toarea îmbun t µire va mai mic decât cea precedent , iar acest lucru ne garanteaz faptul
c dac am putea s facem acest lucru acum, nu am avea niciun motiv s facem îmbun t µirea pe
drumul respectiv mai tarziu.
Iteram de X ori peste toate drumurile, la ecare pas alegem drumul care salveaz cel mai mult
timp ³i îl îmbun t µim.
3) Soluµia pentru tipul 3
Observ m c dac am vrea s îmbun t µim un drum care are distanµa D, este cel mai bine s
îmbun t µim drumul care are viteza minim , pentru a maximiza timpul câ³tigat.
Astfel, faptul c distanµele sunt mai mici decât 200, permite o optimizare a algoritmului de la
pasul 2.
În loc s iter m la ecare pas prin toate drumurile ³i s îl alegem pe cel care salveaz cât mai
mult timp, putem itera prin distanµele drumurilor, a m care este viteza minim a unui drum
cu distanµa respectiv , iar mai apoi îmbun t µim unul dintre drumurile care aveau viteza minim
pentru distanµa xat (este posibil s e mai multe astfel de drumuri)
Astfel, ecare îmbun t µire se poate realiza în 200 de iteraµii, nu în N (50 000).
CAPITOLUL 21. ONI 2017 378
Pentru a aa drumul de vitez minim pentru o distanµ xat , putem s reµinem drumurile
într-o matrice de frecvenµe
drumuri[d][v] reprezentând câte drumuri au distanµa d ³i viteza v
mai µinem un ³ir viteza_minima[d] reprezentând cea mai mic vitez a unui drum cu distanµa
d
- echivalent cu prima valoare v pentru care drumuri[d][v] are o valoare nenul .
Dac la un pas am ales s îmbun t µim un drum care are distanµa d ³i viteza v, trebuie s
mic³or m num rul de drumuri cu viteza v: drumuri[d][v] -= 1
M rim num rul de drumuri cu viteza (v + 1): drumuri[d][v + 1] += 1
* dac nu mai avem drumuri cu viteza v, m rim viteza_minima[d]:
if (drumuri[d][v] == 0) { viteza\_minima[d] += 1; }
4) Soluµia pentru tipul 4
Asem n tor cu tipul 3, doar c aici distanµele nu sunt pân în 200, ci toate distanµele sunt
egale.
Astfel, ne intereseaz doar vitezele, distanµa ind necesar doar la calcularea rezultatului.
O soluµie ar s µinem un ³ir de frecvenµe pentru ecare vitez , ³i s aplic m urm torul
algoritm:
int i = 1;
while (x)
{
if (frecventa[i] > x)
{
frecventa[i + 1] += frecventa[i];
x -= frecventa[i];
frecventa[i] = 0;
}
else
{
frecventa[i] -= x;
frecventa[i + 1] += x;
x = 0;
}
i += 1;
}
O astfel de soluµie se comport foarte bine când valoarea lui N este mare, dar dac N = 1, de
exemplu, ar face X pa³i.
Ca s sc p m de cazul acesta, am putea c uta binar cea mai mic vitez .
Astfel putem aa câte îmbun t µiri trebuie s facem: suma_din(max(0, viteza_cautata_binar
- viteza[i]))
Dac num rul de îmbun t µiri dep ³e³te X, reducem viteza, altfel o m rim.
La nal, îmbun t µim toate drumurile <= viteza c utat pâna la ea, ³i mai îmbun t µim unele
drumuri cu acea vitez (nu le putem îmbun t µi pe toate) dac mai avem îmbun t µiri r mase.
5) Soluµia ocial
Privind ideile de la punctul 1, am putea încerca s c utam binar valoarea ultimului timp salvat.
Not m ultimul timp salvat cu T
Astfel, am putea calcula pentru un drum de câte ori trebuie s îl îmbun t µim, ajungând la
viteza V, astfel încât îmbun t µirea de la V la V+1 s e < T
Acest lucru se poate rezolva tot cu o c utare binar a num rului vitezei, sau folosind o ecuaµie
de gradul 2
Not m cu D distanµa drumului; trebuie s îi g sim viteza V
D / (V * (V + 1)) < T
D / T < V * (V + 1))
0 < V * V + V - D / T
0 = V * V + V - D / T
delta = 1 + 4 * D / T
V1,2 = (-1 +- sqrt(1 + 4 * D / T)) / 2
ONI 2016
22.1 civilizatie
Problema 1 - civilizatie 100 de puncte
În vremuri str vechi P mântul era locuit de c tre o civilizaµie neobi³nuit condus dup reguli
matematice foarte riguroase. Aceast civilizaµie era format din mai multe ora³e-stat asemeni
ora³elor antice. Fiecare ora³ s-a dezvoltat treptat pornind de la un singur cartier de form p trat
cu suprafaµa de un hectar, în jurul c ruia se ad ugau în ecare an cartiere de câte un hectar
ecare în felul urm tor: în primul an s-a format cartierul iniµial, în al doilea an ora³ul s-a extins
formând patru noi cartiere în toate cele patru puncte cardinale, în anul urm tor ora³ul s-a extins
cu 8 noi cartiere dispuse în jurul cartierelor deja formate, ³i a³a mai departe, în ecare an ora³ul
extinzându-se cu înc un rând de cartiere.
Extinderea unui ora³ se opre³te când întâlne³te un alt ora³ sau dac , de³i nu a întâlnit înc
un alt ora³, ajunge la marginea h rµii pe oricare dintre cele patru puncte cardinale. Dou ora³e
se întâlnesc când suprafeµele ocupate de ele ajung s se ating sau între cartierele marginale ale
celor dou ora³e se mai a doar un hectar.
Cerinµe
1. Dimensiunea suprafeµei (în hectare) pe care ar ocupa-o dup t ani, dac nu ar întâlni nici
un alt ora³ ³i nici nu ar ajunge la marginea h rµii.
380
CAPITOLUL 22. ONI 2016 381
2. Timpul scurs pân când toate cele N ora³e ³i-au încetat extinderea, început din cartierele
iniµiale ale c ror coordonate se citesc din ³ier, ³i aria suprafeµei din hart r mas neocupat ,
exprimat în hectare.
Date de intrare
Fi³ierul de intrare civilizatie.in conµine pe prima linie un num r natural p. Pentru toate
testele de intrare, p poate avea doar valoarea 1 sau valoarea 2.
A doua linie a ³ierului conµine dou numere naturale x ³i y reprezentând dimensiunile h rµii.
A treia linie a ³ierului conµine num rul natural t.
A patra linie a ³ierului conµine num rul natural N .
Pe urm toarele N linii se g sesc câte dou numere i ³i j reprezentând coordonatele iniµiale ale
celor N ora³e.
Date de ie³ire
Dac valoarea lui p este 1, atunci se va rezolva numai prima cerinµ .
În acest caz, în ³ierul de ie³ire civilizatie.out se va scrie un singur num r natural, reprezen-
tând aria suprafeµei (în hectare) unui ora³ dup t ani, dac nu ar întâlni nici un alt ora³ ³i nici nu
ar ajunge la marginea h rµii.
Dac valoarea lui p este 2 atunci, se va rezolva numai a doua cerinµ .
În acest caz, ³ierul de ie³ire va conµine pe prima linie un num r natural reprezentând aria
suprafeµei din hart r mas neocupat dup ce toate cele N ora³e ³i-au încetat expansiunea, iar
pe a doua linie un num r natural reprezentând timpul scurs pân când ultimul ora³ s-a oprit din
expansiune.
Restricµii ³i preciz ri
a 1 & N & 2000
a 1 & x, y, t & 100 000
a Pentru 30% din teste se garanteaz faptul c x, y & 500
a Pentru rezolvarea corect a primei cerinµe se acord 20 de puncte, iar pentru rezolvarea
corect a celei de-a doua cerinµe se acord 80 de puncte.
Exemple:
civilizatie.in civilizatie.out Explicaµii
1 145 p = 1, în ³ier se va scrie aria suprafeµei ce ar putea ocupat
79 de un ora³ în timp de 9 ani.
9 Atenµie! Pentru acest test se rezolv doar cerinµa 1).
2
32
46
2 33
79 4
5
2
32
46
2 97 p=2, deci se rezolv doar cerinµa 2
10 10 1 în acest caz, cele 3 civilizaµii nu se vor putea extinde deloc, deci
5 celelalte 97 de hectare r mân neocupate.
3
22
24
32
Timp maxim de executare/test: 3.0 secunde
Memorie: total 128 MB
Dimensiune maxim a sursei: 15 KB
CAPITOLUL 22. ONI 2016 382
Cerinµa 1 - Soluµia 1
Consider m un tablou bidimensional, în care ecare hectar este un element al tabloului.
În acest tablou consider m coordonatele de origine ale ora³ului în mijlocul tabloului.
pentru t=1 coordonatele noilor cartiere sunt chiar coordonatele iniµiale;
pentru t=2 coordonatele noilor cartiere sunt date de: |x-x0|+|y-y0|=1;
pentru t=3 coordonatele noilor cartiere sunt date de: |x-x0|+|y-y0|=2;
...
pentru cazul general |x-x0|+|y-y0|=t-1;
În concluzie num rul de cuburi din ecare romb se poate calcula dup formula:
1+4+8+12+16+...+4(k-1)=
1+4(1+2+3+4+...+k-1)=
1+4k(k-1)/2=
1+2k(k-1)
Cerinµa 2 - Soluµia 1
Folosim un tablou bidimensional de dimensiune N N în care reµinem dup câµi ani s-ar
întâlnii ora³ele dou câte dou ignorându-le pe toate celelalte (îniµial punctul de întâlnire va la
jum tatea drumului).
Folosim un tablou unidimensional de dimensiune N în care reµinem cel mai mic num r de ani
dup care un ora³ ar ajunge la una dintre margini.
Alegem pe baza acestor dou tablouri ora³ele care se opresc primele ³i recalcul m momentele
de întânire ale acestor ora³e cu toate celelalte (întâlnirea nu va mai pentru toate la jum tatea
drumului).
Relu m acest procedeu cu cele r mase pân când alegem toate civilizaµiile.
3
Complexitate O N
Cerinµa 2 - Soluµia 2
Pentru a reduce timpul de execuµie folosim un tablou unidimensional în care reµinem minimele
pe linii. Aceste minime le actualiz m atunci când recalcul m momentele de întalnire dintre ora³ele
alese ³i celelalte ora³e.
38 for(int i=1;i<=n;i++)
39 {
40 int dxMin=min(nx-x[i]+1,x[i]),dyMin=min(ny-y[i]+1,y[i]);
41 dxyMin[i]=min(dxMin,dyMin);
42 }
43
44 // calcul distantei initiale pana la celelalte civilizatii
45 for(int i=1;i<=n;i++)
46 {
47 lMin[i]=nx+ny;
48 for(int j=1;j<=n;j++)
49 {
50 difMin[i][j]=abs(x[i]-x[j])+abs(y[i]-y[j])+1;
51 difMin2[i][j]=difMin[i][j]/2;
52 if(difMin2[i][j]<lMin[i] && i!=j)
53 {
54 lMin[i]=difMin2[i][j];jlMin[i]=j;
55 }
56 }
57 }
58
59 // selectare orase in ordinea opriri expansiunii
60 int nr=0;
61 while(nr<n)
62 {
63 // cautare minim
64 int mMin=nx+ny,iMin,jMin,im=0;
65 for(int i=1;i<=n;i++)
66 {
67 if(mMin>lMin[i] && !dMin[i])
68 {
69 mMin=lMin[i];iMin=i;jMin=jlMin[i];im=0;
70 }
71 if(mMin>dxyMin[i] && !dMin[i])
72 {
73 mMin=dxyMin[i];im=i;
74 }
75 }
76
77 // calcul timp de oprire oras selectat si ajustare timpi
78 // pentru celelalte
79 int i=iMin,j=jMin;
80 if(im!=0)
81 {
82 i=im;dMin[i]=dxyMin[i];
83 }
84 else
85 {
86 if(dMin[i])
87 { // civilizatia i verificata deja
88 i=jMin;j=iMin;
89 }
90
91 dMin[i]=difMin2[i][j];
92 }
93
94 nr++;
95 lMin[i]=nx+ny;
96 for(int k=1;k<=n;k++) // pt toate elementele de pe col i
97 if(!dMin[k] || !dMin[i])
98 if(difMin2[k][i]!=dMin[i])
99 {
100 difMin2[k][i]=difMin2[i][k]=difMin[k][i]-dMin[i];
101 if(difMin2[k][i]<lMin[i] &&
102 k!=i &&
103 (!dMin[k] || !dMin[i]))
104 {
105 lMin[i]=difMin2[k][i];jlMin[i]=k;
106 }
107 if(jlMin[k]==i)
108 {
109 lMin[k]=nx+ny;
110 for(int ik=1;ik<=n;ik++) // pt toate elementele
111 // de pe linia k
112 if(difMin2[k][ik]<lMin[k] && k!=ik )
113 {
CAPITOLUL 22. ONI 2016 386
114 lMin[k]=difMin2[k][ik];jlMin[k]=ik;
115 }
116 }
117 }
118 }
119
120 // calcul suprafete
121 for(int i=1;i<=n;i++)
122 {
123 t=dMin[i];
124 ct[i]=2*t*(t-1)+1;
125 }
126
127 unsigned long long tot=0;
128 int dMax=0;
129 for(int i=1;i<=n;i++)
130 {
131 tot=tot+ct[i];
132 if(dMax<dMin[i])
133 dMax=dMin[i];
134 }
135
136 fout<<(unsigned long long)nx*ny-tot<<’\n’;
137 fout<<dMax<<’\n’;
138 }
139
140 return 0;
141 }
22.2 cmmdc
Problema 2 - cmmdc 100 de puncte
Fie un ³ir de numere naturale nenule a1 , a2 , ..., an ³i un num r natural k .
Cerinµe
S se determine un grup de k numere din ³ir care au proprietatea ca cel mai mare divizor
comun al lor este maxim. Dac exist mai multe astfel de grupuri, se cere acel grup pentru care
suma elementelor este maxim .
Date de intrare
Fi³ierul cmmdc.in conµine pe prima linie numerele naturale n ³i k separate prin spaµiu. Pe
linia a doua se g sesc numerele naturale a1 , a2 , ..., an separate prin câte un spaµiu.
Date de ie³ire
Fi³ierul cmmdc.out conµine pe prima linie un num r natural reprezentând cel mai mare
divizor comun a exact k numere din ³ir, maxim posibil. Pe linia a doua, separate prin câte un
spaµiu ³i ordonate descresc tor, se a cele k numere din ³ir care dau cel mai mare divizor comun
maxim.
Restricµii ³i preciz ri
a 1 & n & 1 000 000
a 2 & k & 100 000
a k&n
a 1 & ai & 1 000 000, i 1..n
a Valorile din ³ir se pot repeta.
Exemple:
cmmdc.in cmmdc.out Explicaµii
63 3 Cel mai mare divizor comun care se poate obµine dintr-un grup
6 9 8 10 15 3 15 9 6 de 3 numere este 3, iar cele 3 numere care dau suma maxim ,
ordonate descresc tor, sunt 15, 9 ³i 6.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 64 MB
Dimensiune maxim a sursei: 15 KB
CAPITOLUL 22. ONI 2016 387
Se construie³te un vector de frecvenµe (v i = de câte ori apare i în sirul de numere dat);
Se face rationamentul urmator: dac k numere au cmmdc-ul egal cu x, atunci ele sunt e egale
cu x, e sunt multiplii ai numarului x.
Astefel se parcurge cu o variabila x descrescator intervalul 1 000 000 2 si pentru ecare
valoare a lui x se determina daca exista cel putin k numere egale cu x sau multiplii de-i lui x, cu
un algoritm asemanator cu Ciurul lui Eratostene.
Aceasta determinare se face parcurgand multiplii lui x descrescator, astfel prima submultime
determinata este solutia ceruta. Cel mai mare multiplu a lui x care teoretic poate sa apara printre
cele n numere se poate calcula in functie de valoarea maxima din sirul a (notata max a si care
oricum nu depaseste 1 000 000).
Complexitate:
O n pentru constructia vectorului v .
O max a log max a pentru determinarea rezultatului (unde max a e maximul din sirul
a)
Expresia de mai sus e aproximarea pentru:
22.3 livada
Problema 3 - livada 100 de puncte
Fermierul Quinto are o livad plin cu pomi fructiferi. Livada are N rânduri, numerotate de
la 1 la N , pe ecare rând aându-se câte M pomi fructiferi, numerotaµi de la 1 la M . Livada lui
Quinto este una special , a³a c pentru unii pomi se cunoa³te cantitatea de fructe (exprimat în
kg) care poate culeas , iar pentru alµii aceasta poate determinat pe baza unei formule.
Quinto ³i-a propus s recolteze C kg de fructe din pomii aaµi în livada lui. Acesta folose³te un
utilaj modern pentru culesul fructelor. Utilajul poate folosit pe oricare din rândurile livezii, dar
poate aduna doar fructele dintr-un ³ir consecutiv de pomi, începând cu primul pom de pe rândul
respectiv, neavând posibilitatea de a culege parµial fructele dintr-un pom.
Preocupat de frumuseµea livezii sale, Quinto s-a gândit la restricµii suplimentare pentru re-
coltarea cantit µii C de fructe. Astfel, el dore³te s adune fructele din pomi de pe maximum R
rânduri diferite, pentru ca N R rânduri s r mân complete.
Deasemenea, el dore³te s culeag cu prioritate pomii care au o cantitate cât mai mic de
fructe, pentru ca în livad s r mân cei mai roditori pomi. Quinto ³i-a dat seama c este dicil
s culeag x C kg de fructe, prin urmare este mulµumit ³i cu o cantitate mai mare, care respect
celelalte condiµii impuse de el.
Cerinµe
Determinaµi cea mai mic valoare X posibil astfel încât s se poat culege, în condiµiile de
mai sus, o cantitate de cel puµin C kg de fructe ³i orice pom din care se culeg fructe s conµin
cel mult X kg de fructe.
Date de intrare
Pe prima linie a ³ierului livada.in se a 4 numere naturale N , M , C , R cu semnicaµia din
enunµ.
Pe a doua linie din ³ierul de intrare se a 5 numere naturale x, y , z , w, u, separate printr-un
spaµiu.
Dac not m cu Aij cantitatea de fructe (exprimat în kg) din cel de-al j -lea pom de pe
linia i, atunci:
Linia a treia din ³ierul de intrare conµine M valori A1i, 1 & i & M , separate printr-un
spaµiu
Linia a patra din ³ierul de intrare conµine N 1 valori Ai1, 2 & i & N , separate printr-un
spaµiu
Celelalte valori Aij , 2 & i & N , 2 & j & M , se calculeaz conform formulei:
Date de ie³ire
CAPITOLUL 22. ONI 2016 389
Fi³ierul de ie³ire livada.out va conµine o singur valoare scris pe prima linie, care reprezint
cea mai mic valoare a cantit µii de fructe (exprimat în kg) dintr-un pom cules, astfel încât s
e respectate toate restricµiile problemei.
Restricµii ³i preciz ri
a 1 & R & N & 100
a 1 & M & 25 000
a 0 & x, y, z, w, u & 10
9
a Atenµie la determinarea ec rei valori Aij pentru c în formul sunt produse care pot
32
s furnizeze valori mai mari decât 2 1.
a 1 & C & 10
18
Exemple:
livada.in livada.out Explicaµii
5 6 18 4 3 6 5 4 Sunt 5 rânduri cu câte 6 pomi pe ecare rând. Figura al turat
2741351 arat matricea care se obµine conform formulelor precizate.
25263 Se dore³te culegerea a cel puµin 18 de kg de fructe de pe maxim
4 rânduri din cele 5.
în gura al turat , este prezentat o soluµie
posibil în care cantitatea maxim culeas
dintr-un pom este de 4 kg.
Nu se pot culege 18 de kg de fructe de pe
maxim 4 rânduri astfel încât s e cule³i doar pomi cu cantitate
de fructe 3kg (în acest caz se pot culege cel mult 8 kg).
Timp maxim de executare/test: 0.5 secunde
Memorie: total 64 MB
Dimensiune maxim a sursei: 15 KB
Problema se rezolv prin c utarea soluµiei (c utare binar sau secvenµial ). Se caut cantitatea
minim de fructe culeas dintr-un singur pom fructifer (se veric pe rând valori posibile ³i se
alege valoarea minim care respect restricµiile problemei).
Soluµii parµiale 30 / 70 puncte
Odat xat valoarea pentru cantitatea maxim de kg de fructe culese dintr-un singur pom,
se determin cantitatea maxim de fructe care poate culeas din întreaga livad astfel încât s
e respectate restricµiile problemei.
Aceast valoare poate aat dac se determin pentru ecare rând cantitatea maxim de
fructe care poate culeas din pomii de pe acel rând, însumând pe rând valorile de pe acest rând
pân la prima valoare mai mare decât valoarea xat , ³i se memoreaz aceste valori într-un vector,
2
care este apoi sortat descresc tor. Este sucient un algoritm de sortare de complexitate O N .
Se însumeaz apoi primele R valori din vectorul sortat, aceast sum reprezentând cantitatea
maxim de fructe care pot adunate din livad .
Dup determinarea cantit µii maxime care poate culeas din întreaga livad , se veric dac
aceasta este cel puµin egal cu cantitatea C cerut în enunµ.
O implementare a ideii de mai sus care folose³te c utarea secvenµial a soluµiei obµine 30
puncte, complexitatea algoritmului ind O N M M axV al, unde N e num rul de rânduri,
M e num rul de pomi de pe ecare rând, iar M axV al e cea mai mare cantitate de fructe dintr-un
singur pom.
O implementare a ideii de mai sus care folose³te c utarea binar a soluµiei obµine 70 puncte,
complexitatea algoritmului ind O N M log M axV al.
CAPITOLUL 22. ONI 2016 390
15 int N,M,R,Sol;
16 long long C;
17
18 void Read()
19 {
20 long long x,y,z,w,u;
21
22 fin>>N>>M>>C>>R;
23 fin>>x>>y>>z>>w>>u;
24
25 for(int i = 1; i<=M; i++)
26 fin>>A[1][i];
27
28 for(int i = 2; i<=N; i++)
29 fin>>A[i][1];
30
31 for(int i = 2; i <= N; ++i)
32 for(int j = 2; j <= M; ++j)
33 A[i][j] = (x * A[i - 1][j] +
34 y * A[i][j - 1] +
35 z * A[i - 1][j - 1] +
36 w) % u;
37
38 }
39
40 void Precalculate()
41 {
42 for(int i = 1; i <= N; ++i)
43 for(int j = 1; j <= M; ++j)
44 {
45 Sum[i][j] = A[i][j] + Sum[i][j-1];
46 Max[i][j] = max(Max[i][j-1],A[i][j]);
47 }
48 }
49
50 long long Find(int i, int Value)
51 {
52 long long Crop = 0;
53
54 int Left = 1, Right = M;
55
56 while(Left <= Right)
57 {
58 int Mid = (Left+Right) / 2;
59 if(Max[i][Mid] <= Value)
60 {
61 Crop = Sum[i][Mid];
62 Left = Mid + 1;
63 }
64 else
65 Right = Mid - 1;
66 }
67 return Crop;
68 }
69
70 bool Check(int Value)
71 {
72 long long V[NMax],k = 0;
73
74 for(int i = 1; i <= N; i++)
75 V[++k] = Find(i,Value);
76
77 sort(V+1,V+k+1,greater<long long>());
78
79 long long Total = 0;
80
81 for(int i = 1; i<=R && i<=k; i++)
82 Total+=V[i];
83
84 return (Total >= C);
85 }
86
87 void Solve()
88 {
89 int Left = 1, Right = MaxVal;
90 while(Left <= Right)
CAPITOLUL 22. ONI 2016 393
91 {
92 int Mid = (Left + Right) / 2;
93
94 if(Check(Mid))
95 {
96 Sol = Mid;
97 Right = Mid - 1;
98 }
99 else
100 Left = Mid + 1;
101 }
102 }
103
104 void Print()
105 {
106 fout<<Sol<<"\n";
107 }
108
109 int main()
110 {
111 Read();
112 Precalculate();
113 Solve();
114 Print();
115 return 0;
116 }
22.4 dif2
Problema 4 - dif2 100 de puncte
Sandu a studiat la ora de informatic mai multe aplicaµii cu vectori de numere naturale, iar
acum are de rezolvat o problem interesant . Se d un ³ir X X1 , X2 , ..., Xn de numere naturale
nenule ³i dou numere naturale p1 ³i p2 , unde p1 $ p2 . Sandu trebuie s construiasc un nou ³ir
Y Y1 , Y2 , ..., Ynn cu n n elemente obµinute din toate produsele de câte dou elemente din
³irul X (ecare element din ³irul Y este de forma Xi Xj , 1 & i,j & n). Sandu are de calculat dou
valori naturale d1 ³i d2 obµinute din ³irul Y . Valoarea d1 este egal cu diferenµa maxim posibil
dintre dou valori ale ³irului Y . Pentru a obµine valoarea d2 , Sandu trebuie s considere c ³irul
Y are elementele ordonate descresc tor iar d2 va diferenµa dintre valorile aate pe poziµiile p1
³i p2 în ³irul ordonat descresc tor. Sandu a g sit rapid valorile d1 ³i d2 ³i, pentru a le verica, v
roag s le determinaµi ³i voi.
Cerinµe
Dându-se ³irul X cu n elemente ³i valorile p1 ³i p2 , determinaµi valorile d1 ³i d2 .
Date de intrare
Fi³ierul de intrare dif2.in va conµine pe prima linie un num r natural C care poate doar
1 sau 2. Dac C 1, atunci pe linia a doua se va aa num rul natural n. Dac C 2, atunci
pe linia a doua se vor aa numerele naturale n, p1 ³i p2 separate prin câte un spaµiu. în ambele
cazuri, pe urm toarele n linii se vor aa elementele ³irului X , câte un num r natural pe ecare
linie a ³ierului.
Date de ie³ire
În cazul C 1, ³ierul de ie³ire dif2.out va conµine pe prima linie valoarea d1 egal cu
diferenµa maxim dintre oricare dou valori din ³irul Y . în cazul C 2 ³ierul de ie³ire va conµine
pe prima linie un num r natural d2 reprezentând diferenµa dintre valorile aate pe poziµiile p1 ³i
p2 din ³irul Y , presupunând c ar ordonat descresc tor.
Restricµii ³i preciz ri
a3 $ n $ 300 000
a1 & p1 $ p2 & n2
a 1 & Xi $ 300 000, i 1..n
a Pentru teste valorând 30 de puncte vom avea C 1, iar pentru teste valorând 70 de puncte
vom avea C 2.
a Pentru teste valorând 10 puncte vom avea C 2 ³i n & 100
CAPITOLUL 22. ONI 2016 394
Exemple:
dif2.in dif2.out Explicaµii
1 32 Atenµie, C 1, deci se rezolv doar cerinµa 1!
4 Valoarea maxim d1 va 32 ³i se obµine efectuând diferenµa
3 dintre 6*6 ³i 2*2.
5
2
6
2 8 Atenµie, C 2, deci se rezolv doar cerinµa 2!
4 5 11 Se obµin în Y urm toarele 16 valori: 3*3, 3*5, 3*2, 3*6, 5*3,
3 5*5, 5*2, 5*6, 2*3, 2*5, 2*2, 2*6, 6*3, 6*5, 6*2, 6*6.
5 Valoarea d2 va 8, deoarece dac vom considera ³irul Y ordonat
2 descresc tor (36, 30, 30, 25, 18, 18, 15, 15, 12, 12, 10, 10, 9, 6,
6 6, 4), atunci Y[5]-Y[11]=18-10=8
Timp maxim de executare/test: 2.0 secunde
Memorie: total 16 MB
Dimensiune maxim a sursei: 15 KB
Se observ c valoarea d1 este egal cu diferenµa dintre valoarea maxim ³i valoarea minim a
elementelor din ³irul Y . Se pot calcula valorile extreme ale elementelor lui X iar d1 va diferenµa
p tratelor lor.
Pentru d2 nu se poate construi ³irul Y ³i apoi s se ordoneze descresc tor deoarece exist o
2
limitare a memoriei disponibile ³i algoritmi k log k pentru sortare (k n ).
2
Voi prezenta un algoritm de complexitate O DIMn n log DIMV , unde DIMV este valoarea
maxima din X .
Se vor num ra câte perechi de elemente din X au valoarea mai mic sau egal decât i. Se
poate face num rarea în O n dac vom precalcula un sir ci cu num rul de valori din X mai
mici sau egale cu i.
Pentru a aa pe ce poziµie va un produs p, vom utiliza ³irul c precalculat ³i vom num r
pentru ecare element din ³ir câte elemente contribuie la construirea unei valori ce nu dep ³e³te
p.
Vom utiliza c utarea binar pentru determinarea celor dou valori. Nu e necesar s facem
sort ri descresc toare, se deduce u³or poziµia necesar dac vom face calculul în cazul ordon rii
cresc toare.
Soluµia comisiei (studenµi LUCIAN BICSI ³i PETRU-ERIC STAVARACHE)
Soluµie O(V logV):
inem un vector de frecvenµ f req i pentru valorile elementelor împreun cu sume parµiale
pe pe acest vector Sumi.
prexe
Pentru a aa produsul aat pe o poziµie Z , c ut m binar produsul, iar pentru un produs P
xat trebuie sa vedem câte perechi (a, b) exista cu a b & P .
Pentru asta vom parcurge ecare valoare posibila, iar pentru o valoare A xata deducem ca
B & P ©A. A³adar toate elementele cu valoarea cel mult B vor forma perechi posibile împreun
cu A. Vor exista f A SumB astfel de perechi.
Dac num rul total de perechi de acest fel este & Z , atunci soluµia ' P .
Solutie O N log2 V :
Similar cu soluµia anterioara, doar ca in loc sa µinem un vector de frecventa, sortam vectorul
iniµial.
Cu Z si P xate (ca in soluµia anterioara), pentru a num r perechile vom face:
Pentru o poziµie i din vector, trebuie sa g sim j maxim astfel încât v i v j & P .
Odat g sit, v i, v 1, ..., v i, j toate vor perechi posibile.
Acest j poate c utat binar, deoarece vectorul este sortat.
CAPITOLUL 22. ONI 2016 395
48
49 int t;
50 long long a, b;
51
52 Read(t);
53 Read(n);
54
55 if(t == 2)
56 {
57 Read(a);
58 Read(b);
59 }
60
61 for(int i = 1; i <= n; ++i)
62 Read(V[i]);
63
64 sort(V + 1, V + n + 1);
65
66 if(t == 1)
67 cout << 1LL * V[n] * V[n] - 1LL * V[1] * V[1] << endl;
68 else
69 cout << kth(1LL * n * n - a + 1) - kth(1LL * n * n - b + 1) << endl;
70
71 return 0;
72 }
22.5 leduri
Problema 5 - leduri 100 de puncte
Am un cablu cu N leduri (numerotate de la 1 la N ) a³ezate echidistant. Iniµial, unele leduri
sunt aprinse, iar altele sunt stinse. Ledurile sunt legate între ele astfel încât atingerea ec rui
led produce modicarea atât a st rii lui, cât ³i a ledurilor vecine lui. Deci, dac se atinge ledul i
(2 & i & N 1) atunci se modic st rile ledurilor i 1, i ³i i 1. Dac se atinge ledul 1, atunci
se modic st rile ledurilor 1 ³i 2, iar dac se atinge ledul N , atunci se modic st rile ledurilor
N 1 ³i N . Vreau s modic starea ledurilor astfel încât s semene cu cablul cu N leduri pe care
îl are Ionuµ, prietenul meu (dou cabluri seam n dac pentru orice i 1..N st rile ledurilor de
pe poziµia i sunt identice).
Cerinµe
Cunoscând cum arat cablul lui Ionuµ, ajutaµi-m s determin num rul minim de atingeri ale
unor leduri astfel încât cablul meu s arate ca ³i cablul lui Ionuµ.
Date de intrare
Fi³ierul de intrare leduri.in conµine pe prima linie num rul natural N . Pe a doua linie sunt
N cifre binare separate prin câte un spaµiu reprezentând st rile ledurilor de pe cablul meu. Cifra
de pe poziµia i este 0 dac ledul i este stins, respectiv este 1 dac ledul i este aprins (i 1..N ).
Pe a treia linie sunt N cifre binare separate prin câte un spaµiu, reprezentând st rile ledurilor de
pe cablul lui Ionuµ.
Date de ie³ire
Fi³ierul de ie³ire leduri.out va conµine pe prima linie un singur num r natural reprezentând
num rul minim de atingeri ale unor leduri astfel încât cablul meu s arate ca ³i cablul lui Ionuµ.
Restricµii ³i preciz ri
a 1 & N & 100 000
a Se garanteaz c pentru toate testele exist soluµie.
a Pentru teste valorând 30 de puncte, N va cel mult 20
Exemple:
CAPITOLUL 22. ONI 2016 399
În primul rând, se observa becurile pot atinse in orice ordine, f r a produce schimb ri de
efect în nal. O a doua observaµie util în rezolvarea problemei este c , pentru a transforma
conguraµia iniµial în cea nala, orice bec ajunge sa e atins maximum o data.
Acest lucru rezult din faptul c atingerea unui bec pentru a doua oara produce neutralizarea
primei operaµii.
n
Din cele doua observaµii se deduce c num rul de seturi de operaµii diferite posibile este 2
(orice set de operaµii se poate vedea ca atingerea unei submulµimi de becuri din cele n).
Soluµia pentru 20p:
Pentru 20% din teste, n & 20, deci se poate simula orice set de operaµii ³i, pentru cele care
produc efectul dorit, s se calculeze num rul de operaµii ³i s se compare cu minimul obµinut de
pân atunci.
n
Complexitatea acestei soluµii este O 2 .
Soluµia pentru 100p:
La o analiz mai atent a conguraµiilor posibile ³i a modurilor din care se poate ajunge la
acestea, se observ c exist maximum dou soluµii de transformare valide. Mai exact, aplicând
o strategie tip Greedy pentru a transforma ³irul iniµial în cel nal, se observ c setul de operaµii
este unic determinat de atingerea sau nu a primului element. Mai exact:
S presupunem c am ales s atingem primul element (cazul în care nu îl atingem se va trata
în mod analog). Se disting dou cazuri:
1) Becul 1 din starea actual e diferit de becul 1 în starea nal , unde singura variant posibil
de a rezolva aceast problem este s atingem becul 2 (deoarece becul 1 nu mai poate schimbat,
din observaµiile de mai sus)
2) St rile celor doua becuri coincid, caz în care nu avem voie sa atingem becul 2 (dac l-am
atinge, nu am mai putea modica înapoi starea becului 1)
Inductiv, se demonstreaz c atingerile tuturor celor n becuri sunt unic determinate.
În nal, se poate s obµinem o stare diferit pentru ultimul bec, caz in care soluµia obtinut
nu este corect .
Soluµia de 100p trateaz cele dou cazuri (atingerea sau nu a primului bec), dup care simuleaz
strategia descris mai sus pentru a obµine o conguraµie care difer de cea nal la cel mult ultima
poziµie. Dac cele doua valori coincid, se actualizeaz eventualul num r minim de operaµii. Dac
acest minim nu a fost actualizat, nu vor exista soluµii (în cadrul problemei, îns , orice test admite
soluµie valid ).
Extra:
Pentru o mai bun înµelegere a corectitudinii problemei, propunem înc o demonstraµie, mai
formal :
Datorita comutativit µii setului de operaµii, este sucient ³i necesar s aducem ambele con-
guraµii la o stare intermediar .
S consider m (S0) = 000 ... 000 ³i (S1) = 000 ... 001.
Lem : Din orice stare iniµial se poate ajunge în S0 sau S1
Demonstraµie: Rezult din algoritmul descris mai sus (de ecare dat când g sim un bec
aprins, atingem becul imediat urm tor ³i repet m).
În continuare, dac se poate ajunge din S0 în S1 sau invers, atunci se poate ajunge din orice
stare în orice stare. Ne intereseaz acum s analiz m când se întâmpl acest lucru.
Analiz m în funcµie de resturile lui n la împ rµirea cu 3:
CAPITOLUL 22. ONI 2016 400
0) n 3k : Putem din starea (S1) s atingem becurile 1, 2, 4, 5, 7, 8, ..., 3k-2, 3k-1 ³i ajungem
în (S0)
1) n 3k 1: Putem din starea (S1) s atingem becurile 2, 3, 5, 6, ..., 3k - 1, 3k ³i ajungem
în (S0)
2) n 3k 2: Acesta este cazul interesant. în acest caz demonstr m imediat c din (S0) nu
se poate ajunge în (S1) (sau invers)
Pentru cazurile în care n = 3k sau n = 3k + 1 rezult imediat c se poate ajunge din orice
stare în oricare alta (deoarece din orice stare se poate ajunge în (S0) sau (S1) ³i din (S0) se poate
ajunge în (S1) ).
n
Cum dintr-o stare x se poate ajunge în toate cele 2 st ri diferite, iar num rul de operaµii
n
posibile este 2 , rezult imediat c modul prin care se ajunge din x în y este unic, pentru orice y
(s presupunem c exist dou submulµimi care îl transform pe x în y ; conform principiului lui
k k
Dirichlet, exist o stare care nu poate atins , pentru c exist 2 st ri diferite ³i 2 transform ri
diferite, iar dou dintre ele duc în aceea³i stare => contradicµie cu ce am demonstrat mai sus).
În concluzie, pentru n 3k sau n 3k 1, soluµia este unic ³i este obµinut prin combinarea
(prin sau exclusiv) a celor dou ³iruri rezultate din algoritmul descris.
Pentru n 3k 2, s consider m starea (S0) ³i s presupunem prin absurd c putem ajunge în
(S1). Atunci, în mod evident, putem ajunge din (S0) în orice alt stare. Folosind un raµionament
asem n tor cu cel din demonstraµia precedent , rezult c exist un singur mod de a transforma
(S0) într-o stare x. Ori, exist dou moduri de a ajunge de la (S0) la (S0): una este setul vid,
iar alta este setul de operaµii 1, 2, 4, 5, 7, 8, ..., 3k + 1, 3k + 2 (se demonstreaz prin inducµie).
Deci presupunerea f cut este fals . Mai mult, se demonstreaz c acest set de operaµii nevid este
unicul mod de a ajunge din (S0) în (S0).
Not : Acela³i set de operaµii transform ³irul (S1) în (S1).
De aici se observ c pentru a ajunge dintr-o stare iniµial (A) într-o stare nal (B) este
sucient ³i necesar ca:
1) Din st rile (A), (B) folosind algoritmul din demonstraµia lemei s se ajung la aceea³i stare
2) Setul de operaµii s e format din combinarea celor doua seturi de operaµii din algoritmul
respectiv, sau prin combinarea celor dou cu "³irul special" 1, 2, 4, 5, ..., 3k + 1, 3k + 2
În concluzie, soluµia se poate obµine ³i prin aducerea celor doua ³iruri la o form intermediar
(tehnica cunoscut ³i ca "meet in the middle"), combinarea celor dou seturi de operaµii ³i,
eventual, tratarea cazului special n 3k 2 (singurul caz în care exist mai multe soluµii ale
problemei).
Complexitate nal : O n
21 }
22 }
23 return ops;
24 }
25
26 int main()
27 {
28 freopen("leduri.in", "r", stdin);
29 freopen("leduri.out", "w", stdout);
30
31 cin >> n;
32
33 for(int i = 1; i <= n; ++i)
34 {
35 cin >> A0[i];
36 A1[i] = A0[i];
37 }
38
39 for(int i = 1; i <= n; ++i)
40 cin >> B[i];
41
42 A1[1] ^= 1;
43 A1[2] ^= 1;
44
45 int a = transform(A0);
46 int b = transform(A1);
47
48 int ans = 1000000;
49 if(A0[n] == B[n]) ans = min(ans, a);
50 if(A1[n] == B[n]) ans = min(ans, b + 1);
51
52 if(ans == 1000000)
53 ans = -1;
54
55 cout << ans << endl;
56
57 return 0;
58 }
35
36 for(int i = 1; i <= n; ++i)
37 if(v[i] != fin[i])
38 return INF;
39
40 return cnt;
41 }
42
43 ofstream out("leduri.out");
44
45 int main()
46 {
47 ifstream in("leduri.in");
48 in >> n;
49 assert(1 <= n && n <= 100000);
50
51 for(int i = 1; i <= n; ++i)
52 {
53 in >> v[i];
54 init[i] = v[i];
55 assert(v[i] == 0 || v[i] == 1);
56 }
57
58 for(int i = 1; i <= n; ++i)
59 {
60 in >> fin[i];
61 assert(fin[i] == 0 || fin[i] == 1);
62 }
63
64 int s1 = go();
65
66 for(int i = 1; i <= n; ++i)
67 v[i] = init[i];
68
69 v[1] ^= 1;
70 v[2] ^= 1;
71
72 int s2 = go() + 1;
73
74 if(s1 >= INF && s2 >= INF)
75 {
76 out << "-1\n";
77 return 0;
78 }
79 else
80 out << min(s1, s2) << "\n";
81
82 return 0;
83 }
22.6 omogene
Problema 6 - omogene 100 de puncte
Se consider o matrice cu L linii ³i C coloane care memoreaz doar valori din mulµimea 0,1,2. O
submatrice nevid (format din cel puµin o linie ³i cel puµin o coloan ) a acestei matrice o numim
omogen dac num rul valorilor de 0 este egal cu num rul de valori de 1 ³i egal cu num rul
valorilor de 2.
De exemplu, în matricea
0 1 2 0
1 2 0 1
sunt ³ase submatrice omogene, acestea ind:
012 120 012 120 120 201
120 201
Submatricele a treia ³i a patra sunt formate din prima linie a matricei iniµial , iar submatricele
a cincea ³i a ³asea sunt formate din a doua linie.
Cerinµe
S se determine câte submatrice nevide omogene exist .
CAPITOLUL 22. ONI 2016 403
Date de intrare
Fi³ierul omogene.in conµine pe prima linie numerele naturale L ³i C . Pe urm toarele L linii
se a câte C numere naturale separate prin spaµii reprezentând câte o linie din matrice.
Date de ie³ire
Fi³ierul omogene.out va conµine pe prima linie un singur num r natural reprezentând num rul
submatricelor nevide omogene.
Restricµii ³i preciz ri
a 2 & L & C & 5 000
a 4 & L C & 65 536
a Atenµie, o submatrice este format dintr-o secvenµ continu de linii ³i coloane, deci, de
exemplu, dac se aleg dintr-o matrice liniile 1, 2 ³i 5, atunci acestea nu formeaz o submatrice.
9
a Num rul submatricelor omogene va mai mic decât 2 10
a întreaga matrice poate submatrice omogen
Exemple:
omogene.in omogene.out Explicaµii
2 4 6 Cele ³ase submatrice au fost menµionate în enunµ.
0 1 20
1 2 01
3 3 3
0 1 2
0 2 2
0 1 1
Timp maxim de executare/test: 3.0 secunde
Memorie: total 64 MB
Dimensiune maxim a sursei: 15 KB
Rezolv m mai întâi problema liniar . Se consider un vector t de lungime n care memoreaz
doar valori din mulµimea {1,2,3}. S se determine num rul secvenµelor omogene (adic în care
num rul valorilor de 0 este egal cu num rul valorilor de 1 ³i egal cu num rul valorilor de 2).
Construim sirul sumelor partiale:
s0[i]= num rul valorilor de 0 din t[1..i]
s1[i]= num rul valorilor de 1 din t[1..i]
s2[i]= num rul valorilor de 2 din t[1..i]
Apoi construim ³irurile
d01[0] = d12[0] = d20[0] = 0 ³i
d01[i] = s0[i] - s1[i], i=1..n
d12[i] = s1[i] - s2[i] , i=1..n
d20[i] = s2[i] - s0[i], i=1..n
Vom determina apoi câte perechi de triplete { d01[i], d12[i], d20[i] } egale sunt în acest ³ir de
lungime n+1 (i=0..n). Dac dou triplete { d01[i],d12[i], d20[i] } ³i { d01[k],d12[k], d20[k] } (i <
j) sunt identice, atunci secvenµa t[i+1], t[i+2],â¦t[j] este o secvenµ omogen .
Pentru a aa num rul perechilor de triplete egale, se poate sorta ³irul tripletelor. în ³irul
sortat, tripletele identice sunt al turate. Dac identic m X triplete identice, atunci num rul
perechilor de triplete identice este X(X-1)/2 (oricare dou ).
Deci complexitatea determin rii num rului de secvenµe omogene din vectorul t este dat se
sortarea tripletelor, deci O n log n.
CAPITOLUL 22. ONI 2016 404
Revenind la problema bidimensional : Din restricµii, L & C ³i L C &65 536. De unde rezult
c
L & sqrt 65536 256.
Deci num rul de linii din matrice nu poate mai mare de 256.
Construim dou matrice de sume parµiale:
z[i][j] = num rul de valori de 0 aate pe coloana j, începând de la poziµia (i,j) în sus.
u[i][j] = num rul de valori de 1 aate pe coloana j, începând de la poziµia (i,j) în sus.
Pentru orice dou linii k ³i p (unde k<=p), dorim s a m câte submatrice omogene de în lµime
H=p-k+1 exist între cele dou linii. Vom construi deci vectorul t0[j] = z[p][j]-z[k-1][j], j=1..C,
deci în care t[j] memoreaz num rul valorilor de 0 aate pe coloana j între liniile k ³i p. Similar,
se construie³te t1[j]=u[p][j]-u[k-1][j], j=1..C, deci în care t1[j] memoreaz num rul valorilor de 1
aate pe coloana j între liniile k ³i p. Atunci t2[j]=H-t0[j]-t1[j], pentru j=1..C.
Apoi problema se rezolv ca în cazul unidimensional.
Complexitatea va deci O L L C logC
9 struct nod
10 {
11 int d01,d12,d20;
12 };
13
14 inline bool test(const nod &t1,const nod &t2)
15 {
16 return t1.d01<t2.d01 ||
17 (t1.d01==t2.d01 && t1.d12<t2.d12) ||
18 (t1.d01==t2.d01 && t1.d12==t2.d12 && t1.d20<t2.d20);
19 }
20
21 nod v[10001];
22 int a[318][10001];
23 int z[318][10001],u[318][10001];
24 int t0,t1,t2,st0,st1,st2;
25 long long sol;
26 int n,m;
27
28 void citire()
29 {
30 f>>n>>m;
31 for(int i=1;i<=n;++i)
32 for(int j=1;j<=m;++j)
33 f>>a[i][j];
34 f.close();
35 }
36
37 void prelucrare()
38 {
39 for(int i=1;i<=n;++i)
40 for(int j=1;j<=m;++j)
41 {
42 z[i][j]=z[i-1][j]+(a[i][j]==0);
43 u[i][j]=u[i-1][j]+(a[i][j]==1);
44 }
45
46 for(int k=1;k<=n;++k)
47 for(int p=k;p<=n;++p)
48 {
49 int d=p-k+1;
50 st0=st1=st2=0;
51 v[0].d01=v[0].d12=v[0].d20=0;
52 for(int j=1;j<=m;++j)
53 {
54 t0=z[p][j]-z[k-1][j];st0+=t0;
55 t1=u[p][j]-u[k-1][j];st1+=t1;
56 t2=d-t0-t1;st2+=t2;
57 v[j].d01=st0-st1;
58 v[j].d12=st1-st2;
59 v[j].d20=st2-st0;
60 }
61
62 sort(v,v+m+1,test);
63
64 int x=1;
65 for(int i=1;i<=m;++i)
66 if(v[i-1].d01==v[i].d01 &&
67 v[i-1].d12==v[i].d12 &&
68 v[i-1].d20==v[i].d20)
69 x++;
70 else
71 {
72 sol=sol+1ll*x*(x-1)/2;
73 x=1;
74 }
75
76 sol=sol+1ll*x*(x-1)/2;
77 }
78 }
79
80 int main()
81 {
82 citire();
83 prelucrare();
84 g<<sol<<’\n’;
CAPITOLUL 22. ONI 2016 408
85 return 0;
86 }
Capitolul 23
ONI 2015
23.1 cub
Problema 1 - cub 100 de puncte
S rb torile de iarn tocmai s-au încheiat. Florinel dore³te s -³i ajute
p rinµii la despodobirea bradului. Tubul luminos pe care l-au folosit
3
anul acesta este mai special. Are N becuri luminoase numerotate de
3
la 1 la N , iar ecare bec care este inscripµionat cu un num r prim, va
r mâne mereu aprins.
Cutia în care trebuie strâns tubul este un cub de latur N . Becul cu
num rul 1, trebuie pus în colµul de coordonate (1,1,1), restul în spiral
pân la umplerea nivelului, apoi nivelul urm tor în sens invers, ³.a.m.d.
Cerinµe
Cunoscând latura N a cubului, s se umple cubul cu tubul luminos
(becurile ind legate cresc tor), apoi s se determine:
1. Coordonatele x, y, z ale becului cu num rul V . (x-linia, y -coloana, z -în lµimea)
2. Num rul de becuri luminoase situate pe ecare faµ a cubului.
Date de intrare
Fi³ierul de intrare cub.in conµine pe prima linie un num r natural p. Pentru toate testele de
intrare, num rul p poate avea doar valoarea 1 sau valoarea 2.
Pe a doua linie a ³ierului de intrare, sunt scrise dou numere naturale N ³i V separate printr-
un spaµiu reprezentând dimensiunea cubului ³i valoarea becului pentru care trebuie determinate
coordonatele.
Date de ie³ire
a Dac valoarea lui p este 1, se va rezolva numai cerinµa 1. În acest caz, în ³ierul de ie³ire
cub.out se vor scrie trei numere naturale x y z , separate prin câte un spaµiu, reprezentând
coordonatele becului cu valoarea V .
409
CAPITOLUL 23. ONI 2015 410
a Dac valoarea lui p este 2, se va rezolva numai cerinµa 2. În acest caz, ³ierul de ie³ire
cub.out va conµine 4 linii. Pe ecare linie i, se va scrie câte un num r natural , reprezentând
num rul de becuri inscripµionate cu numere prime de pe faµa i.
Restricµii ³i preciz ri
a 1 & N & 200
1&V &N
3
a
a Pentru rezolvarea corect a primei cerinµe se acord 20 de puncte, iar pentru cerinµa a doua
se acord 80 de puncte.
a Pentru 20% dintre teste: 1 & N & 20
a Pentru 30% dintre teste: 21 & N & 100
a Pentru 50% dintre teste: 101 & N & 200
Exemple:
cub.in cub.out Explicaµii
1 3 10 222 Atenµie! Pentru acest test se rezolv doar cerinµa 1).
linia 2, coloana 2, nivel 2 - este becul 10
2 3 10 4343 Atenµie! Pentru acest test se rezolv doar cerinµa 2).
4 - becuri inscripµionate cu numere prime pe faµa 1: 2, 3, 17, 19
3 - becuri inscripµionate cu numere prime pe faµa 2: 3, 5, 23
4 - becuri inscripµionate cu numere prime pe faµa 3: 5, 7, 13, 23
3 - becuri inscripµionate cu numere prime pe faµa 4: 7, 11, 19
Timp maxim de executare/test: 0.5 secunde
Memorie: total 8 MB
Dimensiune maxim a sursei: 10 KB
Dac N este un num r par, se vor folosi la ecare plecare 4 direcµii matricea ind completat
astfel.
Dac N este impar elementul din centru va completat ultimul.
Ultimul element completat pe nivelul 1, decide poziµia de plecare în umplerea nivelului urm tor,
parcurgând circular spre exterior în sens trigonometric matricea de la nivelul 2.
Matricea de pe nivelul 2 se poate obµine din valorile matricii de la nivelul 1 astfel:
B ij 2 n n 1 Aij .
unde A este matricea asociat primului nivel, iar B este matricea asociat nivelului 2.
Se observ c matricile de nivel mai mare decât 2, se pot obµine din matricile de la nivelele
anterioare astfel:
a Valoarea unui element de pe nivelul 3 se obµine adunând la valoarea de pe nivelul 1 cu
acelea³i coordonate valoarea 2*N*N.
a Valoarea unui element de pe nivelul 4 se obµine adunând la valoarea de pe nivelul 2 cu
acelea³i coordonate valoarea 2*N*N.
a Valoarea unui element de pe nivelul 5 se obµine adunând la valoarea de pe nivelul 3 cu
acelea³i coordonate valoarea 2*N*N. ³.a.m.d.
Pentru rezolvarea cerinµei 1 (20 pct.): ajunge s sc dem în mod repetat din valoarea V num rul
2*N*N, µinând minte c trecem peste 2 nivele la ecare sc dere. Coordonatele X ³i Y le vom obµine
c utând valoarea r mas în matricile A sau B, iar coordonata Z, se obµine din num rul total de
sc deri*2 + valoarea 1 sau 2, în funcµie de nivelul matricii la care ajungem.
Pentru rezolvarea cerinµei 2 (80 pct.): ajunge s test m elementele de pe chenarul matricilor
A ³i B:
CAPITOLUL 23. ONI 2015 411
55 for (j=p;j<=n-p+1;j++)
56 {
57 v++;
58 if (v==k)
59 {
60 g<<p<<" "<<j<<" "<<z<<"\n";
61 g.close();
62 return 0;
63 }
64 }
65 for (i=p+1;i<=n-p+1;i++)
66 {
67 v++;
68 if (v==k)
69 {
70 g<<i<<" "<<n-p+1<<" "<<z<<"\n";
71 g.close();
72 return 0;
73 }
74 }
75 for (j=n-p;j>=p;j--)
76 {
77 v++;
78 if (v==k)
79 {
80 g<<n-p+1<<" "<<j<<" "<<z<<"\n";
81 g.close();
82 return 0;
83 }
84 }
85 for (i=n-p;i>=p+1;i--)
86 {
87 v++;
88 if (v==k)
89 {
90 g<<i<<" "<<p<<" "<<z<<"\n";
91 g.close();
92 return 0;
93 }
94 }
95 }
96 }
97 else
98 {
99 v=v+n2+1;
100 for (p=1;;p++)
101 {
102 for (j=p;j<=n-p+1;j++)
103 {
104 v--;
105 if (v==k)
106 {
107 g<<p<<" "<<j<<" "<<z<<"\n";
108 g.close();
109 return 0;
110 }
111 }
112 for (i=p+1;i<=n-p+1;i++)
113 {
114 v--;
115 if (v==k)
116 {
117 g<<i<<" "<<n-p+1<<" "<<z<<"\n";
118 g.close();
119 return 0;
120 }
121 }
122 for (j=n-p;j>=p;j--)
123 {
124 v--;
125 if (v==k)
126 {
127 g<<n-p+1<<" "<<j<<" "<<z<<"\n";
128 g.close();
129 return 0;
130 }
CAPITOLUL 23. ONI 2015 413
131 }
132 for (i=n-p;i>=p+1;i--)
133 {
134 v--;
135 if (v==k)
136 {
137 g<<i<<" "<<p<<" "<<z<<"\n";
138 g.close();
139 return 0;
140 }
141 }
142 }
143
144 }
145 }
146 else
147 {
148 for (z=1;z<=n;z++)
149 if (z%2==1)
150 {
151 p=1; v=(z-1)*n2;
152
153 // coltul st-sus
154 v++;
155 if (pr[v]) { f1++; f4++; }
156
157 for (j=p+1; j<=n-p; j++)
158 {
159 v++;
160 if (pr[v]) f1++;
161 }
162
163 // coltul dreapta sus
164 v++;
165 if (pr[v]) { f1++; f2++; }
166
167 for (i=p+1; i<=n-p; i++)
168 {
169 v++;
170 if (pr[v]) f2++;
171 }
172
173 // coltul dreapta jos
174 v++;
175 if (pr[v]) { f2++; f3++; }
176
177 for (j=n-p; j>=p+1; j--)
178 {
179 v++;
180 if (pr[v]) f3++;
181 }
182
183 // coltul stanga-jos
184 v++;
185 if (pr[v]) { f3++; f4++; }
186
187 for (i=n-p; i>=p+1; i--)
188 {
189 v++;
190 if (pr[v]) f4++;
191 }
192
193 v=v+n2-(4*n-4);
194 }
195 else
196 {
197 p=1;
198 v=v+n2-(4*n-4);
199 for (i=p+1; i<=n-p; i++)
200 {
201 v++;
202 if (pr[v]) f4++;
203 }
204
205 // coltul stanga jos
206 v++;
CAPITOLUL 23. ONI 2015 414
34 int v,n,n2,k,x,y,z,p,i,j,f1=0,f2=0,f3=0,f4=0;
35 m=2;
36 pr[1]=2;
37 pr[2]=3;
38 f>>v;
39 f>>n>>k;
40 n2=n*n;
41 if (v==1)
42 {
43 z=1;
44 v=0;
45 while (k-v>n2)
46 {
47 z++;
48 v=v+n2;
49 }
50 if (z%2==1)
51 {
52 for (p=1;;p++)
53 {
54 for (j=p;j<=n-p+1;j++)
55 {
56 v++;
57 if (v==k)
58 {
59 g<<p<<" "<<j<<" "<<z<<"\n";
60 g.close();
61 return 0;
62 }
63 }
64 for (i=p+1;i<=n-p+1;i++)
65 {
66 v++;
67 if (v==k)
68 {
69 g<<i<<" "<<n-p+1<<" "<<z<<"\n";
70 g.close();
71 return 0;
72 }
73 }
74 for (j=n-p;j>=p;j--)
75 {
76 v++;
77 if (v==k)
78 {
79 g<<n-p+1<<" "<<j<<" "<<z<<"\n";
80 g.close();
81 return 0;
82 }
83 }
84 for (i=n-p;i>=p+1;i--)
85 {
86 v++;
87 if (v==k)
88 {
89 g<<i<<" "<<p<<" "<<z<<"\n";
90 g.close();
91 return 0;
92 }
93 }
94 }
95 }
96 else
97 {
98 v=v+n2+1;
99 for (p=1;;p++)
100 {
101 for (j=p;j<=n-p+1;j++)
102 {
103 v--;
104 if (v==k)
105 {
106 g<<p<<" "<<j<<" "<<z<<"\n";
107 g.close();
108 return 0;
109 }
CAPITOLUL 23. ONI 2015 416
110 }
111 for (i=p+1;i<=n-p+1;i++)
112 {
113 v--;
114 if (v==k)
115 {
116 g<<i<<" "<<n-p+1<<" "<<z<<"\n";
117 g.close();
118 return 0;
119 }
120 }
121 for (j=n-p;j>=p;j--)
122 {
123 v--;
124 if (v==k)
125 {
126 g<<n-p+1<<" "<<j<<" "<<z<<"\n";
127 g.close();
128 return 0;
129 }
130 }
131 for (i=n-p;i>=p+1;i--)
132 {
133 v--;
134 if (v==k)
135 {
136 g<<i<<" "<<p<<" "<<z<<"\n";
137 g.close();
138 return 0;
139 }
140 }
141 }
142
143 }
144 }
145 else
146 {
147 for (z=1;z<=n;z++)
148 if (z%2==1)
149 {
150 p=1; v=(z-1)*n2;
151
152 // coltul st-sus
153 v++;
154 k=prim(v);
155 if (k) { f1++; f4++; }
156
157 for (j=p+1; j<=n-p; j++)
158 {
159 v++;
160 k=prim(v);
161 if (k) f1++;
162 }
163
164 // coltul dreapta sus
165 v++;
166 k=prim(v);
167 if (k) { f1++; f2++; }
168
169 for (i=p+1; i<=n-p; i++)
170 {
171 v++;
172 k=prim(v);
173 if (k) f2++;
174 }
175
176 // coltul dreapta jos
177 v++;
178 k=prim(v);
179 if (k) { f2++; f3++; }
180
181 for (j=n-p; j>=p+1; j--)
182 {
183 v++;
184 k=prim(v);
185 if (k) f3++;
CAPITOLUL 23. ONI 2015 417
186 }
187
188 // coltul stanga-jos
189 v++;
190 k=prim(v);
191 if (k) { f3++; f4++; }
192
193 for (i=n-p; i>=p+1; i--)
194 {
195 v++;
196 k=prim(v);
197 if (k) f4++;
198 }
199
200 for (i=1; i<=n2-(4*n-4); i++)
201 {
202 v++;
203 prim(v);
204 }
205 }
206 else
207 {
208 p=1;
209 for (i=1; i<=n2-(4*n-4); i++)
210 {
211 v++;
212 prim(v);
213 }
214
215
216 for (i=p+1; i<=n-p; i++)
217 {
218 v++;
219 k=prim(v);
220 if (k) f4++;
221 }
222
223 // coltul stanga jos
224 v++;
225 k=prim(v);
226 if (k) { f4++; f3++; }
227
228 for (j=p+1; j<=n-p; j++)
229 {
230 v++;
231 k=prim(v);
232 if (k) f3++;
233 }
234
235 // coltul dreapta jos
236 v++;
237 k=prim(v);
238 if (k) { f3++; f2++; }
239
240 for (i=n-p; i>=p+1; i--)
241 {
242 v++;
243 k=prim(v);
244 if (k) f2++;
245 }
246
247 // coltul dreapta sus
248 v++;
249 k=prim(v);
250 if (k) {f2++; f1++; }
251
252 for (j=n-p; j>=p+1; j--)
253 {
254 v++;
255 k=prim(v);
256 if (k) f1++;
257 }
258
259 // coltul stanga sus
260 v++;
261 k=prim(v);
CAPITOLUL 23. ONI 2015 418
65 ///nivel 2 - matrice B
66 sum=2*n*n+1;
67 for(i=1;i<=n;i++)
68 for(j=1;j<=n;j++)
69 b[i][j]=sum-a[i][j];
70 //afisare(b);
71 if (p==1)
72 {
73 ///cerinta 1
74 x=v;
75 int nivel=0;
76 while(x>2*n*n)
77 x=x-2*n*n, nivel+=2;
78 int stop=0;
79 for(i=1;i<=n && stop==0; i++)
80 for(j=1;j<=n && stop==0; j++)
81 {
82 if(a[i][j]==x)
83 {
84 fout<<i<<" "<<j<<" "<<nivel+1<<endl;
85 stop=1;
86 }
87 if(b[i][j]==x)
88 {
89 fout<<i<<" "<<j<<" "<<nivel+2<<endl;
90 stop=1;
91 }
92 }
93 }
94 else
95 {
96 ///cerinta 2
97 f1=f2=f3=f4=0;
98 ///fata 1 - linia 1 A,B,.... 200*200 elemente=40.000 nr de testat
99 for(j=1;j<=n;j++)
100 {
101 nr=a[1][j];
102 while(nr<n*n*n)
103 {
104 if (prim(nr)) f1++;
105 nr+=2*n*n;
106 }
107 nr=b[1][j];
108 while(nr<n*n*n)
109 {
110 if (prim(nr)) f1++;
111 nr+=2*n*n;
112 }
113 }
114 ///fata 2 - coloana n A,B,....
115 for(i=1;i<=n;i++)
116 {
117 nr=a[i][n];
118 while(nr<n*n*n)
119 {
120 if (prim(nr)) f2++;
121 nr+=2*n*n;
122 }
123 nr=b[i][n];
124 while(nr<n*n*n)
125 {
126 if (prim(nr)) f2++;
127 nr+=2*n*n;
128 }
129 }
130 ///fata 3 - linia n A,B,....
131 for(j=1;j<=n;j++)
132 {
133 nr=a[n][j];
134 while(nr<n*n*n)
135 {
136 if (prim(nr)) f3++;
137 nr+=2*n*n;
138 }
139 nr=b[n][j];
140 while(nr<n*n*n)
CAPITOLUL 23. ONI 2015 420
141 {
142 if (prim(nr)) f3++;
143 nr+=2*n*n;
144 }
145 }
146 ///fata 4 - coloana 1 A,B,....
147 for(i=1;i<=n;i++)
148 {
149 nr=a[i][1];
150 while(nr<n*n*n)
151 {
152 if (prim(nr)) f4++;
153 nr+=2*n*n;
154 }
155 nr=b[i][1];
156 while(nr<n*n*n)
157 {
158 if (prim(nr)) f4++;
159 nr+=2*n*n;
160 }
161 }
162 fout<<f1<<’\n’;
163 fout<<f2<<’\n’;
164 fout<<f3<<’\n’;
165 fout<<f4<<’\n’;
166 }
167
168 return 0;
169 }
120 ///fata 3
121 for(nivel=1;nivel<=n;nivel++)
122 for(j=1;j<=n;j++)
123 if(ciur[a[n][j][nivel]]==false)
124 {
125 // printf("%d ",a[n][j][nivel]);
126 f3++;
127 }
128 if (p==2) printf("%d\n",f3);
129 ///fata 4
130 for(nivel=1;nivel<=n;nivel++)
131 for(i=1;i<=n;i++)
132 if(ciur[a[i][1][nivel]]==false)
133 {
134 // printf("%d ",a[i][1][nivel]);
135 f4++;
136 }
137 if (p==2) printf("%d\n",f4);
138 return 0;
139 }
53 }
54
55 int a[202][202];
56 int dx[4]={0,1,0,-1}, dy[4]={1,0,-1,0};
57
58 int main()
59 {
60 ifstream fi("cub.in"); ofstream fo("cub.out");
61 int i,j,k,d,p,N,V;
62 fi>>p>>N>>V;
63
64 if (p==1)
65 {
66 for(i=0;i<=N+1;i++)
67 a[0][i]=a[N+1][i]=a[i][0]=a[i][N+1]=1;
68
69 i=j=1;
70 d=0;
71 for(k=1;k<=N*N;k++)
72 {
73 a[i][j]=k;
74 if(!a[i+dx[d]][j+dy[d]])
75 {
76 i+=dx[d];
77 j+=dy[d];
78 }
79 else
80 {
81 d=(d+1)%4;
82 i+=dx[d];
83 j+=dy[d];
84 }
85 }
86
87 k=V/(N*N);
88 V%=(N*N);
89 if (k&1)
90 V=N*N+1-V;
91
92 for (i=1;i<=N;i++)
93 for (j=1;j<=N;j++)
94 if (a[i][j]==V)
95 {
96 fo<<i<<" "<<j<<" "<<k+1<<"\n";
97 break;
98 }
99 }
100 else
101 {
102 int f[5],t;
103 f[1]=f[2]=f[3]=f[4]=0;
104 for (i=1;i<=N;i++)
105 for (j=1;j<=N;j++)
106 for (t=0;t<4;t++)
107 {
108 if (i&1)
109 k=j+(i-1)*N*N+t*(N-1);
110 else
111 k=i*N*N-j+1-t*(N-1);
112
113 if (t==3 && j==N)
114 k=(i&1)*(1+(i-1)*N*N);
115
116 f[t+1]+=prim(k);
117 }
118 for (t=1;t<=4;t++)
119 fo<<f[t]<<"\n";
120 }
121
122 return 0;
123 }
CAPITOLUL 23. ONI 2015 424
23.2 risc
Problema 2 - risc 100 de puncte
Pentru a participa la un concert, n persoane s-au a³ezat la coad pe un singur rând în a³-
teptarea deschiderii casei de bilete. În lµimile celor n persoane sunt toate distincte. Pe baza
acestei informaµii cruciale, agenµii de securitate au decis ca din motive de ... securitate, ordinea
persoanelor care a³teapt la coad trebuie schimbat în funcµie de în lµimile lor.
Astfel, agentii de paz vor alege, pe rând, câte o persoan ³i o vor trimite la sfâr³itul rândului.
Dup ecare operaµie de tipul acesta, s -i spunem de mutare, rândul se restrânge, ocupându-
se poziµia r mas liber . Strategia agenµilor de paz este aceasta: la terminarea tuturor operaµiilor
de mutare, riscul minim de securitate se obµine dac toate persoanele aate în dreapta persoanei
celei mai înalte vor mai înalte decât cele aate în stânga persoanei cele mai înalte. În plus, înal-
µimile persoanelor vor cresc toare pân la poziµia k a persoanei celei mai înalte ³i descresc toare
dup poziµia k .
Mai exact: dac h1 , h2 , ..., hn sunt în lµimile persoanelor dup nalizarea operaµiilor de
mutare, atunci: exist o poziµie k , cu 1 & k & n astfel încât
h1 $ h2 $ ...hk 1 $ hk % hk 1 % ... % hn 1 % hn
Cerinµe
Cunoscând num rul de persoane n ³i în lµimile h1 , h2 , ..., hn ale acestora s se scrie un program
care determin :
1. Poziµia persoanei celei mai înalte în rândul iniµial, în cazul în care nu sunt necesare operaµii
de mutare.
2. Num rul minim de mut ri necesare pentru ca rândul de persoane s prezinte un risc minim
de securitate.
Date de intrare
Pe prima linie a ³ierului de intrare risc.in se g se³te num rul natural p a c rui valoare poate
doar 1 sau 2.
Pe a doua linie a ³ierului de intrare se a num rul natural n cu semnicaµia din enunµ.
Pe a treia linie se g sesc n numere naturale, distincte: h1 , h2 , ..., hn , separate prin câte un
singur spaµiu, reprezentând în lµimile persoanelor.
Date de ie³ire
Fi³ierul de ie³ire este risc.out.
a Dac valoarea lui p este 1 atunci se va rezolva numai cerinµa 1. în acest caz, ³ierul de ie³ire
va conµine pe prima linie un num r natural poz ce reprezint poziµia persoanei celei mai înalte în
rândul iniµial. Dac rândul iniµial nu respect condiµiile de risc minim de securitate, atunci poz
este -1.
a Dac valoarea lui p este 2 se va rezolva numai cerinµa 2. în acest caz ³ierul de ie³ire va
conµine pe prima linie un num r natural m, reprezentând num rul minim de mut ri necesare
pentru a obµine risc minim de securitate.
Restricµii ³i preciz ri
a 1 & n & 100 000
a 1 & h1 , h2 , ...hn & 100 000
a Persoana cea mai înalt într-o conguraµie cu risc minim de securitate poate plasat pe
oricare dintre poziµiile 1...n
a Pentru 50% din teste, n & 2 000, iar pentru alte 40% din teste, n & 10 000
a Pentru rezolvarea corect a primei cerinµe se acord 20 de puncte, iar pentru cerinµa a doua
se acord 80 de puncte.
Exemple:
CAPITOLUL 23. ONI 2015 425
Cerinµa 1. 20 puncte
Se determin înalµimea hmax ³i poziµia pmax a celei mai înalte persoane.
Pentru ecare poziµie 2 & i & pmax se veric dac h[i] > h[i -1] ³i similar, pentru ecare
poziµie i % pmax se veric dac pentru persoana i aat în dreapta acesteia se veric dac
hi $ hi 1. Pentru a determina dac toate persoanele aate în dreapta poziµiei pmax sunt
mai înalte decât cele aate în stânga se veric condiµia hpmax 1 $ hn.
Cerinµa 2. Total - 80 de puncte
Soluµia 1 - Complexitate O n n, prof. Carmen Popescu, C. N. Gheorge Laz r Sibiu
Se marcheaz valorile care trebuie mutate folosind un vector boolean. Simultan cu aceste
mut ri vom calcula ³i urm toarele valori:
mx = maximul valorilor ce se mut la sfâr³it
mn = minimul valorilor ce vor în dreapta maximului dup mut ri
Pentru ecare în lµime hi, i $ k c ut m toate valorile din faµa sa care sunt mai mari, adic
hj % hi cu j $ i (este înc lcat prima condiµie de mai sus), acestea vor mutate.
Vom muta apoi la sfâr³it toate valorile aate în dreapta maximului care nu respect cerinµa
a doua de mai sus, deci pentru ecare în lµime hi cu i % k 1 vom muta la sfâr³it valorile din
faµa sa, care sunt mai mici decât hi, adic mut m valorile hj cu j % k ³i j $ i pentru care
hj $ hi.
Mut m apoi valorile care au r mas în stânga maximului ³i care sunt mai mari decât minimul
valorilor din dreapta (condiµia a treia de mai sus), deci mai mari decât mn.
Acum toate valorile sunt în jum tatea potrivit , îns s-ar putea ca elementele care se aau
iniµial în dreapta maximului ³i nu au fost mutate s e mai mici decât maximul valorilor mutate la
sfâr³it (încalc condiµia a doua de mai sus) si s trebuiasc s le mut m la sfâr³it. Vom muta
a³adar la sfâr³it valorile hi $ mx cu i % k .
O alt posibilitate de a aranja ³irul dat este s mut m maximul la sfâr³itul ³irului ³i apoi s
relu m mut rile ca mai sus. Se va alege cea mai favorabil din cele dou variante.
Aceast soluµie obµine 30 de puncte din 80 posibile.
CAPITOLUL 23. ONI 2015 426
Cu ro³u s-au reprezentat cele mai mici numere din ³ir aate în ordine cresc toare în parcurgerea
³irului de la stânga la dreapta. Num rul acestora este Asci 3 (pentru i ' 5). Cu albastru sunt
gurate cele mai mari numere din ³ir aate în ordine descresc toare în parcurgerea ³irului de la
stânga la dreapta. Num rul lor este Desc 2, iar cap tul din stânga al acestui sub³ir începe la
poziµia pmax 7.
Numerele marcate cu negru trebuie s e mutate. Ordinea mut rii poate aleas astfel încât
s respecte cerinµa de risc minim.
pmax 7, Asc7 Desc 3 2 % Ascn 3.
Prin urmare, M n Ascpmax Desc 10 5 5
O alt situaµie este exemplicat mai jos:
CAPITOLUL 23. ONI 2015 427
8 #include <algorithm>
9
10 using namespace std;
11 using VI = vector<int>;
12
13 VI a, b, c; // sirul sirul inaltimilor, sirul sortat, sir auxiliar
14 int n, V;
15
16 int main()
17 {
18 ifstream fin("risc.in");
19 ofstream fout("risc.out");
20
21 int hmax(0), pmax(-1);
22 fin >> V >> n;
23 a = VI(n);
24 for (int i = 0; i < n; ++i)
25 {
26 fin >> a[i];
27 if ( a[i] > hmax )
28 hmax = a[i], pmax = i;
29 }
30
31 if ( V == 1 )
32 {
33 bool ok = true;
34 for (int i = 0; i < n && ok; ++i)
35 {
36 if ( i && i <= pmax && a[i - 1] > a[i] )
37 ok = false;
38
39 if ( i > pmax && a[i - 1] < a[i] )
40 ok = false;
41 }
42
43 if ( ok && pmax && a[pmax - 1] > a[n - 1])
44 ok = false;
45 if ( ok )
46 fout << pmax + 1 << ’\n’;
47 else
48 fout << -1 << ’\n’;
49 }
50 else
51 {
52 b = VI(n); c = VI(hmax + 1);
53 for (int i = 0; i < n; i++)
54 c[a[i]]++; // c[i] - numarul elem egale cu i (frecventele)
55
56 for (int i = 1; i <= hmax; i++) // O(n)
57 c[i] += c[i-1]; // c[i] - numarul elem mai mici sau egale cu i
58
59 for (int i = 0; i < n; i++)
60 b[c[a[i]] - 1] = a[i];
61
62 int cntAsc(0), cntDesc(0), k(0);
63 for (int i(0), j(0); i < n; ++i) // partea crescatoare
64 {
65 if (a[i] == b[j] )
66 cntAsc++, j++;
67
68 if ( i == pmax )
69 k = cntAsc;
70 }
71
72 for (int i(pmax), j(n - 1); i < n; ++i) // partea descrescatoare
73 if (a[i] == b[j] )
74 cntDesc++, j--;
75
76 fout << n - max(cntAsc, cntDesc + k) << ’\n’;
77 }
78
79 fin.close();
80 fout.close();
81 return 0;
82 }
CAPITOLUL 23. ONI 2015 429
75 b[j]=true;
76 k++;
77 if (a[j]>mx) mx=a[j];
78 if (a[j]<mn) mn=a[j];
79 }
80
81 // marcam valorile din dreapta care nu respecta ordinea si
82 // vor fi mutate la sfarsit
83 for (i=p+2;i<=n;i++)
84 {
85 if (a[i]<mn)
86 mn=a[i];
87 for (j=i-1;j>p;j--)
88 if (a[j]<a[i] && !b[j])
89 {
90 b[j]=true;
91 k++;
92 if (a[j]>mx) mx=a[j];
93 }
94 }
95
96 // marcam valorile care au ramas in stanga (nemutate) care sunt
97 // mai mari decat minimul din dreapta si care vor
98 // fi mutate la sfarsit
99 for (i=1;i<p;i++)
100 if (!b[i] && a[i]>mn)
101 {
102 b[i]=true;
103 k++;
104 if (a[i]>mx) mx=a[i];
105 }
106
107 // verificam valorile din dreapta care au ramas nemutate si care
108 // sunt mai mici decat maximul celor mutate, ele trebuie mutate
109 // la sfarsit
110 for (i=n;i>p;i--)
111 if (!b[i] && a[i]<mx)
112 k++;
113
114 // CAZUL 2:
115 // mutam maximul la sfarsit pe urma mutam ce nu respecta ordinea
116 // mn = minimul valorilor ce se vor afla in dreapta
117 mn=a[p];
118 int k1=1; // am mutat maximul la sfarsit
119 for (i=2;i<=n;i++)
120 if (i!=p)
121 for (j=i-1;j>=1;j--)
122 if (j!=p && a[j]>a[i] && !c[j])
123 {
124 c[j]=true;
125 k1++;
126 if (a[j]<mn) mn=a[j];
127 }
128 // cautam valorile ramase nemutate si care sunt mai mari decat
129 // minimul celor mutate si ele vor fi mutate
130 for (i=1;i<=n;i++)
131 if (i!=p && !c[i] && a[i]>mn)
132 k1++;
133
134 // solutia e cea din cazul cel mai favorabil
135 if (k<k1)
136 g<<k<<"\n";
137 else
138 g<<k1<<"\n";
139 }
140
141 return 0;
142 }
5 #include <fstream>
6 #include <vector>
7 #include <algorithm>
8
9 using namespace std;
10 using VI = vector<int>;
11
12 VI a, b; // sirul inaltimilor, sirul sortat
13 int n, V;
14
15 int main()
16 {
17 ifstream fin("risc.in");
18 ofstream fout("risc.out");
19
20 int hmax(0), pmax(-1);
21 fin >> V >> n;
22 a = VI(n);
23 for (int i = 0; i < n; ++i)
24 {
25 fin >> a[i];
26 if ( a[i] > hmax )
27 hmax = a[i], pmax = i;
28 }
29
30 if ( V == 1 )
31 {
32 bool ok = true;
33 for (int i = 0; i < n && ok; ++i)
34 {
35 if ( i && i <= pmax && a[i - 1] > a[i] )
36 ok = false;
37
38 if ( i > pmax && a[i - 1] < a[i] )
39 ok = false;
40 }
41
42 if ( ok && pmax && a[pmax - 1] > a[n - 1])
43 ok = false;
44 if ( ok )
45 fout << pmax + 1 << ’\n’;
46 else
47 fout << -1 << ’\n’;
48 }
49 else
50 {
51 b = a;
52 sort(b.begin(), b.end());
53 int cntAsc(0), cntDesc(0), k(0);
54
55 for (int i(0), j(0); i < n; ++i) // partea crescatoare
56 {
57 if (a[i] == b[j] )
58 cntAsc++, j++;
59
60 if ( i == pmax )
61 k = cntAsc;
62 }
63
64 for (int i(pmax), j(n - 1); i < n; ++i) // partea descrescatoare
65 if (a[i] == b[j] )
66 cntDesc++, j--;
67
68 fout << n - max(cntAsc, cntDesc + k) << ’\n’;
69 }
70
71 fin.close();
72 fout.close();
73 return 0;
74 }
23.3 roboti
Problema 3 - roboti 100 de puncte
CAPITOLUL 23. ONI 2015 432
Cerinµe
Cunoscând dimensiunile N , M ale terenului ³i coordonatele parcelelor în care sunt plantaµi
copaci se cere:
1. Num rul minim de roboµi necesari defri³ rii întregului teren.
2. S se r spund la Q interog ri de forma k , unde k este un num r natural. Pentru ecare
interogare de aceast form va trebui determinat latura minim a unui robot astfel încât s e
necesari pentru defri³are cel mult k roboµi.
Date de intrare
Fi³ierul de intrare roboti.in conµine:
a Pe prima linie un num r natural p reprezentând varianta cerinµei de rezolvare. Pentru toate
testele de intrare, num rul p poate avea doar valoarea 1 sau valoarea 2.
a Pe a doua linie se a 3 numere naturale N , M , T separate prin câte un spaµiu reprezen-
tând num rul liniilor, num rul coloanelor terenului dreptunghiular, respectiv num rul copacilor
plantaµi.
a Urm toarele T linii conµin ecare câte dou numere naturale x, y separate prin câte un
spaµiu, reprezentând linia, respectiv coloana parcelei în care este plantat un copac.
a În cazul cerinµei 1, ultima linie conµine un singur num r natural L, reprezentând latura unui
robot.
a În cazul cerinµei 2, penultima linie va conµine un num r natural Q, iar ultima linie Q numere
naturale k1 , k2 , ..., kQ separate prin câte un spaµiu, reprezentând num rul maxim de roboµi ce pot
utilizaµi în ecare dintre cele Q interog ri.
Date de ie³ire
a Dac valoarea lui p este 1, se va rezolva numai cerinµa 1. În acest caz, în ³ierul de ie³ire
roboti.out se va scrie un singur num r natural n1 , reprezentând num rul minim de roboµi utilizaµi.
a Dac valoarea lui p este 2, se va rezolva numai cerinµa 2. În acest caz, în ³ierul de ie³ire
roboti.out se vor scrie Q linii. Fiecare linie i va conµine câte un num r natural ni , reprezentând
latura minim a unui robot astfel încât pentru defri³are s e utilizaµi cel mult ki roboµi.
Restricµii ³i preciz ri
a 2 & N, M, L & 150
a 1 & Q & 150
a 1 & ki & 150, 1 & i & Q
a 1 & T & 1000
a Latura robotului nu poate mai mare decât dimensiunile terenului
a Pe tot parcursul deplas rii, ecare robot se va aa în interiorul suprafeµei terenului.
a în orice moment în interiorul suprafeµei terenului se va aa cel mult un robot.
Exemple:
2 688415 41 p 2
3 352655 Prima valoare din ³ierul de ie³ire reprezint latura minim pe
4 738682 care o pot avea roboµii astfel încât pentru defri³area întregului
1 3 teren s e necesar un singur robot, conform primei interog ri.
A doua valoare din ³ierul de ie³ire reprezint latura minim pe
care o pot avea roboµii astfel încât pentru defri³area întregului
teren s e necesari cel mult trei roboµi, conform celei de-a doua
interog ri.
Atenµie! Pentru acest test se rezolv doar cerinµa 2.
Cerinµa 2. 50 de puncte
Se caut binar latura minim a roboµilor care trebuie folosiµi pentru a nu dep ³i num rul admis
de roboµi utilizaµi. Num rul de roboµi folosiµi se face la fel ca la cerinµa 1. Pentru un algoritm de
tip greedy, complexitatea soluµiei la cerinµa 2 este O Q n T log T
CAPITOLUL 23. ONI 2015 434
66 {
67 Lmin = L;
68 hi = L - 1;
69 }
70 else
71 lo = L + 1;
72 }
73 }
74 }
75
76 fin.close();
77 fout.close();
78 }
79
80 int CountRobots(int L) // O(T * log(n)^2)
81 {
82 int cnt(0), cntUp(0);
83
84 for (const auto& c : cl)
85 {
86 cntUp = 1;
87 if (c.i > L && c.j <= m - L)
88 cntUp += Query(c.i - L, m - c.j - L + 1);
89
90 Update(c.i, m - c.j + 1, cntUp);
91 cnt = max(cnt, cntUp);
92 }
93
94 for (const auto& c : cl)
95 Reset(c.i, m - c.j + 1);
96
97 return cnt;
98 }
99
100 void Reset(int ic, int jc)
101 {
102 for (int i = ic; i <= n; i += i & -i)
103 for (int j = jc; j <= m; j += j & -j)
104 mx[i][j] = 0;
105 }
106
107 void Update(int ic, int jc, int val)
108 {
109 for (int i = ic; i <= n; i += i & -i)
110 for (int j = jc; j <= m; j += j & -j)
111 mx[i][j] = max(mx[i][j], val);
112 }
113
114 int Query(int ic, int jc)
115 {
116 int cnt(0);
117 for (int i = ic; i >= 1; i -= i & -i)
118 for (int j = jc; j >= 1; j -= j & -j)
119 cnt = max(cnt, mx[i][j]);
120 return cnt;
121 }
17
18 int CountRobots(int L);
19
20 ifstream fin("roboti.in");
21 ofstream fout("roboti.out");
22
23 int main()
24 {
25 int x, y, p, T, L;
26
27 fin >> p >> n >> m >> T;
28
29 for (int i = 1; i <= T; ++i)
30 {
31 fin >> x >> y;
32 b[x][y] = 1;
33 }
34
35 if ( p == 1 )
36 {
37 fin >> L;
38 fout << CountRobots(L) << ’\n’;
39 }
40 else
41 {
42 int Q, k, lo, hi, Lmin;
43
44 for (fin >> Q; Q--; fout << Lmin << ’\n’)
45 {
46 fin >> k;
47 lo = 1, hi = n / k + 1;
48 while (lo <= hi)
49 {
50 L = (lo + hi) / 2;
51
52 if (CountRobots(L) <= k)
53 {
54 Lmin = L;
55 hi = L - 1;
56 }
57 else
58 lo = L + 1;
59 }
60 }
61 }
62
63 fin.close();
64 fout.close();
65 }
66
67 int CountRobots(int L)
68 {
69 int cnt = 0;
70 a = vector<VI>(n + 1, VI(m + 2));
71
72 for (int i = 1; i <= n; ++i)
73 for (int j = m; j >= 1; --j)
74 {
75 if ( b[i][j] )
76 {
77 if ( i > L && j <= m - L )
78 a[i][j] = 1 + a[i - L][j + L];
79 else
80 a[i][j] = 1;
81 }
82 else
83 a[i][j] = max(a[i][j + 1], a[i - 1][j]);
84
85 cnt = max(cnt, a[i][j]);
86 }
87
88 return cnt;
89 }
1 /*
2 prof. Constantin Galatan
3 O(Q * T * log n)
4 */
5 #include <iostream>
6 #include <fstream>
7 #include <algorithm>
8 #include <deque>
9
10 using namespace std;
11 using PII = pair<int, int>;
12
13 #define I q1.front().first
14 #define J q1.front().second
15
16 deque<PII> q, q1, q2, q3;
17 int n, m;
18
19 int CountRobots(int L);
20
21 int main()
22 {
23 ifstream fin("roboti.in");
24 ofstream fout("roboti.out");
25
26 int x, y, p, T, L;
27
28 fin >> p >> n >> m >> T;
29 for (int i = 1; i <= T; ++i)
30 {
31 fin >> x >> y;
32 q.push_back({x, y});
33 }
34
35 sort(q.begin(), q.end());
36
37 if ( p == 1 )
38 {
39 fin >> L;
40 fout << CountRobots(L) << ’\n’;
41 }
42 else
43 {
44 int Q, k, lo, hi, Lmin;
45
46 for (fin >> Q; Q--; fout << Lmin << ’\n’)
47 {
48 fin >> k;
49 lo = 1, hi = n / k + 1;
50 while (lo <= hi)
51 {
52 L = (lo + hi) / 2;
53
54 if ( CountRobots(L) <= k)
55 {
56 Lmin = L;
57 hi = L - 1;
58 }
59 else
60 lo = L + 1;
61 }
62 }
63 }
64
65 fin.close();
66 fout.close();
67 }
68
69 int CountRobots(int L)
70 {
71 int lastJ, lastI, i1, i2, j1, cnt = 0;
72 bool first(true);
73 for (q1 = q; !q1.empty(); q1.swap(q2))
74 {
75 cnt++;
CAPITOLUL 23. ONI 2015 438
152 }
153
154 return cnt;
155 }
23.4 casa
Problema 4 - casa 100 de puncte
În aceast poveste este vorba despre o cas cu mai multe camere. O camer are forma unui
p trat de latur 1. Dac dou camere au un perete comun, atunci se poate trece dintr-o camer
în alta. Casa nu are neap rat form dreptunghiular .
O asemenea cas poate descris în povestea noastr în dou moduri:
- prin matricea minimal : o matrice cu elemente 0 ³i 1 în care exist N valori egale cu 1, ce
corespund camerelor, iar prima linie, ultima linie, prima coloan ³i ultima coloan au cel puµin un
element egal cu 1.
- prin construcµie: un ³ir de N 1 perechi ai , bi 1 & i $ n în care ai " r1, 2, ..., ix ³i
bi " rN, S, E, V x. Camerele vor numerotate de la 1 la n. Perechea ai , bi precizeaz poziµia
camerei i 1 faµ de camera ai : E înseamn la dreapta (est), N deasupra (nord), V la stânga
(vest), S dedesubt (sud). Observaµi c pentru prima camer nu exist nicio precizare!
De exemplu, casa de mai sus poate descris de ³irul (1 E) (2 E) (2 S) (3 S), adic a doua
camer e lipit la est de prima camer , urm toarea (a treia) la est de camera 2, a patra la sud
de camera 2, iar ultima la sud de camera 3.
Cerinµe
1. Se d descrierea unei case prin construcµie ³i se cere descrierea acesteia prin matricea
minimal .
2. Se d descrierea unei case prin matricea minimal ³i se cere descrierea acesteia prin con-
strucµie.
Date de intrare
Fi³ierul casa.in conµine:
a Pe prima linie un num r natural p reprezentând cerinµa care trebuie rezolvat . Pentru toate
testele de intrare, num rul p poate avea valoarea 1 sau 2.
a Dac valoarea lui p este 1 atunci liniile urm toare conµin descrierea unei case prin construcµie
astfel: pe linia a doua un num r natural N reprezentând num rul de camere ale casei, iar pe ecare
din urm toarele N 1 linii câte dou valori separate prin câte un spaµiu - un num r natural ³i un
caracter, cu semnicaµia de mai sus.
a Dac valoarea lui p este 2 atunci liniile urm toare conµin descrierea unei case prin matrice
minimal astfel: pe linia a doua dou numere naturale nenule M , N reprezentând dimensiunile
matricei, iar pe urm toarele M linii câte N numere 0 sau 1 separate prin câte un spaµiu.
Date de ie³ire
Dac valoarea lui p este 1 atunci se va rezolva numai cerinµa 1. În acest caz ³ierul casa.out
va conµine pe prima linie dou numere naturale M ³i N , separate prin câte un singur spaµiu repre-
zentând num rul de linii respectiv num rul de coloane ale matricei minimale, iar pe urm toarele
M linii câte N valori 0 sau 1 separate prin câte un singur spaµiu.
Dac valoarea lui p este 2 atunci se va rezolva numai cerinµa 2. În acest caz ³ierul casa.out
va conµine pe prima linie dou numere naturale N r ³i C separate printr-un singur spaµiu. N r
reprezint num rul de camere, iar C poziµia camerei 1 (cel mai mic num r de ordine al unei
coloane care conµine valoarea 1 în prima linie). Urm toarele N r 1 linii vor conµine ecare câte
dou valori separate printr-un singur spaµiu, reprezentând descrierea unei case prin construcµie
conform preciz rilor din enunµ. Coloanele vor numerotate începând de la 1, iar dac exist mai
multe soluµii va a³at cea mai mic în ordine lexicograc : perechea k, l va a³at înaintea
perechii k, l dac k $ k sau dac k k ³i l $ l (adic E < N < S < V).
CAPITOLUL 23. ONI 2015 440
Restricµii ³i preciz ri
a Matricea minimal a unei case are maximum 100 000 elemente.
Exemple:
casa.in casa.out Explicaµii
1 23
5 111
1 E 011
2 E
2 S
3 S
2 51
2 3 1E
1 11 1S
1 01 2E
4S
Timp maxim de executare/test: 0.1 secunde
Memorie: total 4 MB
Dimensiune maxim a sursei: 10 KB
Cerinµa 1.
Se determin câµi pa³i se fac spre nord, sud, est, vest, pornind din camera 1. Astfel se determin
dimensiunile matricei, apoi, având poziµionat corect camera 1, se completeaz matricea cu 1
urmând succesiv pa³ii daµi .
Cerinµa 2.
Se determin u³or poziµia primei camere, pe linia 1. Fiecare din camerele urm toare se deter-
min c utând pentru camera anterioar în cele 4 direcµii vecinii cu valoarea 1 care nu au fost deja
enumeraµi.
Deoarece nu se cunosc limitele maxime ale dimensiunilor m ³i n ale matricei, dar se cunoa³te
produsul lor m*n <= 100 000 se folose³te în locul unei matrice un vector de dimensiune 100 000
(liniarizarea matricei).
16
17 fi>>op;
18 if (op==1)
19 {
20 fi>>nc;
21 for (i=1;i<nc;i++)
22 fi>>a[i]>>c[i];
23
24 int max_e=0,max_v=0,max_n=0,max_s=0;
25 for (i=1;i<=nc;i++)
26 {
27 for(j=0;j<4;j++)
28 p[i+1][j]=p[a[i]][j];
29
30 switch(c[i])
31 {
32 case ’N’:
33 p[i+1][2]--;
34 p[i+1][1]++;
35 if(p[i+1][1]>max_n)
36 max_n=p[i+1][1];
37 break;
38 case ’S’:
39 p[i+1][1]--;
40 p[i+1][2]++;
41 if(p[i+1][2]>max_s)
42 max_s=p[i+1][2];
43 break;
44 case ’E’:
45 p[i+1][3]--;
46 p[i+1][0]++;
47 if(p[i+1][0]>max_e)
48 max_e=p[i+1][0];
49 break;
50 case ’V’:
51 p[i+1][0]--;
52 p[i+1][3]++;
53 if(p[i+1][3]>max_v)
54 max_v=p[i+1][3];
55 break;
56 }
57 }
58
59 m=max_n+max_s+1;
60 n=max_e+max_v+1;
61 fo<<m<<" "<<n<<"\n";
62 p[1][1]=max_n+1;
63 p[1][2]=max_v+1;
64
65 for (i=1;i<nc;i++)
66 {
67 switch(c[i])
68 {
69 case ’N’:
70 p[i+1][1]=p[a[i]][1]-1;
71 p[i+1][2]=p[a[i]][2];
72 break;
73 case ’S’:
74 p[i+1][1]=p[a[i]][1]+1;
75 p[i+1][2]=p[a[i]][2];
76 break;
77 case ’E’:
78 p[i+1][1]=p[a[i]][1];
79 p[i+1][2]=p[a[i]][2]+1;
80 break;
81 case ’V’:
82 p[i+1][1]=p[a[i]][1];
83 p[i+1][2]=p[a[i]][2]-1;
84 break;
85 }
86 }
87
88 for (i=1;i<=nc;i++)
89 t[(p[i][1]-1)*n+p[i][2]-1]=1;
90
91 for (i=1;i<=m;i++)
CAPITOLUL 23. ONI 2015 442
92 {
93 for (j=1;j<=n;j++)
94 fo<<t[(i-1)*n+j-1]<<" ";
95 fo<<"\n";
96 }
97 }
98
99 if (op==2)
100 {
101 fi>>m>>n;
102 nc=0;
103 k=0;
104
105 for (j=1;j<=n;j++)
106 {
107 fi>>t[j-1];
108 nc+=t[j-1];
109 if (k==0 && t[j-1]==1)
110 k=j;
111 }
112
113 for (i=2;i<=m;i++)
114 for (j=1;j<=n;j++)
115 {
116 fi>>t[(i-1)*n+j-1];
117 nc+=t[(i-1)*n+j-1];
118 }
119
120 fo<<nc<<" "<<k<<"\n";
121 p[1][0]=1;
122 p[1][1]=k;
123 t[k-1]=2;
124 k=1;
125 v=1;
126
127 while (v<nc)
128 {
129 i=p[k][0];
130 j=p[k][1];
131
132 if (j<n && t[(i-1)*n+j]==1)
133 {
134 v++;
135 t[(i-1)*n+j]=v+1;
136 p[v][0]=i;
137 p[v][1]=j+1;
138 p[v][2]=1;
139 }
140
141 if (i>1 && t[(i-2)*n+j-1]==1)
142 {
143 v++;
144 t[(i-2)*n+j-1]=v+1;
145 p[v][0]=i-1;
146 p[v][1]=j;
147 p[v][2]=2;
148 }
149
150 if (i<m && t[i*n+j-1]==1)
151 {
152 v++;
153 t[i*n+j-1]=v+1;
154 p[v][0]=i+1;
155 p[v][1]=j;
156 p[v][2]=3;
157 }
158
159 if (j>1 && t[(i-1)*n+j-2]==1)
160 {
161 v++;
162 t[(i-1)*n+j-2]=v+1;
163 p[v][0]=i;
164 p[v][1]=j-1;
165 p[v][2]=4;
166 }
167
CAPITOLUL 23. ONI 2015 443
168 k++;
169 }
170
171 for (k=2;k<=nc;k++)
172 {
173 i=p[k][0];
174 j=p[k][1];
175 switch(p[k][2])
176 {
177 case 1: j--; break;
178 case 2: i++; break;
179 case 3: i--; break;
180 case 4: j++; break;
181 }
182
183 fo<<t[(i-1)*n+j-1]-1<<" "<<pct[p[k][2]]<<"\n"; }
184 }
185
186 return 0;
187 }
53 for(i=1;i<=lmax;i++)
54 for(j=1;j<=cmax;j++)
55 a[i][j]=0;
56 ///copiere din coada
57 a[1][1]=1;
58 for(i=2;i<=t;i++) a[coada[i].x][coada[i].y]=1;
59
60 ///afisare
61 for(i=1;i<=lmax;i++)
62 {
63 for(j=1;j<cmax;j++)
64 fout<<a[i][j]<<" ";
65 fout<<a[i][j]<<endl; ///ultimul de pe linie
66 }
67 }
68
69 if (caz==2)
70 {
71 fin>>n>>m;
72 bool a[n+2][m+2]; ///definire locala de matrice
73
74 ///initializare bordura
75 for(i=0;i<=n+1;i++) a[i][0]=a[i][m+1]=0;
76 for(j=1;j<=m+1;j++) a[0][j]=a[n+1][j]=0;
77
78 ///prelucrare
79 t=0;
80 lmax=0;
81 cmax=0;
82 for(i=1;i<=n;i++)
83 for(j=1;j<=m;j++)
84 {
85 fin>>a[i][j];
86 t+=a[i][j];
87 if ((lmax+cmax==0) && (a[i][j]==1)) lmax=i,cmax=j;
88 }
89 fout<<t<<" "<<cmax<<"\n";
90
91 st=dr=1;
92 coada[1].x=lmax;
93 coada[1].y=cmax;
94 a[lmax][cmax]=0;
95 while(st<=dr)
96 {
97 // st - nr camerei vecina
98 lmax=coada[st].x;
99 cmax=coada[st].y;
100 for(k=0;k<4;k++)
101 if (a[lmax+dx[k]][cmax+dy[k]]==1)
102 {
103 fout<<st;
104 if (k==0) fout<<" E\n";
105 if (k==1) fout<<" N\n";
106 if (k==2) fout<<" S\n";
107 if (k==3) fout<<" V\n";
108 a[lmax+dx[k]][cmax+dy[k]]=0;
109 dr++;
110 coada[dr].x=lmax+dx[k];
111 coada[dr].y=cmax+dy[k];
112 }
113 st++;
114 }
115 }
116
117 return 0;
118 }
7 ifstream f("casa.in");
8 ofstream g("casa.out");
9
10 struct matrice
11 {
12 int l,c;
13 } q[100010];
14
15 int a[100010];
16 int dx[4]={0,1,-1,0}, dy[4]={1,0,0,-1},dx1[]={0,-1,1,0},dy1[]={-1,0,0,1};
17 char dir1[]="ESNV";
18 int var,i,j,n,lmax,cmax,cmin,v,m,nr,lmin;
19 char ch;int dir[256];
20
21 int cmp(matrice a, matrice b)
22 {
23 if(a.l==b.l)
24 return a.c<b.c;
25 return a.l<b.l;
26 }
27
28 int main()
29 {
30 f>>var;
31 dir[’E’]=0;
32 dir[’S’]=1;
33 dir[’N’]=2;
34 dir[’V’]=3;
35
36 if(var==1)
37 {
38 f>>n;
39 q[1].l=1;
40 q[1].c=1;
41 cmin=lmin=1000000000;
42
43 for(i=2;i<=n;i++)
44 {
45 f>>v>>ch;
46 q[i].l=q[v].l+dx[dir[ch]];
47 q[i].c=q[v].c+dy[dir[ch]];
48
49 if(q[i].l>lmax)
50 lmax=q[i].l;
51
52 if(q[i].l<lmin)
53 lmin=q[i].l;
54
55 if(q[i].c>cmax)
56 cmax=q[i].c;
57
58 if(q[i].c<cmin)
59 cmin=q[i].c;
60 }
61
62 if(cmin<=0)
63 {
64 cmax+=(-cmin)+1;
65 for(i=1;i<=n;i++)
66 q[i].c+=(-cmin)+1;
67 }
68
69 if(lmin<=0)
70 {
71 lmax+=(-lmin);
72 for(i=1;i<=n;i++)
73 q[i].l+=(-lmin)+1;
74 }
75
76 g<<lmax<<" "<<cmax<<’\n’;
77
78 sort(q+1,q+n+1,cmp);
79
80 int k=1;
81 for(i=1;i<=lmax;i++)
82 {
CAPITOLUL 23. ONI 2015 446
83 for(j=1;j<=cmax;j++)
84 if(i==q[k].l&&j==q[k].c)
85 {
86 g<<1<<" ";k++;
87 }
88 else
89 g<<0<<" ";
90
91 g<<’\n’;
92 }
93
94 return 0;
95 }
96
97 f>>n>>m;
98 int x,c1;
99 for(i=1;i<=n;i++)
100 for(j=1;j<=m;j++)
101 {
102 f>>x;
103 if(x==1)
104 {
105 nr++;
106 if(nr==1)
107 c1=j;
108
109 a[(i-1)*m+j]=-1;
110 }
111 }
112
113 g<<nr<<" "<<c1<<’\n’;
114
115 q[1].l=1;
116 q[1].c=c1;
117 a[c1]=1;
118 int p=1,u=1;
119 nr=1;
120
121 while(p<=u)
122 {
123 for(int k=0;k<4;k++)
124 {
125 int l=q[p].l+dx[k];
126 int c=q[p].c+dy[k];
127 int t=(l-1)*m+c;
128 if(l>=1&&l<=n&&c>=1&&c<=m&&a[t]==-1)
129 {
130 nr++;
131 g<<a[(q[p].l-1)*m+q[p].c]<<" "<<dir1[k]<<’\n’;
132 a[t]=nr;
133 u++;
134 q[u].l=l;
135 q[u].c=c;
136 }
137 }
138
139 p++;
140 }
141
142 return 0;
143 }
23.5 lenes
Problema 5 - lenes 100 de puncte
Lene³ul este un animal foarte lene³. El se deplaseaz numai în linie dreapt , dar face din când
în când câte un popas. în aceast problem lene³ul trebuie s traverseze de la nord la sud ³i
înapoi un teren reprezentat de o matrice de dimensiuni M N cu valori numere naturale. Valorile
reprezint efortul cerut pentru traversarea zonei respective. Lene³ul va alege o coloan pentru
traversarea matricei, iar pentru popasuri, în num r de k1, va alege zone al turate drumului din
coloana din stânga sau cea din dreapta. în cazul în care se va întoarce va proceda la fel, dar va
CAPITOLUL 23. ONI 2015 447
face k2 popasuri. Regulile problemei cer ca cele dou drumuri s nu aib zone comune.
Cerinµe
Cunoscând dimensiunile M , N ale terenului, num rul de popasuri k1, k2 ³i efortul pentru
traversarea ec rei zone a terenului, s se determine:
1. Efortul minim de parcurgere a terenului de la Nord la Sud, folosind k1 popasuri.
2. Efortul minim de parcurgere a terenului de la Nord la Sud ³i înapoi de la Sud la Nord,
folosind k1 popasuri la deplasarea Nord - Sud, respectiv k2 popasuri la deplasarea Sud - Nord.
Date de intrare
Fi³ierul lenes.in conµine:
a Pe prima linie un num r natural p reprezentând cerinµa de rezolvare. Pentru toate testele
de intrare num rul p poate avea doar valoarea 1 sau 2.
a Pe linia a doua sunt 4 numere naturale M , N , k1, k2, separate prin câte un spaµiu cu
semnicaµia de mai sus.
a Pe urm toarele M linii se g sesc câte N numere naturale separate prin câte un spaµiu,
reprezentând eforturile de traversare a ec rei zone a terenului.
Date de ie³ire
a Dac valoarea lui p este 1, se va rezolva numai cerinµa 1. în acest caz ³ierul lenes.out va
conµine un singur num r natural reprezentând efortul minim necesar pentru traversarea terenului
în condiµiile date de la Nord la Sud.
a Dac valoarea lui p este 2, se va rezolva numai cerinµa 2. în acest caz ³ierul lenes.out va
conµine un singur num r natural reprezentând efortul minim necesar pentru traversarea terenului
în condiµiile date în ambele sensuri de la Nord la Sud ³i de la Sud la Nord.
Restricµii ³i preciz ri
a 3 & M, N & 500
a 0 & k1, k2 & M
a Valorile din matrice sunt numere naturale din intervalul 1, 1000.
a Lene³ul poate s fac popasuri pe aceea³i linie în ambele celule din stânga ³i din dreapta
coloanei parcurse.
a Deplasarea între ultima zon a drumului parcurs de la Nord la Sud ³i prima zon a drumului
parcurs de la Sud la Nord la întoarcere se face cu efort 0.
Exemple:
30
31 for ( int i = 1; i <= M; ++ i )
32 {
33 if ( up )
34 ++ v[ Mat[lin - 1][i] ];
35 if ( down )
36 ++ v[ Mat[lin + 1][i] ];
37 }
38
39 for ( int i = 0; i < VMax && k ; ++ i )
40 if ( k >= v[i] )
41 {
42 res += i * v[i];
43 k -= v[i];
44 }
45 else if ( v[i] )
46 {
47 res += k * i;
48 k = 0;
49 }
50
51 return res;
52 }
53
54 int case1()
55 {
56
57 int ret = get_line_sum(1, k1);
58
59 for ( int i = 1; i <= N; ++ i )
60 ret = min( ret, get_line_sum(i, k1));
61
62 return ret;
63 }
64
65 int case2()
66 {
67
68 int ret = oo;
69
70 for ( int i = 1; i <= N; ++ i )
71 V[i] = get_line_sum(i, k2);
72
73 left[1] = V[1];
74 for ( int i = 2; i <= N; ++ i )
75 left[i] = min(V[i], left[i - 1]);
76
77 right[N] = V[N];
78 for ( int i = N - 1; i > 0; -- i )
79 right[i] = min(V[i], right[i + 1]);
80
81
82 // computing distant lines
83 for ( int i = 1; i <= N; ++ i )
84 {
85 int r = get_line_sum(i, k1);
86 int other = oo;
87
88 if ( i > 3 ) other = min(other, left[i - 3]);
89 if ( i < N - 2) other = min(other, right[i + 3]);
90
91 ret = min(ret, r + other);
92 }
93
94 // computing adiacent lines
95 for ( int i = 1; i < N; ++ i )
96 {
97
98 int r1 = get_line_sum(i, k1 , true, false);
99 int r2 = get_line_sum(i + 1, k2, false, true);
100
101 ret = min( ret, r1 + r2 );
102
103 r1 = get_line_sum(i, k2 , true, false);
104 r2 = get_line_sum(i + 1, k1, false, true);
105
CAPITOLUL 23. ONI 2015 450
182 }
183
184 return ret;
185 }
186
187 int Work[])() = case1, case2 ;int main()freopen(IN, "r", stdin);freopen(OUT, "w",
stdout);scanf("for ( int i = 1; i <= N; ++ i)for ( int j = 1; j <= M; ++ j
)scanf("swap(N, M);for ( int i = 1; i <= N; ++ i )for ( int j = 1; j <= M; ++ j
)Sum[i] += Mat[i][j];for ( int i = 1; i <= M; ++ i )Mat[0][i] = Mat[N + 1][i] = VMax
- 1;for ( int i = 1; i <= N; ++ i )sort( Mat[i] + 1, Mat[i] + M + 1);printf("return
0;
64
65 if (p==1)
66 {
67 for (j=1;j<n;j++)
68 {
69 s=calc(j,k1);
70 if (s<mn) mn=s;
71 }
72 g<<mn<<"\n";
73 }
74 else
75 {
76 int cc;
77 // cazul 1: doua coloane alaturate (j si j+1)
78 for (j=2;j<n-1;j++)
79 {
80 for (int g=1;g<=2;g++)
81 {
82 s=0;
83 for (i=1;i<=k1;i++)
84 s=s+a[i][j-1];
85 for (i=1;i<=k2;i++)
86 s+=a[i][j+2];
87
88 s=s+sum[j]+sum[j+1];
89 if (s<mn) mn=s;
90 s1=k1; k1=k2; k2=s1;
91 }
92 }
93
94 // cazul 2: coloanele j si j+2 (o coloana goala intre ele)
95 for (j=2;j<n-2;j++)
96 for (int g=1; g<=2; g++)
97 {
98 s1=0;
99 for (i=1; i<=k1; i++)
100 s1+=a[i][j-1];
101 for (i=1; i<=k2; i++)
102 s1+=a[i][j+3];
103
104 // incercam sa inlocuim o parte din popasuri cu
105 // popasuri pe coloana din mijloc, j+1
106 i1=k1; i2=1; i3=k2;
107 s=s1;
108 do
109 {
110 ok=0;
111 if (i1>0 &&
112 a[i1][j-1]>=a[i3][j+3] &&
113 a[i1][j-1]>a[i2][j+1]) // inlocuim un popas de pe
114 // coloana j-1 cu popas pe
115 {
116 // coloana j+1
117 s=s+a[i2][j+1]-a[i1][j-1];
118 i1--;
119 i2++;
120 ok=1;
121 }
122 else
123 if (i3>0 &&
124 a[i3][j+3]>=a[i1][j-1] &&
125 a[i3][j+3]>a[i2][j+1]) // inlocuim un popas de pe
126 // coloana j-1 cu popas pe
127 {
128 // coloana j+1
129 s=s+a[i2][j+1]-a[i3][j+3];
130 i3--;
131 i2++;
132 ok=1;
133 }
134 } while (ok==1);
135
136 s+=sum[j]+sum[j+2];
137 if (s<mn)
138 mn=s;
139
CAPITOLUL 23. ONI 2015 453
216 }
217 }
71 if (s<mn) mn=s;
72
73 s = sum[i-1][k2] + sum[i][m] + sum[i+1][m] + sum[i+2][k1];
74 if (s<mn) mn=s;
75 }
76
77 // cazul 2: 2 coloane cu una intre ele
78 for (int tt=1;tt<=2;tt++)
79 {
80 for (i=2;i<=n-3;i++)
81 {
82
83 i1=k1; i2=0; i3=k2;
84 s = sum[i][m] + sum[i+2][m];
85 do
86 {
87 gg=0;
88 if (i1>=1 && i2<=m &&
89 a[i+1][i2+1]<a[i-1][i1] && a[i+3][i3]<=a[i-1][i1])
90 {
91 i1--; i2++; gg=1;
92 }
93 else
94 if (i3>=1 && i2<=m &&
95 a[i+1][i2+1]<a[i+3][i3] && a[i-1][i1]<=a[i+3][i3])
96 {
97 i3--; i2++; gg=1;
98 }
99 } while (gg==1);
100 s1 = s + sum[i-1][i1] + sum[i+1][i2] + sum[i+3][i3];
101 if (s1<mn) mn=s1;
102 }
103
104 // coloanele 1 si 3
105 s = sum[1][m] + sum[3][m];
106
107 if (n>3)
108 {
109 for (j=0;j<=k2;j++)
110 if (k1+j<=m && k2>j)
111 {
112 s1 = sum[2][k1+j];
113 s1 += sum[4][k2-j];
114 s1 += s;
115 if (s1<mn) mn=s1;
116 }
117 }
118 else
119 {
120 s=s+sum[2][k1+k2];
121 if (s<mn) mn=s;
122 }
123
124 // coloanele n-2 si n
125 if (n>3)
126 {
127 s = sum[n-2][m] + sum[n][m];
128
129 for (j=0;j<=k1;j++)
130 if (k2+j<=m && k1>j)
131 {
132 s1 = sum[n-3][k1-j];
133 s1 += sum[n-1][k2+j];
134 s1 += s;
135 if (s1<mn) mn=s1;
136 }
137 }
138 i1=k1; k1=k2; k2=i1;
139 }
140
141 // cazul 3: doua coloane oarecare
142 for (i=1; i<=n-3; i++)
143 {
144 s1 = calc(i,k1);
145 s2 = calc(i,k2);
146 for (i1=i+3;i1<=n;i1++)
CAPITOLUL 23. ONI 2015 456
147 {
148 s = s1 + calc(i1,k2);
149 if (s<mn) mn=s;
150
151 s = s2 + calc(i1,k1);
152 if (s<mn) mn=s;
153 }
154 }
155 g<<mn<<’\n’;
156 }
157 }
23.6 sipet
Problema 6 - sipet 100 de puncte
Un arheolog a g sit un sipet interesant. Dup ce l-a deschis cu grij , a
constatat cu surprindere c sipetul conµine b nuµi de aur. Uitându-se mai
atent a mai g sit ceva: un pergament ascuns într-un compartiment secret al
sipetului, cu un text scris într-o limb antic , pe care, din fericire, arheologul
o cuno³tea. Din text a reie³it c un grup de negustori foarte bogaµi a vrut
s ascund în mare secret averea breslei lor, format din monede de aur,
deoarece se prevestea un r zboi cumplit. Negustorii ³tiau c exist ³anse ca aceast comoar s
e g sit ³i conscat de du³mani, deci s-au sf tuit cum e mai bine s procedeze, cum s ascund
comoara. Arheologul a reu³it s deduc din text urm toarele:
a) Cele N monede, care formau averea breslei, au fost împ rµite în maximum trei feluri de
gr mezi, formate din p1, p2 ³i p3 b nuµi, p1, p2 ³i p3 ind numere prime consecutive, p1 $ p2 $ p3.
Fiecare gr mad a fost pus în întregime într-un sipet.
b) Este posibil s existe 0 (zero) gr mezi formate din p1 sau p2 sau p3 monede, scopul ind
s se obµin o împ rµire în care num rul monedelor r mase nedistribuite s e minim, iar dac
exist mai multe posibilit µi, se alege aceea pentru care num rul de gr mezi este mai mare. Dac
exist mai multe astfel de soluµii, se consider corect oricare dintre ele.
c) Monedele care nu au putut distribuite conform regulilor stabilite, au fost donate bisericii.
Cerinµe
Scrieµi un program care determin num rul maxim S de sipete ³i num rul sipetelor cu p1, p2
respectiv p3 monede, precum ³i suma donat bisericii.
Date de intrare
Fi³ierul sipet.in conµine, pe prima linie num rul natural T , iar pe urm toarele T linii câte
dou numerele naturale N ³i p1, desp rµite printr-un singur spaµiu.
Date de ie³ire
Fi³ierul sipet.out va conµine pe primele T linii câte 5 numere naturale, separate prin câte
un spaµiu: S , x, y , z ³i r, reprezentând num rul maxim S de sipete, num rul x de sipete cu
p1 monede, num rul y de sipete cu p2 monede, respectiv num rul z de sipete cu p3 monede ³i
num rul r de monede donate bisericii, corespunz toare datelor de intrare de pe linia T 1 a
³ierului sipet.in. Dac exist mai multe soluµii corecte, este acceptat oricare dintre ele.
Restricµii ³i preciz ri
a 1 & N & 10 000 000
a 2 & p1 $ p2 $ p3 & N
a 1 & T & 10 - în ³ierul de intrare nu vor mai mult de 10 perechi de numere N p1
Exemple:
sipet.in sipet.out Explicaµii
3 33000 - num rul maxim de sipete este 3, toate cu câte 3 monede;
15 5 21010 - sau: 2 0 2 0 0 (1*3+1*7=2*5=10); (ambele soluµii sunt co-
10 3 31110 recte!)
41 11 - num rul maxim de sipete este 3; 1 sipet cu 11, unul cu 13 ³i
unul cu 17 monede.
CAPITOLUL 23. ONI 2015 457
15 {
16 int a, b;
17 };
18
19 int Tes, N, L, p[4];
20 int A, B, C, R;
21 pereche v[NMax];
22 bool bb[NMax];
23
24 bool isPrime( int x )
25 {
26
27 for ( int d = 2; d * d <= x; ++ d )
28 if ( x % d == 0 )
29 return false;
30 return true;
31
32 }
33
34 int sqr( int x )
35 {
36 return x * x;
37 }
38
39 int main()
40 {
41
42 freopen(IN, "r", stdin);
43 freopen(OUT, "w", stdout);
44
45 scanf("%d", &Tes);
46
47 while ( Tes -- )
48 {
49 scanf("%d%d", &N, &p[1]);
50
51 assert(isPrime(p[1]));
52 for ( int i = 2; i <= 3; ++ i )
53 for ( p[i] = p[i - 1] + 1; !isPrime(p[i]); ++ p[i] );
54
55 // fprintf(stderr, "%d %d %d\n", p[1], p[2], p[3]);
56 for ( int a = 0; a * p[1] <= N; ++ a )
57 for ( int b = 0; a * p[1] + b * p[2] <= N && b < p[1]; ++ b )
58 {
59 int pos = a * p[1] + b * p[2];
60 v[pos].a = a;
61 v[pos].b = b;
62 bb[pos] = true;
63 }
64
65 bool found = false; R = -1;
66 for ( int r = 0; r <= p[1] && R == -1; ++ r )
67 for ( int c = 0; r + c * p[3] <= N && c <= p[1]; ++ c )
68 {
69 int pos = c * p[3] + r;
70 if ( bb[N - pos] &&
71 (R == -1 || R != -1 &&
72 A + B + C < v[N - pos].a + v[N - pos].b + c ))
73 {
74 found = true;
75 A = v[N - pos].a;
76 B = v[N - pos].b;
77 C = c;
78 R = r;
79 }
80 }
81
82 for ( int a = 0; a * p[1] <= N; ++ a )
83 for ( int b = 0; a * p[1] + b * p[2] <= N && b < p[1]; ++ b )
84 {
85 int pos = a * p[1] + b * p[2];
86 bb[pos] = false;
87 }
88
89 printf("%d %d %d %d %d\n", A + B + C, A, B, C, R);
90
CAPITOLUL 23. ONI 2015 459
91 }
92
93 return 0;
94 }
Capitolul 24
ONI 2014
24.1 harta
Problema 1 - harta 100 de puncte
Pe baza unei imagini preluate din satelit, se realizeaz harta unei mici localit µi. Localitatea
ocup o suprafaµ dreptunghiular , cu laturile orientate pe direcµiile Nord-Sud, respectiv Est-Vest.
Studiind imaginea obµinut de la satelit, cartograi au constatat c toate cele k cl diri au
forma unor dreptunghiuri distincte. Imaginea poate reprezentat sub forma unui tablou cu
n m celule a³ezate pe n linii numerotate de la 1 la n ³i m coloane numerotate de la 1 la m.
Numim drum, un dreptunghi al tabloului care str bate întreaga localitate pe direcµia Est-Vest
³i are un num r maxim de linii sau un dreptunghi care str bate întreaga localitate pe direcµia
Nord-Sud ³i are un num r maxim de coloane. Drumurile, evident, nu trebuie s treac prin
cl diri.
Cartograi sunt interesaµi ca pe aceast hart s e reprezentate la scar doar cl dirile, nu
³i drumurile. De aceea, pentru realizarea h rµii, l µimile drumurilor au fost reduse la o singur
celul .
Tabloul care reprezint imaginea localit µii se codic astfel: 1 pentru o celul ocupat de o
cl dire ³i 0 pentru o celul neocupat .
Cerinµe
Cunoscând n, m ³i k , precum ³i tabloul care codic imaginea, se cere s se determine:
1. Num rul S de celule ocupate de c tre cl direa p tratic cu latura maxim ³i num rul
de cl diri C alese dintre celelalte k 1 cl diri, cu proprietatea c ecare dintre ele încape în
interiorul cl dirii p tratice cu latur maxim , f r s se suprapun peste celulele marginale ale
acesteia.
2. Tabloul care reprezint harta, în urma prelucr rii imaginii iniµiale.
Date de intrare
Fi³ierul de intrare harta.in conµine pe prima linie un num r natural p. Pentru toate testele
de intrare, num rul p poate avea doar valoarea 1 sau valoarea 2.
Pe linia a doua se g sesc numerele naturale n, m ³i k separate prin câte un spaµiu.
Pe ecare dintre urm toarele k linii, se g sesc câte patru numere naturale i1 j1 i2 j2 separate
prin câte un spaµiu, primele dou numere reprezentând coordonatele celulei din extremitatea Nord-
Vest, iar ultimele dou , coordonatele celulei din extremitatea Sud-Est pentru ecare dintre cele k
cl diri.
Date de ie³ire
a Dac valoarea lui p este 1, atunci se va rezolva numai cerinµa 1. În acest caz, în ³ierul de
ie³ire harta.out se vor scrie cele dou numere S ³i C având semnicaµia descris la cerinµa 1,
separate printr-un singur spaµiu.
a Dac valoarea lui p este 2, atunci se va rezolva numai cerinµa 2. În acest caz, ³ierul de
ie³ire harta.out va conµine tabloul care reprezint harta obµinut pe baza imaginii din satelit.
Fi³ierul va avea n1 linii. Pe ecare linie se vor g si câte m1 valori 0 sau 1 separate prin câte un
singur spaµiu. Celulele situate pe marginile cl dirilor vor avea valoarea 1. Celulele din interiorul
cl dirilor, ca ³i cele din exterior, vor avea valoarea 0.
460
CAPITOLUL 24. ONI 2014 461
Restricµii ³i preciz ri
a3 & n, m & 1500
a1 & i1 & i2 & n
a 1 & j1 & j2 & m
a 1 & k & 1000
a 1 & Lmax & 50 (Lmax - latura maxim a unui dreptunghi)
a Se garanteaz c exist soluµie pentru ambele cerinµe, pentru toate datele de test.
a Pentru rezolvarea corect a primei cerinµe se acord 20 de puncte, iar pentru cerinµa a doua
se acord 80 de puncte.
Exemple:
Cerinµa a) - 20 puncte
Se determin latura Lmax a celei mai mari cl diri p tratice. Apoi, pentru ecare cl dire, se
determin dac laturile sale de lungimi L ³i H îndeplinesc condiµia: L $ Lmax 1 ³i H $ Lmax 1.
Cerinµa b) Total - 80 de puncte
Soluµia 1 - 30 de puncte
Liniile ³i coloanele care trebuie ³terse trebuie s nu conµin valori 1. Se reµin numerele de
ordine acele acestor linii ³i coloane. Dac determinarea acestor linii sau coloane se face prin
parcurgerea lor ³i ³tergerea se fece linie cu linie, respectiv coloan cu coloan , atunci, în funcµie
de alte optimiz ri, se pot obµine 30 de puncte.
Soluµia 2 - 55 de puncte
CAPITOLUL 24. ONI 2014 462
Se reµin la fel ca în soluµia anterioar numerele de ordine ale linilor ³i coloanelor care trebuie
³terse. Pentru ecare drum pe hart , se ³terg num rul maxim posibil de linii, respectiv coloane
adiacente.
Solutia 3 - 80 de puncte
În timpul citirii se genereaz cl dirile în interiorul matricei a conform cerinµelor de a³are.
Pentru a evita operaµiile de ³tergere de linii/coloane se marcheaz liniile/coloanele care trebuie
sa e ³terse astfel:
- initial a[i][0]=0; respectiv a[0][j]=0;
- dac linia i / coloana j intersecteaz cel puµin o cl dire, atunci a[i][0]=1; respectiv a[0][j]=1;
- dac a[i][0]==0 si a[i+1][0]==0, atunci a[i][0]=2; (marc m linia i pentru eliminare)
- dac a[0][j]==0 si a[0][j+1]==0, atunci a[0][j]=2; (marc m coloana j pentru eliminare)
- se a³eaz toate elementele a[i][j] pentru care a[i][0]!=2 && a[0][j]!=2
Soluµia 4 - 80 de puncte
Se reµin în ³irurul x toate liniile pe care se g se³te cel puµin o celul marginal ocupat de
o cl dire, iar în ³irul y toate coloanele pe care se g se³te cel puµin o celul marginal ocupat
de o cl dire. Pentru ecare dreptunghi i1 j1 i2 j2, se insereaz în x ³i y ³i coordonatele celulei
i1 1, j1 1 situate în exteriorul c dirii.
în ³irurile xa ³i xb se reµin liniile ³i coloanele tuturor celulelor marginale ocupate de cl diri.
Se ordoneaz cresc tor ³irurile x ³i y , apoi, pentru ecare valoare din ³irul xa, se caut binar
poziµia i a acesteia în ³irul x, iar pentru ecare valoare din ³irul ya, se caut binar poziµia j a
acesteia în ³irul y .
Poziµia i, j obµinut astfel reprezint noile coordonate ale unei celule marginale ocupate de
o cl dire pe hart .
109
110 n = 0, m = 0; int i, j;
111 for (size_t k = 0; k < xa.size(); ++k )
112 {
113 i= GetPos(b1, xa[k]);
114 j = GetPos(b2, ya[k]);
115 n = max(n, i), m = max(m, j);
116 A[i][j] = 1;
117 }
118
119 if ( n < M ) n++;
120 if ( m < M ) m++;
121 WriteMatr(A, n, m);
122 }
123
124 fin.close();
125 fout.close();
126 return 0;
127 }
128
129
130 int GetPos(VI v, int val)
131 {
132 int i, p2, n = v.size();
133 int lo = 0, hi = n, mid;
134
135 while ( lo <= hi )
136 {
137 mid = lo + (hi - lo) / 2;
138 if ( v[mid] == val )
139 return mid;
140 if ( val < v[mid] )
141 hi = mid - 1;
142 else
143 lo = mid + 1;
144 }
145
146 return 0;
147 }
148
149 void WriteMatr(bool a[][DIM], int N, int M)
150 {
151 for ( int i = 1; i <= N; ++i )
152 {
153 for ( int j = 1; j <= M; ++j )
154 fout << a[i][j] << ’ ’;
155 fout << ’\n’;
156 }
157 }
24 fscanf(fin,"%d%d%d%d",&p,&n,&m,&k);
25 for(int i=1;i<=k;++i)
26 {
27 fscanf(fin,"%d%d%d%d",&d[i].i1,&d[i].j1,&d[i].i2,&d[i].j2);
28 d1[i]=d2[i]=d[i];
29 }
30 fclose(fin);
31 }
32
33 void solve()
34 {
35 int a,b;
36 if(p==1)
37 {
38 for(int i=1;i<=k;i++)
39 {
40 a=(d[i].i2-d[i].i1+1);
41 b=(d[i].j2-d[i].j1+1);
42 if(a==b)
43 {
44 s=a*b;
45 if(s>S)
46 {
47 S=s;
48 dmax=d[i];
49 }
50 }
51 }
52
53 for(int i=1;i<=k;i++)
54 {
55 if(d[i].i2-d[i].i1+1<=dmax.i2-dmax.i1-1&&
56 d[i].j2-d[i].j1+1<=dmax.j2-dmax.j1-1)
57 C++;
58 }
59 fprintf(fout,"%d %d\n",S,C);
60
61 }
62 else
63 {
64 int i,j,di=0,dj=0,ix=1,iy,xx=1,yy=1;
65 dreptunghi aux;
66 for(i=1;i<k;i++)
67 for(j=i+1;j<=k;j++)
68 {
69 if(d[i].i1>d[j].i1)
70 {
71 aux=d[i];
72 d[i]=d[j];
73 d[j]=aux;
74 }
75
76 if(d2[i].i2>d2[j].i2)
77 {
78 aux=d2[i];
79 d2[i]=d2[j];
80 d2[j]=aux;
81 }
82
83 if(d1[i].j1>d1[j].j1)
84 {
85 aux=d1[i];
86 d1[i]=d1[j];
87 d1[j]=aux;
88 }
89 }
90
91 for(i=1;i<=k;i++)
92 {
93 if(d[i].i1-2>=xx)
94 for(int ix=xx;ix<=d[i].i1-2;ix++)
95 linii[ix]=1;
96
97 if(d[i].i2>=xx)
98 xx=d[i].i2+1;
99
CAPITOLUL 24. ONI 2014 466
100 if(d1[i].j1-2>=yy)
101 for(int iy=yy;iy<=d1[i].j1-2;iy++)
102 coloane[iy]=1;
103
104 if(d1[i].j2>=yy)
105 yy=d1[i].j2+1;
106 }
107
108 if(n-xx>=1)
109 for(int ix=xx;ix<=n-1;ix++)
110 linii[ix]=1;
111
112 if(m-yy>=1)
113 for(int iy=yy;iy<=m-1;iy++)
114 coloane[iy]=1;
115
116 int ii=1,iii=1;
117 i=1;
118 while(i<=n)
119 {
120 if(!linii[i])
121 {
122 while(d[ii].i1==i&&ii<=k)
123 {
124 x[d[ii].j1]=x[d[ii].j2]=d[ii].i2-d[ii].i1+1;
125
126 for(int jj=d[ii].j1+1;jj<d[ii].j2;jj++)
127 x[jj]=1;
128 ii++;
129 }
130
131 while(d2[iii].i2==i&&iii<=k)
132 {
133 for(int jj=d2[iii].j1+1;jj<d2[iii].j2;jj++)
134 x[jj]=1;
135 iii++;
136 }
137
138 for(j=1;j<=m;j++)
139 if(!coloane[j])
140 if(!x[j])
141 fprintf(fout,"0 ");
142 else
143 {
144 fprintf(fout,"1 ");
145 x[j]--;
146 }
147 fprintf(fout,"\n");
148 }
149
150 i++;
151 }
152 }
153 }
154
155 int main()
156 {
157 read();
158 solve();
159 fclose(fout);
160 return 0;
161 }
11 ofstream fout("harta.out");
12
13 struct Drept
14 {
15 int i1, j1, i2, j2;
16 } d[DIM];
17
18 int sc[DIM], sl[DIM], a[DIM][DIM];
19 int k, N, M, Lmax, L, H, T, nr_dr;
20
21 void WriteMatr(int a[][DIM], int N, int M);
22 void DeleteLine(int L);
23 void DeleteColumn(int C);
24
25 int main()
26 {
27 fin >> T >> N >> M >> k;
28 int i1, j1, i2, j2;
29
30 for ( int i = 0; i < k; ++i )
31 {
32 fin >> i1 >> j1 >> i2 >> j2;
33 d[i].i1 = i1, d[i].j1 = j1, d[i].i2 = i2, d[i].j2 = j2;
34 L = i2 - i1 + 1, H = j2 - j1 + 1;
35
36 if ( L == H && L > Lmax )
37 Lmax = L;
38
39 for ( int i = i1; i <= i2; ++i)
40 a[i][j1] = a[i][j2] = 1, sl[i] += 2;
41
42 for ( int j = j1; j <= j2; ++j )
43 a[i1][j] = a[i2][j] = 1, sc[j] += 2;
44 }
45
46 if ( T == 1 )
47 {
48 for ( int i = 0; i < k; ++i )
49 {
50 L = d[i].i2 - d[i].i1 + 1, H = d[i].j2 - d[i].j1 + 1;
51 if ( L < Lmax - 1 && H < Lmax - 1 )
52 nr_dr++;
53 }
54
55 fout << Lmax * Lmax << ’ ’ << nr_dr << ’\n’;
56 }
57 else
58 {
59 for ( int col = 1; col <= M; ++col ) // pt fiec coloana O(M)
60 {
61 int k = 0;
62 while ( col + k <= M && !sc[col + k] )
63 k++;
64
65 if ( k > 1 )
66 {
67 for ( int j = col + 1; j < col + k; ++j )
68 a[1][j] = 2;
69
70 col += k - 1;
71 }
72 }
73
74 for ( int j = 1; j <= M; ++j )
75 if ( a[1][j] == 2 )
76 DeleteColumn(j), --j;
77
78 for ( int lin = 1; lin <= N; ++lin ) // pt fiec linie O(N)
79 {
80 int k = 0;
81 while ( lin + k <= N && !sl[lin + k] )
82 k++;
83
84 if ( k > 1 )
85 {
86 for ( int i = lin + 1; i < lin + k; ++i )
CAPITOLUL 24. ONI 2014 468
87 a[i][1] = 2;
88
89 lin += k - 1;
90 }
91 }
92
93 for ( int i = 1; i <= N; ++i )
94 if ( a[i][1] == 2 )
95 DeleteLine(i), --i;
96
97 WriteMatr(a, N, M);
98 }
99
100 fin.close();
101 fout.close();
102 return 0;
103 }
104
105 void DeleteLine(int L)
106 {
107 for ( int j = 1; j <= M; ++j )
108 for ( int i = L; i < N; ++i )
109 a[i][j] = a[i + 1][j];
110 N--;
111 }
112
113
114 void DeleteColumn(int C)
115 {
116 for ( int i = 1; i <= N; ++i )
117 for ( int j = C; j < M; ++j )
118 a[i][j] = a[i][j + 1];
119 M--;
120 }
121
122 void WriteMatr(int a[][DIM], int N, int M)
123 {
124 for ( int i = 1; i <= N; ++i )
125 {
126 for ( int j = 1; j <= M; ++j )
127 fout << a[i][j] << ’ ’;
128 fout << ’\n’;
129 }
130 }
29 {
30 fin >> T >> N >> M >> k;
31 int i1, j1, i2, j2;
32
33 for ( int i = 0; i < k; ++i )
34 {
35 fin >> i1 >> j1 >> i2 >> j2;
36 d[i].i1 = i1, d[i].j1 = j1, d[i].i2 = i2, d[i].j2 = j2;
37 L = i2 - i1 + 1, H = j2 - j1 + 1;
38 if ( L == H && L > Lmax )
39 Lmax = L;
40
41 for ( int i = i1; i <= i2; ++i)
42 a[i][j1] = a[i][j2] = 1, sl[i] += 2;
43
44 for ( int j = j1; j <= j2; ++j )
45 a[i1][j] = a[i2][j] = 1, sc[j] += 2;
46 }
47
48 if ( T == 1 )
49 {
50 for ( int i = 0; i < k; ++i )
51 {
52 L = d[i].i2 - d[i].i1 + 1, H = d[i].j2 - d[i].j1 + 1;
53 if ( L < Lmax - 1 && H < Lmax - 1 )
54 nr_dr++;
55 }
56
57 fout << Lmax * Lmax << ’ ’ << nr_dr << ’\n’;
58 }
59 else
60 {
61 for ( int col = 1; col <= M; ++col ) // pt fiec coloana O(M)
62 {
63 int k = 0;
64 while ( col + k <= M && !sc[col + k] )
65 k++;
66
67 if ( k > 1 )
68 {
69 for ( int j = col + 1; j < col + k; ++j )
70 a[1][j] = 2;
71
72 col += k - 1;
73 }
74 }
75
76 for ( int j = 1; j <= M; ++j )
77 {
78 int k = 0;
79 while ( j + k <= M && a[1][j + k] == 2 )
80 ++k;
81
82 if ( k ) DeleteKColumns(j, k), --j;
83 }
84
85 for ( int lin = 1; lin <= N; ++lin ) // pt fiec linie O(N)
86 {
87 int k = 0;
88 while ( lin + k <= N && !sl[lin + k] )
89 k++;
90
91 if ( k > 1 )
92 {
93 for ( int i = lin + 1; i < lin + k; ++i )
94 a[i][1] = 2;
95 lin += k - 1;
96 }
97 }
98
99 for ( int i = 1; i <= N; ++i )
100 {
101 int k = 0;
102 while ( i + k <= N && a[i + k][1] == 2 )
103 ++k;
104
CAPITOLUL 24. ONI 2014 470
13 int patrate[52],lmax;
14 char a[1502][1502];
15 int i1,j1,i2,j2,i;
16 int l1,c1;
17 int S,C;
18
19 int main()
20 {
21 fin>>p>>n>>m>>k;
22 if(p==1)
23 {
24 for(i=1;i<=k;i++)
25 {
26 fin>>i1>>j1>>i2>>j2;
27 lat=i2-i1+1;
28 lung=j2-j1+1;
29 lx=lat;
30 if(lung>lx)lx=lung;
31 patrate[lx]++;
32 if(lat==lung)
33 if(lat>lmax)
34 lmax=lat;
35 }
36
37 S=lmax*lmax;
38 C=0;
39 for(i=1;i<=lmax-2;i++)
40 C=C+patrate[i];
41
42 fout<<S<<" "<<C;
43 }
44 else
45 {
46 for(i=1;i<=k;i++)
47 {
48 fin>>i1>>j1>>i2>>j2;
49 for(l1=i1;l1<=i2;l1++)
50 {
51 a[l1][j1]=1;
52 a[l1][j2]=1;
53 a[l1][0]=1;//marcat linie care ramane
54 }
55
56 for(c1=j1;c1<=j2;c1++)
57 {
58 a[i1][c1]=1;
59 a[i2][c1]=1;
60 a[0][c1]=1;//marcat coloana care ramane
61 }
62 }
63
64 for(l1=1;l1<=n-1;l1++)
65 if(a[l1][0]==0 && a[l1+1][0]==0)
66 a[l1][0]=2;//linia l1 se va sterge
67
68 for(c1=1;c1<=m-1;c1++)
69 if(a[0][c1]==0 && a[0][c1+1]==0)
70 a[0][c1]=2;//coloana c1 se va sterge
71
72 //vom pastra doar liniile si coloanele marcate diferit de 2
73 for (l1=1;l1<=n;l1++)
74 {
75 if(a[l1][0]!=2)
76 {
77 for(c1=1;c1<=m;c1++)
78 if(a[0][c1]!=2)
79 fout<<(int)a[l1][c1]<<" ";
80
81 fout<<"\n";
82 }
83 }
84 }
85
86 fout.close();
87 fin.close();
88 return 0;
CAPITOLUL 24. ONI 2014 473
89 }
72 fin.close();
73 fout.close();
74 return 0;
75 }
76
77 void One()
78 {
79 int nr_dr(0);
80 for ( int i = 0; i < k; ++i )
81 {
82 L = d[i].i2 - d[i].i1 + 1, H = d[i].j2 - d[i].j1 + 1;
83 if ( L < Lmax - 1 && H < Lmax - 1)
84 nr_dr++;
85 }
86 fout << Lmax * Lmax << ’ ’ << nr_dr << ’\n’;
87 }
88
89 void Two()
90 {
91 sort(x.begin(), x.end());
92 sort(y.begin(), y.end());
93
94 x.erase(unique(x.begin(), x.end()), x.end());
95 x.erase(unique(x.begin(), x.end()), x.end());
96 y.erase(unique(y.begin(), y.end()), y.end());
97
98 int i, j;
99 for (size_t k = 0; k < xa.size(); ++k )
100 {
101 i = lower_bound(x.begin(), x.end(), xa[k]) - x.begin();
102 j = lower_bound(y.begin(), y.end(), ya[k]) - y.begin();
103 n = max(n, i), m = max(m, j);
104 A[i][j] = 1;
105 }
106
107 if ( n < M ) n++;
108 if ( m < M ) m++;
109 WriteMatr(A, n, m);
110 }
111
112 void WriteMatr(bool a[][DIM], int N, int M)
113 {
114 for ( int i = 1; i <= N; ++i )
115 {
116 for ( int j = 1; j <= M; ++j )
117 fout << a[i][j] << ’ ’;
118 fout << ’\n’;
119 }
120 }
24.2 qvect
Problema 2 - qvect 100 de puncte
Se consider N vectori cu elemente întregi, numerotaµi de la 1 la N , sortaµi cresc tor, ecare
vector având un num r precizat de elemente.
Cerinµe
S se r spund la Q întreb ri de tipul:
a) 1 i j
cu semnicaµia: care este minimul dintre modulele diferenµelor oric ror dou elemente, pri-
mul element aparµinând vectorului numerotat cu i, iar cel de al doilea element aparµinând
vectorului numerotat cu j ?
b) 2 i j
cu semnicaµia: care este valoarea ce se g se³te pe poziµia median în vectorul obµinut prin
interclasarea vectorilor având numerele de ordine i, i 1, ...,j (i $ j ).
Date de intrare
CAPITOLUL 24. ONI 2014 475
Fi³ierul de intrare qvect.in conµine pe prima linie dou numerele naturale N Q, separate
printr-un spaµiu, ce reprezint num rul de vectori, respectiv num rul de întreb ri.
Pe ecare dintre urm toarele N linii se g se³te descrierea unui vector sub forma: k a1 a2 ... ak ,
unde k reprezint num rul de elemente, iar a1 , ..., ak reprezint elementele vectorului, separate
prin câte un spaµiu.
Pe ecare dintre urm toarele Q linii se g se³te descrierea unei întreb ri sub forma unui triplet
de numere naturale: t i j , separate prin câte un spaµiu, unde t reprezint tipul întreb rii ³i poate
lua numai valorile 1 sau 2, iar i ³i j au semnicaµia precizat în cerinµ .
Date de ie³ire
Fi³ierul de ie³ire qvect.out va conµine Q numere întregi, câte unul pe linie, reprezentând în
ordine, r spunsurile la cele Q întreb ri.
Restricµii ³i preciz ri
a 1 & N, i, j & 100
a 1 & Q & 1 000
a 1 & t & 2
a 1 & k & 5 000
a -1 000 000 000 & a1 , a2 , ...ak & 1 000 000 000
a Prin valoarea aat pe poziµia median a unui vector a cu k elemente se înµelege valoarea
elementului situat pe poziµia [k/2], adic partea întreag a lui k / 2.
a 15% dintre teste vor conµine numai întreb ri de tipul 1
a 15% dintre teste vor conµine numai întreb ri de tipul 2
Exemple:
qvect.in qvect.out Explicaµii
3 3 13 Prima întrebare este de tipul 2. Vectorul nou obµinut prin
7 1 4 5 8 11 18 19 3 interclasarea vectorilor numerotaµi cu 2 ³i cu 3 este urm -
6 2 4 5 10 21 29 10 torul: 2, 4, 5, 10, 13, 14, 15, 15, 21, 29 ³i conµine 6+4=10
4 13 14 15 15 elemente, valoarea elementului median este 13.
2 23 A doua întrebare este de tipul 1. Diferenµa minim se
1 23 obµine pentru perechea (10,13), unde valoarea 10 aparµine
2 13 vectorului numerotat cu 2, iar valoarea 13 aparµine vecto-
rului numerotat cu 3.
A treia întrebare este de tipul 2. Poziµia median în vecto-
rul nou obµinut prin interclasare este (7+6+4)/2 = 8, deci
valoarea ce se g se³te pe poziµia median este 10.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 8 MB din care pentru stiv 2 MB
Dimensiune maxim a sursei: 15 KB
58 case 1: {
59 g << q1(x, y) << "\n";
60 break;
61 };
62 case 2: {
63 g << q2(x, y) << "\n";
64 break;
65 };
66 }
67 }
68 return 0;
69 }
61 }
62 d = val - 1;
63 }
64 else
65 s = val + 1;
66 }
67
68 return rez;
69 }
70
71 int main()
72 {
73 int n, q, op, i, j, x, y, m;
74
75 f >> n >> q;
76 for (i=1; i<=n; ++i)
77 {
78 f >> x;
79 a[i][0] = x;
80 nr[i] = nr[i-1] + x;
81 for (j=1; j<=x; ++j)
82 f>> a[i][j];
83 }
84
85 while ( q-- )
86 {
87 f >> op >> x >> y;
88 switch (op)
89 {
90 case 1:
91 {
92 g << q1(x, y) << "\n";
93 break;
94 };
95 case 2:
96 {
97 m = (nr[y] - nr[x-1]) / 2;
98 g << q2(x, y, m) << "\n";
99 break;
100 };
101 }
102 }
103
104 return 0;
105 }
28 }
29
30 return Min;
31 }
32
33 int q2(int x, int y, int p)
34 {
35 int i, j, s, d, val, nr, k, ok, nr0, rez, sol;
36 s = -inf, d = inf;
37 while ( s <= d )
38 {
39 val = (s + d) >> 1 ;
40 nr = 0; ok = 0;
41 for (k = x; k<=y; ++k)
42 {
43 i = 1; j = a[k][0];
44 nr0 = upper_bound(a[k] + 1, a[k] + j + 1, val) - a[k] - 1;
45 if (a[k][nr0] == val)
46 {
47 sol = val; ok = 1;
48 }
49
50 nr += nr0;
51 }
52
53 if (nr >= p)
54 {
55 if (ok)
56 {
57 rez = sol;
58 if (nr == p) return sol;
59 }
60 d = val - 1;
61 }
62 else
63 s = val + 1;
64 }
65
66 return rez;
67 }
68
69 int main()
70 {
71 int n, q, op, i, j, x, y, m;
72
73 freopen("qvect.in", "r", stdin);
74 freopen("qvect.out","w", stdout);
75
76 scanf("%d%d", &n, &q);
77 for (i=1; i<=n; ++i)
78 {
79 scanf("%d", &x);
80 a[i][0] = x;
81 nr[i] = nr[i-1] + x;
82 for (j=1; j<=x; ++j)
83 scanf("%d", &a[i][j]);
84 }
85
86 while ( q-- )
87 {
88 scanf("%d%d%d", &op, &x, &y);
89 switch (op)
90 {
91 case 1: {
92 printf("%d\n", q1(x, y));
93 break;
94 };
95 case 2: {
96 m = (nr[y] - nr[x-1]) >> 1;
97 printf("%d\n", q2(x, y, m));
98 break;
99 };
100 }
101 }
102
103 return 0;
CAPITOLUL 24. ONI 2014 480
104 }
72 if(b[i]<=a[p][j])
73 c[++n]=b[i++];
74 else
75 c[++n]=a[p][j++];
76
77 while(j<=a[p][0] && n<=nr)
78 c[++n]=a[p][j++];
79
80 while(i<=k && n<=nr)
81 c[++n]=b[i++];
82
83 for(i=1;i<=n;i++)
84 b[i]=c[i];
85
86 return n;
87 }
88
89 int cerinta2(int n1, int n2)
90 {
91 int i,j,nr=0,k;
92 for(i=n1;i<=n2;i++)nr+=a[i][0];
93 nr/=2;
94 k=min(nr,a[n1][0]);
95 for(i=1;i<=k;i++)
96 b[i]=a[n1][i];
97
98 for(i=n1+1;i<=n2;i++)
99 k=interc(k,i,nr);
100
101 return b[nr];
102 }
103
104 int main()
105 {
106 citeste();
107 int k,t,i,j;
108 for(k=1;k<=q;k++)
109 {
110 f>>t>>i>>j;
111 if(t==1)
112 g<<cerinta1(i,j)<<endl;
113 else
114 g<<cerinta2(i,j)<<endl;
115 }
116
117 return 0;
118 }
26
27 int cerinta1(int n1, int n2)
28 {
29 int i=1,j=1,m=0,nr1,nr2, dif=1000000005,x,y;
30 nr1=a[n1][0];
31 nr2=a[n2][0];
32 while(i<=nr1 && j<=nr2)
33 {
34 if(a[n1][i]<a[n2][j])
35 { x=a[n1][i];i++;
36 if(m==2)
37 dif=min(dif, abs(x-y));
38 m=1;
39 }
40 else
41 if(a[n1][i]>a[n2][j])
42 {
43 y=a[n2][j];j++;
44 if(m==1)
45 dif=min(dif, abs(x-y));
46 m=2;
47 }
48 else
49 if(a[n1][i]==a[n2][j])
50 return 0;
51 }
52
53 if(i<=nr1)
54 {
55 if(m==2)
56 dif=min(dif, abs(a[n1][i]-y));
57 }
58 else
59 {
60 if(m==1)
61 dif=min(dif, abs(x-a[n2][j]));
62 }
63
64 return dif;
65 }
66
67 int minim(int n1, int n2)
68 {
69 int p=0,i, mi=1000000005,j,k;
70
71 for(i=n1;i<=n2;i++)
72 {
73 j=poz[i];
74 if(j<=a[i][0] && a[i][j]<mi)
75 {
76 mi=a[i][j];
77 p=i;
78 }
79 }
80
81 poz[p]++;
82 return mi;
83 }
84
85 int cerinta2(int n1, int n2)
86 {
87 int i,med,nr=0;
88 for(i=1;i<=n;i++)
89 poz[i]=1;
90
91 for(i=n1;i<=n2;i++)
92 nr+=a[i][0];
93
94 nr/=2;
95 for(i=1;i<=nr;i++)
96 med=minim(n1,n2);
97
98 return med;
99 }
100
101 int main()
CAPITOLUL 24. ONI 2014 483
102 {
103 citeste();
104
105 int k,t,i,j;
106
107 for(k=1;k<=q;k++)
108 {
109 f>>t>>i>>j;
110 if(t==1)
111 g<<cerinta1(i,j)<<endl;
112 else
113 g<<cerinta2(i,j)<<endl;
114 }
115
116 return 0;
117 }
57 }
58
59 if(i<=nr1)
60 {
61 if(m==2)
62 dif=min(dif, abs(a[n1][i]-y));
63 }
64 else
65 {
66 if(m==1)
67 dif=min(dif, abs(x-a[n2][j]));
68 }
69
70 return dif;
71 }
72
73 int cerinta2(int n1, int n2)
74 {
75 int i,j,nr=0,k;
76 for(i=n1;i<=n2;i++)
77 nr+=a[i][0];
78
79 nr/=2;
80 k=min(nr,a[n1][0]);
81 for(i=1;i<=k;i++)
82 b[i]=a[n1][i];
83
84 for(i=n1+1;i<=n2;i++)
85 {
86 for(j=1;j<=a[i][0] && j<=nr;j++)
87 b[++k]=a[i][j];
88
89 sort(b+1,b+k+1);
90 k=min(k,nr);
91 }
92
93 return b[k];
94 }
95
96 int main()
97 {
98 citeste();
99 int k,t,i,j;
100 for(k=1;k<=q;k++)
101 {
102 f>>t>>i>>j;
103 if(t==1)
104 g<<cerinta1(i,j)<<endl;
105 else
106 g<<cerinta2(i,j)<<endl;
107 }
108
109 return 0;
110 }
19
20 poz[i]=1;
21 }
22 }
23
24 int abs(int x)
25 {
26 return max(x,-x);
27 }
28
29 int cerinta1(int n1, int n2)
30 {
31 int i=1,j=1,m=0,nr1,nr2, dif=1000000005,x,y;
32 nr1=a[n1][0];
33 nr2=a[n2][0];
34
35 while(i<=nr1 && j<=nr2)
36 {
37 if(a[n1][i]<a[n2][j])
38 {
39 x=a[n1][i];i++;
40 if(m==2)
41 dif=min(dif, abs(x-y));
42 m=1;
43 }
44 else
45 if(a[n1][i]>a[n2][j])
46 {
47 y=a[n2][j];
48 j++;
49 if(m==1)
50 dif=min(dif, abs(x-y));
51 m=2;
52 }
53 else
54 if(a[n1][i]==a[n2][j])
55 return 0;
56 }
57
58 if(i<=nr1)
59 {
60 if(m==2)
61 dif=min(dif, abs(a[n1][i]-y));
62 }
63 else
64 {
65 if(m==1)
66 dif=min(dif, abs(x-a[n2][j]));
67 }
68
69 return dif;
70 }
71
72
73 int cerinta2(int n1, int n2)
74 {
75 int i,j,nr=0,k;
76 for(i=n1;i<=n2;i++)
77 nr+=a[i][0];
78
79 nr/=2;
80 k=min(nr,a[n1][0]);
81 for(i=1;i<=k;i++)
82 b[i]=a[n1][i];
83
84 for(i=n1+1;i<=n2;i++)
85 {
86 for(j=1;j<=a[i][0] && j<=nr;j++)
87 b[++k]=a[i][j];
88
89 sort(b+1,b+k+1);
90 k=min(k,nr);
91 }
92
93 return b[k];
94 }
CAPITOLUL 24. ONI 2014 486
95
96 int main()
97 {
98 citeste();
99 freopen("qvect.out","w", stdout);
100 int k,t,i,j;
101
102 for(k=1;k<=q;k++)
103 {
104 scanf("%d%d%d", &t, &i, &j);
105 if(t==1)
106 printf("%d\n",cerinta1(i,j));
107 else
108 printf("%d\n",cerinta2(i,j));
109 }
110
111 return 0;
112 }
55
56 int cautbin2(int i, int v)
57 {
58 int p,q,m,r;
59 p=1;
60 q=b[i];
61 r=-1;
62 while(p<=q && r==-1)
63 {
64 m=p+(q-p)/2;
65 if(v==a[i][m])
66 return m;
67
68 if(v<a[i][m])
69 q=m-1;
70 else
71 p=m+1;
72 }
73
74 return -1;
75 }
76
77 void sortare()
78 {
79 int i,j,k,p,q,r,s,ok;
80
81 //sterg elementele suplimentare
82 k=1;
83 for (i=2;i<=n;i++)
84 {
85 if(v[k]!=v[i])
86 v[++k]=v[i];
87 }
88
89 n=k;
90 ok=0;
91 while(ok==0)
92 {
93 r=0;
94 s=0;
95 do
96 {
97 p=r+1;
98 q=p;
99 while(q+1<=n && v[q]<=v[q+1])
100 q++;
101
102 s++;
103 r=q+1;
104 while(r+1<=n && v[r]<=v[r+1])
105 r++;
106
107 if(p<=q && q<r && r<=n)
108 {
109 s++;
110 i=p;
111 j=q+1;
112 k=0;
113 while(i<=q && j<=r)
114 {
115 if(v[i]<v[j])
116 w[++k]=v[i++];
117 else
118 w[++k]=v[j++];
119 }
120
121 while(i<=q)
122 w[++k]=v[i++];
123
124 while(j<=r)
125 w[++k]=v[j++];
126
127 i=p;
128 for(j=1;j<=k;j++)
129 v[i++]=w[j];
130 }
CAPITOLUL 24. ONI 2014 488
131 } while(r<n);
132
133 if(s==1) ok=1;
134 }
135
136 //sterg elementele suplimentare
137 k=1;
138 for (i=2;i<=n;i++)
139 {
140 if(v[k]!=v[i])
141 v[++k]=v[i];
142 }
143 n=k;
144 }
145
146 int mmse(int i1, int j1, int v)
147 {
148 //aflam fata de cate valori din secventa i1..j1 este v mai mare sau egala
149 int s,i;
150 s=0;
151 for(i=i1;i<=j1;i++)
152 {
153 if(a[i][b[i]]<=v)
154 s=s+b[i];
155 else
156 if(a[i][1]<=v)
157 s=s+cautbin(i,v);
158 }
159
160 return s;
161 }
162
163 int exista(int i1, int j1, int v)
164 {
165 int s,i;
166 for(i=i1;i<=j1;i++)
167 {
168 if(a[i][1]<=v && v<=a[i][b[i]])
169 {
170 s=cautbin2(i,v);
171 if(s!=-1) return 1;
172 }
173 }
174
175 return -1;
176 }
177
178 int mediana(int i1, int j1)
179 {
180 int p,q,m,s,nr;
181 nr=0;
182 for(p=i1;p<=j1;p++)
183 nr=nr+b[p];
184
185 p=1;
186 q=n;
187 while(p<=q)
188 {
189 m=p+(q-p)/2;
190 s=mmse(i1,j1,v[m]);
191 if(s<nr/2)
192 p=m+1;
193 else
194 q=m-1;
195 }
196
197 while(exista(i1,j1,v[p])==0)
198 p++;
199
200 return v[p];
201 }
202
203 int main()
204 {
205 int i,j,t,i1,j1;
206 fin>>N>>Q;
CAPITOLUL 24. ONI 2014 489
207 n=0;
208 for (i=1;i<=N;i++)
209 {
210 fin>>b[i];
211 for (j=1;j<=b[i];j++)
212 {
213 fin>>a[i][j];
214 n++;
215 v[n]=a[i][j];
216 }
217 }
218
219 sortare();
220
221 for (i=1;i<=Q;i++)
222 {
223 fin>>t>>i1>>j1;
224 if(t==1)
225 fout<<dif_min(i1,j1);
226 else
227 fout<<mediana(i1,j1);
228
229 fout<<"\n";
230 }
231
232 fout.close();
233 fin.close();
234 return 0;
235 }
24.3 tg
Problema 3 - tg 100 de puncte
Fie un num r natural N . Spunem c a, b, c este un triplet geometric
Ó
limitat de N , dac a, b
³i c sunt trei numere naturale astfel încât 1 & a $ b $ c & N ³i b a c.
Cerinµe
S se determine num rul tripletelor geometrice limitate de num rul natural N .
Date de intrare
Fi³ierul de intrare tg.in conµine pe prima linie un num r natural N .
Date de ie³ire
În ³ierul de ie³ire tg.out se va scrie num rul tripletelor geometrice limitate de N .
Restricµii ³i preciz ri
a 4&N & 4 000 000
Exemple:
tg.in tg.out Explicaµii
8 2 Cele dou triplete sunt 1, 2, 4 ³i 2, 4, 8
Timp maxim de executare/test: 0.1 secunde
Memorie: total 32 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 5 KB
Complexitate O N N
Pentru ecare a din mulµimea r1, 2, ..., N 2x ³i pentru ecare c din mulµimea a 2, a 3, ..., N
se veric dac a c este p trat perfect ³i în caz armativ se calculeaz b sqrt a c ³i se
contorizeaz rezultatul.
Complexitate O N sqrt N
Pentru ecare a din mulµimea 1, 2, ..., N 2 se observ c dac ar exista tripletul a, b, c atunci
ar trebui s avem c b b©a, deci b b ar trebui s e multiplu al lui a ³i în acela³i timp ar trebui
s e p trat perfect, iar b % a.
Ne-ar ajuta astfel s ³tim care este cel mai mic p trat perfect multiplu al lui a. Fie a1 acest
num r. Am avea a1 a x, unde x este cel mai mic posibil astfel incat a1 s e p trat perfect.
e e e f f f
Dac a p11 p22 ... pkk , atunci x p11 p22 ... pkk unde fi ei mod 2 , adic x este
produsul factorilor primi care apar la puteri impare în descompunerea lui a.
Se mai observ apoi c orice alt multiplu al lui a care este si p trat perfect va de forma
a2 a x k , unde k ' 1. Pentru k 1 se obtine a1 . Deoarece trebuie s avem b Õb % a a,
2
atunci patratele perfecte care ne intereseaz pentru obµinerea lui c se obµin pentru k % xa . Astfel
Ó Õ
a x k si c b b©a x k . Deoarece c & N vom avea k & N
2
putem determina b x
.
ÕCu alte cuvinte
Õ pentru ecare
Õ a din mulµimea r1, 2, ..., N 2x vom parcurge k din mulµimea
r x 1 , x 2 , ..., x x ³i astfel vom obµine toate tripletele geometrice c utate, care sunt
a a a
Ó 2
de forma ( a, b a x k , c x k ).
Pentru determinarea lui x putem folosi algoritmul de descompunere în factori primi O sqrt a.
Complexitate O N
Ideea de rezolvare este asem natoare cu cea anterioar . Se incearc diminuarea efortului de
calculare la ecare pas a lui x prin construirea vectorului xi = cel mai mic numar natural care
înmulµit cu i produce un p trat perfect, adic vom avea i xi cel mai mic patrat perfect multiplu
al lui i.
Se procedeaz asem n tor cu algoritmul Ciurul lui Eratostene. Se iniµializeaz xi cu 0 ³i
se parcurge în ordinea 1, 2, 3, ..., N . Daca avem xi 0 atunci vom marca xi j j i pentru
toti 1 & i j j & N .
25 fin.close();
26 fout.close();
27 }
27 x=v[a];
28 k1=sqrt(a/x);
29 k2=sqrt(n/x);
30 s=s+k2-k1;
31 }
32
33 fout<<s<<endl;
34 fout.close();
35 fin.close();
36 return 0;
37 }
18 t=a;
19 d=2;
20 while(d*d<=t)
21 {
22 c=0;
23 while(t%d==0)
24 {
25 c++;
26 t=t/d;
27 }
28 if(c%2==1) x=x*d;
29 d++;
30 }
31
32 if(t>1) x=x*t;
33 k1=sqrt(a/x);
34 k2=sqrt(n/x);
35 s=s+k2-k1;
36 }
37
38 fout<<s<<endl;
39 fout.close();
40 fin.close();
41 return 0;
42 }
24.4 progresie
Problema 4 - progresie 100 de puncte
Cerinµe
S se determine un ³ir strict Ócresc tor, cu lungimea N , format din numere naturale nenule,
1 & a1 $ a2 $ a3 $ ... $ aN & 2N N , cu proprietatea c oricare trei termeni distincµi ai ³irului nu
sunt în progresie aritmetic , adic pentru oricare numere naturale i, j ³i k cu 1 & i $ j $ k & N ,
este îndeplinit condiµia: ai ak j 2 aj . Prin x s-a notat partea întreag a lui x.
De Ó
exemplu, pentru N 5, cel mai mare termen al ³irului va trebui s e mai mic sau egal cu
2 5 5% adic aN & 22, deci o soluµie este: 1, 2, 4, 5, 10.
Date de intrare
Fi³ierul de intrare progresie.in conµine pe primul rând num rul natural N cu semnicaµia de
mai sus.
Date de ie³ire
În ³ierul de ie³ire progresie.out se vor scrie pe primul rând, desp rµite prin câte un spaµiu,
cele N elemente ale ³irului ai , 1 & i & N .
Restricµii ³i preciz ri
a 3 & N & 20 000
a Dac soluµia nu este unic , se va accepta orice soluµie corect .
Exemple:
progresie.in progresie.out Explicaµii
5 1 2 4 5 10 N 5; aN & 22;
Un ³ir strict cresc tor format din 5 numere naturale
nenule cu proprietatea c oricare 3 termeni ai s i nu
sunt în progresie aritmetic este: 1, 2, 4, 5, 10
7 3 5 6 11 12 14 15 N 7; aN & 37;
Un ³ir strict cresc tor format din 7 numere naturale
nenule cu proprietatea c oricare 3 termeni ai s i nu
sunt în progresie aritmetic este: 3, 5, 6, 11, 12, 14, 15
Timp maxim de executare/test: 0.1 secunde
Memorie: total 32 MB din care pentru stiv 16 MB
Dimensiune maxim a sursei: 5 KB
CAPITOLUL 24. ONI 2014 494
Varianta 1
Aceast soluµie utilizeaz un algoritm asem n tor cu algoritmul lui Eratostene de determinare
a numerelor prime. Se utilizeaz un vector care iniµial pe toate poziµiile este iniµializat cu 1 ³i apoi
începând cu a doua poziµie se elimin din acest ³ir toate poziµiile obµinute cu formula 2*poziµia
curent - i unde i ia toate valorile anterioare poziµiei curente. Se avanseaz apoi în ³ir pân la
prima valoare nenul . Soluµia are un ordin de complexitate O n log n ³i obµine aproximativ
30% din punctaj.
Varianta 2
Fie Tn mulµimea tuturor întregilor nenegativi a c ror scriere în baza 3 conµine cel mult n cifre,
toate ind diferite de cifra 2.
Num rul de elemente din Tn este 2n deoarece elementele lui Tn sunt n-uple formate din 0 ³i 1,
iar cel mai mare întreg din Tn este 111....11 = (3n - 1)/2. Tn nu va conµine trei numere distincte
în progresie aritmetic deoarece dac x, y, z " Tn 2y x z , num rul 2y conµine numai cifrele 0
³i 2 în reprezentarea sa în baza trei. Rezult c x y z , µinând seama de algoritmul de adunare
în baza trei, ceea ce contrazice ipoteza. Soluµia obµine aproximativ 50% din punctaj.
Varianta 3
Soluµia are la baz un mecanism constructiv, observând c din prima stare notat S1 r1, 2x
se poate trece în starea urm toare reunind elementele lui S1 cu elementele lui S1 adunate cu prima
putere a lui 3. Se obµine astfel S2 r1, 2, 4, 5x. Apoi se obµine S3 r1, 2, 4, 5, 10, 11, 13, 14x. Se
continu mecanismul atât timp cât valorile din starea curent sunt mai mici sau egale cu N . Se
poate demonstra prin inducµie matematic c acest algoritm conduce la mulµimi cu proprietatea
cerut de problem . Ordinul de complexitate al acestei soluµii este O n ³i obµine punctaj maxim.
Varianta 4 prof. Eugen Nodea - Colegiul Naµional Tudor Vladimirescu Tg. Jiu
Se poate construi un ³ir care respect cerinµele folosind relaµia de recurenµ :
a[2*i] = 3 * a[i] - 2
a[2*i+1] = 3 * a[i] - 1, i=0, ..., N, cu a[0] = 1
Complexitate : O N
Varianta 5 prof. Piµ-Rada Ionel-Vasile, Colegiu Naµional Traian Drobeta Turnu - Severin
Se construie³te ³irul v[1], v[2], ..., v[N-1], format din numere naturale nenule cu proprietatea
c
(*) oricare dou secvenµe adiacente din ³irul v[] au sume diferite, astfel:
- primii trei termeni sunt 1, 2, 1
- al patrulea termen nu poate 1, 2, 3, 4 deci va aleas valoarea 5, apoi pentru termenii
cinci, ³ase ³i ³apte se pot alege valorile 1, 2, 1 ³i se obµine ³irul cu ³apte termeni 1, 2, 1, 5, 1, 2, 1
- al optulea termen nu poate dintre 1, 2, 3, ...,13 ³i se va alege valoarea 14, apoi iara³i se pot
completa urm torii ³apte termeni egali cu primii ³apte termeni ³i se obtine un ³ir cu 15 termeni
1, 2, 1, 5, 1, 2, 1, 14, 1, 2, 1, 5, 1, 2, 1
p
- apare astfel ideea de a construi un ³ir care pe poziµiile i egale cu puteri ale lui doi, i 2 , s
aib valoarea egal cu suma termenilor anteriori plus 1,
v[i] = 1 +v[1] + v[2] + ... + v[i-1],
apoi urm torii i 1 termeni vor ale³i identici cu primii obµinându-se un ³ir cu 2 i 1 termeni
³i procesul va repetat.
irul cerut de problem se va obµine prin a[1]=1 ³i a[k+1]=a[k]+v[k], pentru 1 & k $ N .
Din ³irul 1, 2, 1, 5, 1, 2, 1, 14, 1, 2, 1, 5, 1, 2, 1 se va obµine ³irul 1, 2, 4, 5, 10, 11, 13, 14, 28,
29, 31, 32, 37, 38, 40, 41, ...
Algoritmul permite implementare cu complexitatea O N .
21
22 f>>n;
23
24 a[1]=1;a[2]=2;k=2;
25
26 i=1;
27 un=0;
28 p=3;
29 while (!un)
30 {
31 t=k;
32 for(j=1;j<=k;j++)
33 {
34 x=a[j]+p;
35 if (x<=3*n*sqrt(n)) a[++t]=x;
36 else un=1;
37
38 }
39
40 if (!un)
41 k=2*k;
42 else
43 k=t;
44 i++;
45 p=p*3;
46 }
47 // cout << t ;
48
49 for(i=1;i<=n;i++)
50 g<<a[i]<<" ";
51
52 g<<"\n";
53 f.close();
54 g.close();
55 return 0;
56 }
1 # include <cstdio>
2 # include <cmath>
3 using namespace std;
4
5 int N, K, i;
6 int a[100003];
7
8 int main()
9 {
10 freopen("progresie.in", "r", stdin);
11 freopen("progresie.out","w",stdout);
12
13 scanf("%d", &N);
14
15 a[0] = 1;
16 for (i=0; i<=N; ++i)
17 {
18 a[2*i] = 3 * a[i] - 2;
19 a[2*i+1] = 3 * a[i] - 1;
20 }
21
22 for (i=0; i<N; ++i)
23 printf("%d ", a[i]);
24
25 return 0;
26 }
1 #include <stdio.h>
2 #include <math.h>
3
4 #define NMax 10002
5
6 int N, Limit;
7 bool b[2 * NMax * NMax];
8 int sol[NMax];
9
10 bool bkt( int x, int val )
11 {
12 if ( x == N + 1 )
13 return true;
14
15 for ( int v = val; v <= Limit; ++ v )
16 if ( b[v]==false )
17 {
18 for ( int i = 1; i < x; ++ i)
19 b[ 2 * v - sol[i] ]=true;
20
21 sol[x] = v;
22
23 if ( bkt( x + 1, v + 1) )
24 return true;
25
26 for ( int i = 1; i < x; ++ i)
27 b[ 2 * v - sol[i] ]=false;
28 }
29
30 return false;
31 }
32
33 int main()
34 {
35 freopen("progresie.in", "r", stdin);
36 freopen("progresie.out", "w", stdout);
37
38 scanf("%d", &N);
39 Limit = 2 * N * sqrt(N);
40 if ( bkt( 1, 1 ) )
41 {
42 for ( int i = 1; i <= N; ++ i)
43 printf("%d ", sol[i]);
44
45 printf("\n");
46 }
47 else
48 return 0;
49 }
24.5 reex
Problema 5 - reex 100 de puncte
La un concurs de robotic , în timpul prezent rii, un roboµel cu corp cilindric cu diametrul de
o unitate scap de sub control ³i se deplaseaz într-un ring de form dreptunghiular . Ringul este
împ rµit în N M p trate identice, cu latura de o unitate, a³ezate pe N linii ³i M coloane.
Robotul poate p r si ringul numai pe la colµuri, acestea
ind numerotate de la 1 la 4, colµul cu num rul 1 ind cel din
stânga jos apoi restul ind numerotate în sens trigonometric.
Suprafaµa ringului este delimitat de exterior prin intermediul
a patru pereµi desp rµitori: doi pereµi verticali (a³ezaµi de
la colµul 1 la colµul 4, respectiv de la colµul 2 la colµul 3) ³i doi
pereµi orizontali (a³ezaµi de la colµul 1 la colµul 2, respectiv
de la colµul 3 la colµul 4), f r a bloca ie³irile, ca în desenul al turat.
Robotul p trunde în ring prin colµul cu num rul 1 sub un unghi de 45 grade ³i cu o vitez de
un p trat/s.
Ciocnirile cu pereµii sunt considerate perfect elastice (robotul nu-³i pierde din vitez ) iar un-
ghiul de incidenµ este egal cu cel de reexie.
CAPITOLUL 24. ONI 2014 499
Cerinµe
Se cere s se determine:
a) dup câte secunde ³i prin ce colµ al ringului va ie³i robotul;
b) de câte ori se ciocne³te robotul de pereµii orizontali ³i verticali, rezultând o schimbare de
direcµie, pân la ie³irea din ring.
Date de intrare
Fi³ierul de intrare reex.in conµine pe prima linie dou numere naturale N ³i M , separate
printr-un singur spaµiu.
Date de ie³ire
Fi³ierul de ie³ire reex.out va conµine pe prima linie dou numere naturale S ³i C , separate
printr-un singur spaµiu, S reprezentând num rul de secunde dup care robotul va ie³i din ring, iar
C reprezint num rul colµului prin care acesta va ie³i. Pe a doua linie, ³ierul de ie³ire va conµine
dou numere naturale H ³i V , separate printr-un spaµiu, H reprezentând num rul de ciocniri cu
pereµii orizontali ai ringului, iar V num rul de ciocniri cu pereµii verticali.
Restricµii ³i preciz ri
a 3 & N, M & 2 000 000 000
a Pentru rezolvarea corect a unei singure cerinµe se acord 50% din punctaj, iar pentru
rezolvarea corect a ambelor cerinµe se acord 100% din punctaj.
Exemple:
reex.in reex.out Explicaµii
36 11 4 4 1
Pân la ie³ire se parcurg 11 p trate,
ie³irea se produce pe la colµul 4. Se
produc 4 ciocniri cu pereµii orizontali
³i o ciocnire cu pereµii verticali.
57 13 4 2 1
Se parcurg 13 p trate, ie³irea se face
la colµul 4 ³i de produc 2 ciocniri cu
pereµii orizontali (în punctele a ³i c
respectiv o ciocnire cu pereµii verti-
cali în punctul b).
Soluµia 1 - 40 de puncte
Se simuleaz deplasarea robutului din p trat în p trat pe diagonal (x x 1 ³i y z 1),
se veric ciocnirea cu un petete orizontal (y 1 sau y N ) sau cu un perete vertical (x 1 sau
x M ). Se veric dac s-a ajuns într-un colµ astfel:
- Colµul 1 (stânga jos) cu x 1 ³i y 1;
- Colµul 2 (dreapta jos) cu x M ³i y 1;
- Colµul 3 (dreapta sus) cu x M ³i y N ;
- Colµul 4 (stânga sus) cu x 1 ³i y N ;
CAPITOLUL 24. ONI 2014 500
În urma ec rei ciocniri se schimba direcµia de deplasare pe axa x sau y , în funcµie de peretele
ciocnit.
Pentru rezolvarea cerinµei 1) se num r p traµelele parcurse p na se ajunge într-un colµ, viteza
ind de un p trat/s, timpul în secunde coincide cu num rul de p trate parcurse.
În cazul unei ciocniri cu un perete se num r aceast ciocnire în funtie de perete (orizontal
sau vertical).
Soluµia 2 - 68 de puncte
Se simuleaz deplasarea robotului din perete în perete ³i se înâlnesc dou situaµii:
- se poate face un salt pe x ³i y cu min N, M (N -lungimea ³i M -l µimea ringului);
- se produce o ciocnire înainte de a parcurge o distanµ egal cu min N, M , situaµie în care
incrementarea se face f r dep ³irea lui N ³i M sau 1.
în acest caz timpul (nr. de p trate parcurse) se poate calcula mai simplu dup relaµia:
S V M 1, în care S - nr. de secunde, V - nr. de ciocniri cu pereµii verticali, M - lungimea
ringului.
Solutia 3 - 100 de puncte
Dac se analizeaz parcursul robotului desf ³urat (vezi imaginea de mai jos) ³i se noteaz
n N 1 ³i m M 1 se poate observa c num rul de ciocniri cu pereµii orizontali H , respectiv
num rul de ciocniri cu pereµii verticali V sunt daµi de relaµiile:
H N ©cmmdc N, M ³i V M ©cmmdc N, M în care cu cmmdc N, M s-a notat cel mai
mare divizor comun al lui N ³i M .
Nr. de p trate parcurse ³i implicit timpul în secunde se poate calcual ca S cmmmc N, M 1.
Colµul în care se produce ie³irea se poate determina din nr. de ciocniri cu pereµii orizontali ³i
verticali astfel:
- pt. num r impar de ciocniri cu pereµii orizontali se poate ie³i pe latura de sus adic colµurile
3 sau 4.
- pt. V par singura posibilitate de ie³ire este colµul 2 (pe latura de jos);
- pt. H impar ie³irea se va face pe latura din dreapta, colµurile 2 sau 3;
- pt. H par ie³irea se face pe latura sin stânga singura posibilitate ind colµul 4 .
Colµul exact se determin prin combinarea posibilit tilor rezultate în funtie de paritatea lui H
³i V .
10 int main()
11 {
12 f >> n >> m;
13 --n, --m;
14
15 //cmmdc
16 a = n;
17 b = m;
18 while(b)
19 {
20 r = a % b;
21 a = b; b = r;
22 }
23
24 //cmmmc
25 cmmmc = n * m / a;
26
27 v = n / a;
28 h = m / a;
29 c = 1;
30 if (v % 2 == 0)
31 c = 4;
32 else
33 if (h % 2 == 0)
34 c = 2;
35 else
36 c = 3;
37
38 g << cmmmc + 1 << " " << c << "\n";
39 g << h - 1 << " " << v - 1 << "\n";
40 return 0;
41 }
41 x++;
42 b.x+=dx;
43 b.y+=dy;
44 //cout << "B("<<b.y<<"."<<b.x<<")\n ";
45 if (b.x == m) {dx= -1; E++;} //lat E
46 if (b.y == n) {dy= -1; N++;} //lat N
47 if (b.x == 1) {dx = 1; W++;} //lat W
48 if (b.y == 1) {dy = 1; S++;} //lat S
49 if ((b.x==c1.x) && (b.y==c1.y)) {colt=1; S--; W--;}
50 if ((b.x==c2.x) && (b.y==c2.y)) {colt=2; S--; E--;}
51 if ((b.x==c3.x) && (b.y==c3.y)) {colt=3; N--; E--;}
52 if ((b.x==c4.x) && (b.y==c4.y)) {colt=4; N--; W--;}
53
54 } while (!colt);
55
56 outFile << x << " " << colt << "\n";
57 outFile << N + S << " " << E + W << "\n";
58
59 inFile.close();
60 outFile.close();
61 return 0;
62 }
51 s = s * M + 1;
52
53 outFile << s << " " << colt << "\n";
54 outFile << nh -1 << " " << nl -1 << "\n";
55
56 inFile.close();
57 outFile.close();
58 return 0;
59 }
64 if (dx > 0)
65 b.x+=n-b.y;
66 else
67 b.x-=n-b.y;
68
69 b.y=n;
70 }
71 else
72 if (b.x+dx < 1)
73 {
74 if (dy > 0)
75 b.y+=b.x-1;
76 else
77 b.y-=b.x-1;
78
79 b.x=1;
80 }
81 else
82 if (b.y+dy < 1)
83 {
84 if (dx > 0)
85 b.x+=b.y-1;
86 else
87 b.x-=b.y-1;
88
89 b.y=1;
90 }
91 }
92
93 //cout << "B("<<b.y<<"."<<b.x<<")\n ";
94 //cin >> ch;
95 if (b.x == m) {dx= -dx; E++; s+=m-1;} //lat E
96 if (b.y == n) {dy= -dy; N++;} //lat N
97 if (b.x == 1) {dx = -dx; W++; s+=m-1;} //lat W
98 if (b.y == 1) {dy = -dy; S++;} //lat S
99 if ((b.x==c1.x) && (b.y==c1.y)) {colt=1; S--; W--;}
100 if ((b.x==c2.x) && (b.y==c2.y)) {colt=2; S--; E--;}
101 if ((b.x==c3.x) && (b.y==c3.y)) {colt=3; N--; E--;}
102 if ((b.x==c4.x) && (b.y==c4.y)) {colt=4; N--; W--;}
103 } while (!colt);
104
105 outFile << s << " " << colt << "\n";
106 outFile << N + S << " " << E +W << "\n";
107
108 inFile.close();
109 outFile.close();
110 return 0;
111 }
25 ifstream inFile;
26 ofstream outFile;
27
28 // citire date din fis
29 inFile.open("reflex.in");
30 outFile.open("reflex.out");
31 inFile >> n >> m;
32
33 N=n-1;
34 M=m-1;
35 CMMDC=cmmdc(N,M);
36 // CMMMC = N * M / CMMDC;
37 nl=N/CMMDC;
38 nh=M/CMMDC;
39 if (nl%2==0)
40 colt=4;
41 else
42 if (nh%2==0)
43 colt=2;
44 else
45 colt=3;
46
47 s = nl;
48 s = s * M + 1;
49
50 outFile << s << " " << colt << "\n";
51 outFile << nh -1 << " " << nl -1 << "\n";
52
53 inFile.close();
54 outFile.close();
55 return 0;
56 }
41 else
42 if (nh%2==0)
43 colt=2;
44 else
45 colt=3;
46
47 s = nl;
48 s = s * M + 1;
49
50 outFile << s << " " << colt << "\n";
51 outFile << nh -1 << " " << nl -1 << "\n";
52
53 inFile.close();
54 outFile.close();
55 return 0;
56 }
24.6 traseu
Problema 6 - traseu 100 de puncte
într-un ora³ exist un hotel de form cubic , cu N etaje, nu-
merotate de la 1 la N . Suprafaµa ec rui etaj K (1 & K & N )
este p tratic ³i este împ rµit în N N camere identice al turate,
dispuse pe N linii ³i N coloane, ecare camer având drept eti-
chet un triplet de numere naturale KLC (K =etajul, L=linia,
C =coloana, 1 & L, C & N ), ca în imaginea al turat .
Dintre cele N N N camere ale hotelului, una este special
deoarece în ea locuie³te de mult timp un ³oricel. Fiind isteµ, el ³tie
eticheta camerei în care se a precum ³i eticheta camerei în care
buc tarul hotelului depoziteaz alimente.
Studiind hotelul, ³oricelul a constatat c pe ecare etaj, din orice camer poate intra în toate
camerele care au un perete comun cu aceasta (existând un mic oriciu pentru aerisire).
De asemenea, ³oricelul a constatat c din ecare camer (situat la etajele 2, 3,
..., sau N 1) poate intra în camera situat imediat deasupra ei ³i în camera situat
imediat sub ea.
Fiind un ³oricel binecrescut, el nu intr în nicio camer ocupat de clienµi ca s
nu-i deranjeze.
Hotelul având mulµi clienµi, ³oricelul trebuie s -³i g seasc cel mai scurt traseu de
la camera lui la camera cu alimente, traseu care s treac printr-un num r minim de
camere, toate neocupate.
Cerinµe
Se cere s se determine:
a) num rul de camere prin care trece cel mai scurt traseu al ³oricelului de la camera lui la
camera cu alimente (inclusiv camera lui ³i camera cu alimente);
b) etichetele camerelor prin care trece traseul determinat la punctul a).
Date de intrare
Fi³ierul traseu.in conµine:
a pe prima linie, dou numere naturale N ³i M separate printr-un spaµiu, N cu semnicaµia
din enunµ iar M reprezentând num rul de camere ocupate de clienµii hotelului;
a pe a doua linie, trei numere naturale K1 L1 C1, separate prin câte un spaµiu, reprezentând
eticheta camerei în care se a ³oricelul;
a pe a treia linie, trei numere naturale K2 L2 C2, separate prin câte un spaµiu, reprezentând
eticheta camerei în care sunt depozitate alimentele;
a pe ecare dintre urm toarele M linii, câte trei numere naturale X Y Z , separate prin câte
un spaµiu, reprezentând etichetele celor M camere ocupate de clienµi.
Date de ie³ire
CAPITOLUL 24. ONI 2014 507
Restricµii ³i preciz ri
a 2 & N & 100; 1 & M & 5000 ³i M $ N N 2
a oricelul nu intr decât în camere neocupate de clienµi.
a Camera ³oricelului este o camer neocupat de clienµi.
a Dac exist mai multe trasee ale ³oricelului de la camera lui la camera de alimente care trec
prin exact T camere, atunci traseul a³at va cel mai mic traseu din punct de vedere lexicograc.
a Eticheta (X1 Y1 Z1 ) se consider strict mai mic în sens lexicograc ca eticheta (X2 Y2 Z2 )
dac este satisf cut doar una dintre condiµiile:
1) X1 $ X2 2) X1 X2 ³i Y1 $ Y2 3) X1 X2 ³i Y1 Y2 ³i Z 1 $ Z2
a Eticheta X1 Y1 Z1 se consider egal cu eticheta X2 Y2 Z2 dac X1 X2 ³i Y1 Y2 ³i
Z1 Z2 . Vom scrie egalitatea lor astfel: (X1 Y1 Z1 ) = (X2 Y2 Z2 ).
a Traseul ce trece (în aceast ordine) prin camerele cu etichetele (X1 Y1 Z1 ), (X2 Y2 Z2 ), ...,
(XT YT ZT ) este mai mic din punct de vedere lexicograc decât traseul (A1 B1 C1 ), (A2 B2 C2 ),
..., (AT BT CT ) dac exist un indice J (1 & J & T ) astfel încât (X1 Y1 Z1 ) = (A1 B1 C1 ), (X2
Y2 Z2 ) = (A2 B2 C2 ), ..., (XJ 1 YJ 1 ZJ 1 ) = (AJ 1 BJ 1 CJ 1 ) iar eticheta (XJ YJ ZJ ) este
strict mai mic decât eticheta (AJ BJ CJ ).
a Se acord : 40% din punctaj pentru determinarea corect a num rului T ³i 100% din punctaj
pentru rezolvarea corect a ambelor cerinµe.
a Se garanteaz c exist soluµie pentru ambele cerinµe, pentru toate datele de test.
Exemple:
traseu.in traseu.out Explicaµii
3 4 7 Hotelul are trei etaje (1,2 ³i 3). Pe ecare etaj sunt 3*3 camere.
1 1 1 1 1 1 ³oricelul se a în camera cu eticheta 1 1 1 iar camera cu alimente
3 3 3 1 1 2 are eticheta 3 3 3.
3 3 1 1 1 3 Sunt 4 camere ocupate de cli-
2 1 1 1 2 3 enµi. Acestea au etichetele : 3
3 1 1 1 3 3 3 1, 2 1 1, 3 1 1, 3 1 3.
3 1 3 2 3 3 Traseul cel mai scurt trece
3 3 3 prin T=7 camere.
Sunt mai multe astfel de tra-
see. De exemplu:
1) (1 1 1, 1 1 2, 1 1 3, 1 2 3,
1 3 3, 2 3 3, 3 3 3)
2) (1 1 1, 1 1 2, 1 1 3, 2 1 3, 2
2 3, 3 2 3, 3 3 3)
3) (1 1 1, 1 2 1, 1 3 1, 1 3 2, 2 3 2, 3 2 3, 3 3 3) etc.
Cel mai mic astfel de traseu (în sens lexicograc) este traseul 1).
Timp maxim de executare/test: 1.0 secunde
Memorie: total 16 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 10 KB
- Se poate borda masivul cu -1 pentru a se evita ie³irea în afara poziµiilor camerelor hotelului
- Marc m cu 1 poziµia camerei ³oricelului A[K1][L1][C1]=1.
- Pentru ecare camer accesibil (e x y z eticheta acestei camere) studiem cele maximum 6
camere vecine în care ar putea intra ³oricelul:
- Poate accesibil oricare din cele 6 camere cu dac elemntul masivului corespunz tor eti-
chetei camerei este 0 sau este mai mare ca A[x][y][z]
- Vizit m ³i marc m ecare camer accesibil memorând valoarea A[x][y][z]+1 în elementul
corespunz tor etichetei camerei în masiv. Valoare memorat reprezentând num rul minim
de camere prin care trebuie s treac ³oricelul pentru a ajunge în camera cu eticheta curent ,
plecând din camera iniµial .
- Poziµiile camerelor care au fost vizitate le vom reµine într-o coad , în ordinea vizit rii lor.
- Primul elemnt din coad reµine poziµia (K1,L1,C1), memorat pe poziµia 1.
- Cât timp nu a fost vizitat camera cu alimente, vom vizita pentru poziµia curent p din
coad (x,y,z) cele maximum 6 camere accesibile. Vom ad uga la nalul cozii poziµiile ec rei
camere accesibile, în ordinea vizit rii. Trecem la poziµia p+1 din coad ³i acest procedeu.
- La nal, valoarea T=A[K2][L2][C2] reprezint num rul minim de camere prin care trece
taseul cel mai scurt al ³oricelului de la camera lui la camera cu alimente.
- Traseul se va reconstitui plecând de la camera cu alimente c tre camera ³oricelului. Se
viziteaz cele maximum 6 camere accesibile marcate cu T-1, în ordinea din desen, pentru
a obµine traseul cel mai mic în sens lexicograc. Dintre acestea se alege prima camer
marcat cu T-1. Apoi, pentru camera aleas se viziteaz camerele accesibile marcate cu T-2
în ordinea din imagine ³i din nou se alege prima dintre acestea, etc. Traseul a fost obµinut
dac s-a ajuns la camera ³oricelului marcat cu 1.
- Poziµiile acestor T camere alese se vor memora într-un vector ale c ror componente se vor
a³a în ordine invers .
3
Complexitate O N
86 ++z;
87 else
88 if (a[x][y+1][z]==val-1)
89 ++y;
90 else
91 if (a[x+1][y][z]==val-1)
92 ++x;
93 --val;
94 c[val].x=x;
95 c[val].y=y;
96 c[val].z=z;
97 }
98 }
99
100 int main()
101 {
102 citeste();
103 bordare();
104 coada();
105
106 int val=a[k2][l2][c2];
107 g<<val<<endl;
108 c[val].x=k2;
109 c[val].y=l2;
110 c[val].z=c2;
111 drum(val);
112
113 for(int i=1;i<=val; i++)
114 g<<c[i].x<<’ ’<<c[i].y<<’ ’<<c[i].z<<endl;
115
116 g.close();
117 return 0;
118 }
40 }
41
42 void coada()
43 {
44 p=u=1;
45 c[1].x=k1;
46 c[1].y=l1;
47 c[1].z=c1;
48 a[k1][l1][c1]=1;
49 while((p<=u)&&(a[k2][l2][c2]==0))
50 {
51 x=c[p].x;
52 y=c[p].y;
53 z=c[p++].z;
54 for(i=0;i<6;i++)
55 {
56 xc=x+dx[i];
57 yc=y+dy[i];
58 zc=z+dz[i];
59 if (a[xc][yc][zc]==0)
60 {
61 u++;
62 a[xc][yc][zc]=a[x][y][z]+1;
63 c[u].x=xc;
64 c[u].y=yc;
65 c[u].z=zc;
66 }
67 }
68 }
69 }
70
71 void drum(short int x, short int y, short int z, int val)
72 {
73 if(val>1)
74 {
75 if (a[x-1][y][z]==val-1) drum(x-1,y,z,val-1);
76 else
77 if (a[x][y-1][z]==val-1) drum(x,y-1,z,val-1);
78 else
79 if (a[x][y][z-1]==val-1) drum(x,y,z-1,val-1);
80 else
81 if (a[x][y][z+1]==val-1) drum(x,y,z+1,val-1);
82 else
83 if (a[x][y+1][z]==val-1) drum(x,y+1,z,val-1);
84 else
85 if (a[x+1][y][z]==val-1) drum(x+1,y,z,val-1);
86
87 g<<x<<’ ’<<y<<’ ’<<z<<endl;
88 }
89 }
90
91 int main()
92 {
93 citeste();
94 bordare();
95 coada();
96
97 int val=a[k2][l2][c2];
98 g<<val<<endl;
99 g<<k1<<’ ’<<l1<<’ ’<<c1<<endl;
100 drum(k2,l2,c2,val);
101
102 //cout<<val;
103 g.close();
104 return 0;
105 }
7 ifstream f("traseu.in");
8 ofstream g("traseu.out");
9
10 struct cel
11 {
12 short k, l, c;
13 };
14
15 short dx[]={-1, 0, 1, 0, 0, 0};
16 short dy[]={ 0, 1, 0,-1, 0, 0};
17 short dz[]={ 0, 0, 0, 0, 1,-1};
18 bool a[102][102][102];
19 int M[102][102][102], T[102][102][102];
20 short n, m, k1, l1, c1, k2, l2, c2;
21
22 queue <cel> q;
23
24 void lee()
25 {
26 short k;
27 cel x, y;
28 x.k = k1; x.l = l1; x.c = c1;
29 M[x.k][x.l][x.c] = 1;
30 T[x.k][x.l][x.c] = -1;
31 q.push(x);
32
33 while(!q.empty())
34 {
35 x = q.front(); q.pop();
36 for (k=0; k<6; ++k)
37 {
38 y.k = x.k + dz[k];
39 y.l = x.l + dx[k];
40 y.c = x.c + dy[k];
41 if (a[y.k][y.l][y.c] == 0)
42 if (M[x.k][x.l][x.c] + 1 < M[y.k][y.l][y.c])
43 {
44 if (T[y.k][y.l][y.c] == 0)
45 T[y.k][y.l][y.c] = x.k*1000000 + x.l*1000 + x.c;
46 else
47 {
48 if(T[y.k][y.l][y.c] > x.k*1000000+x.l*1000+x.c)
49 T[y.k][y.l][y.c] = x.k*1000000+x.l*1000+x.c;
50 }
51
52 M[y.k][y.l][y.c] = M[x.k][x.l][x.c] + 1;
53 q.push(y);
54 }
55 else
56 if (M[x.k][x.l][x.c] + 1 == M[y.k][y.l][y.c])
57 {
58 if (T[y.k][y.l][y.c] > x.k*1000000 + x.l*1000 + x.c)
59 T[y.k][y.l][y.c] = x.k*1000000 + x.l*1000 + x.c;
60 }
61 }
62 }
63 }
64
65 void afis(short k, short l, short c)
66 {
67 short k2, l2, c2;
68 int x;
69 if (k == k1 && l == l1 && c == c1)
70 g << k << " " << l << " " << c << "\n";
71 else
72 {
73 x = T[k][l][c];
74 k2 = x / 1000000;
75 l2 = x / 1000 % 1000;
76 c2 = x % 1000;
77 afis(k2, l2, c2);
78 g << k << " " << l << " " << c << "\n";
79 }
80 }
81
82 int main()
CAPITOLUL 24. ONI 2014 513
83 {
84 short k, l, c;
85 f >> n >> m;
86 for (k=0; k<=n+1; ++k)
87 for (l=0; l<=n+1; ++l)
88 for (c=0; c<=n+1; ++c)
89 {
90 M[k][l][c] = inf;
91 if (k==0 || l==0 || c==0)
92 a[k][l][c] = 1;
93 if (k==n+1 || l==n+1 || c==n+1)
94 a[k][l][c] = 1;
95 }
96
97 f >> k1 >> l1 >> c1;
98 f >> k2 >> l2 >> c2;
99
100 while (m--)
101 {
102 f >> k >> l >> c;
103 a[k][l][c] = 1;
104 }
105
106 lee();
107
108 g << M[k2][l2][c2] << "\n";
109 afis(k2, l2, c2);
110 return 0;
111 }
44 {
45 K=k+dk[j];
46 L=l+dl[j];
47 C=c+dc[j];
48 if(1<=K && K<=N && 1<=L && L<=N &&
49 1<=C && C<=N && A[K][L][C]==0)
50 {
51 A[K][L][C]=j + (1 + A[k][l][c] / 10) * 10;
52 tl++;
53 tail[tl].K=K;
54 tail[tl].L=L;
55 tail[tl].C=C;
56 tlen++;
57 if(K==K2 && L==L2 && C==C2)break;
58 }
59 }
60
61 tf++;
62 tlen--;
63 }
64
65 T=A[K2][L2][C2]/10;
66 K=K2;
67 L=L2;
68 C=C2;
69
70 for(i=T;i>=1;i--)
71 {
72 tail[i].K=K;
73 tail[i].L=L;
74 tail[i].C=C;
75 j=A[K][L][C]%10;
76 j=5-j;
77 K=K+dk[j];
78 L=L+dl[j];
79 C=C+dc[j];
80 }
81
82 fout<<T<<"\n";
83 for (i=1;i<=T;i++)
84 {
85 fout<<(int)tail[i].K<<" "<<(int)tail[i].L<<" "<<(int)tail[i].C<<"\n";
86 }
87
88 fout.close();
89 fin.close();
90 return 0;
91 }
Capitolul 25
ONI 2013
25.1 aranjare
Problema 1 - aranjare 100 de puncte
Toat lumea ³tie c Mirel are 2 N sticluµe cu parfum a³ezate pe un raft cu 2 N poziµii,
numerotate de la 1 la 2 N . El are N sticluµe cu parfum cump rate din µar ³i alte N sticluµe cu
parfum cump rate din Franµa.
Sticluµele cump rate din µar sunt etichetate cu r1 , r2 , r3 , ..., rN , iar sticluµele cump rate din
Franµa sunt etichetate cu f1 , f2 , f3 , ..., fN . Fiecare sticluµ are asociat valoarea cu care a fost
cump rat .
Iniµial, Mirel are a³ezate pe primele N poziµii sticluµele cump rate din µar sortate cres-
c tor dup valoare, iar pe urm toarele N poziµii sticluµele cump rate din Franµa sortate tot
cresc tor dup valoare. Astfel, cele 2 N sticluµe cu parfum sunt a³ezate în felul urm tor:
r1 , r2 , r3 , ..., rN , f1 , f2 , f3 , ..., fN . Mai exact, sticluµa ri se a pe poziµia i, iar sticluµa fi se a
pe poziµia N i, pentru i din intervalul 1, N .
Prietenul s u cel mai bun, Marian, s-a gândit s -i fac o surprinz ³i s -i schimbe aranjarea
sticluµelor cu parfum în urm toarea ordine: r1 , f1 , r2 , f2 , r3 , f3 , ..., rN , fN . Cum Marian are dou
mâini, el poate face numai urm torul tip de operaµie: ia dou sticluµe cu parfum de pe raft (de
pe dou poziµii diferite) ³i le interschimb .
Cerinµe
Dându-se num rul N , ³i 2 N valori reprezentând valoarea ec rei sticluµe cu parfum, ajutaµi-l
pe Marian s fac operaµiile necesare pentru a schimba ordinea sticluµelor cu parfum în ordinea
precizat în enunµ.
Date de intrare
Fi³ierul de intrare aranjare.in conµine pe prima linie num rul N , iar pe urm toarea linie 2 N
numere naturale, separate prin câte un spaµiu. Primele N numere reprezint valorile sticluµelor
cump rate din µar , iar urm toarele N numere reprezint valorile sticluµelor cump rate din Franµa.
Atât primele N , cât ³i ultimele N numere sunt sortate cresc tor în funcµie de valoare.
Date de ie³ire
Fi³ierul de ie³ire aranjare.out va conµine mai multe linii. Pe ecare linie se vor aa dou
numere diferite x ³i y din intervalul 1, 2 N , semnicând faptul c Marian trebuie s interschimbe
sticluµa de pe poziµia x cu sticluµa de pe poziµia y .
Restricµii ³i preciz ri
a 2 & N & 100 000
a Dac exist mai multe soluµii, se poate a³a oricare dintre ele.
a Soluµia nu trebuie s fac neap rat num rul minim de operaµii.
a Pentru 15% din teste se garanteaz c N & 13.
a Pentru alte 25% din teste se garanteaz c N & 300.
a Pentru alte 30% din teste se garanteaz c N & 1000.
515
CAPITOLUL 25. ONI 2013 516
Exemple:
aranjare.in aranjare.out Explicaµii
3 24 În explicaµia de mai jos, ecare sticluµ are numele etichetei
135235 35 urmat de valoarea ei în parantez .
34 irul iniµial este: r1 1r2 3r3 5f1 2f2 3f3 5
Dup prima mutare devine: r1 1f1 2r3 5r2 3f2 3f3 5
Dup a doua mutare devine: r1 1f1 2f2 3r2 3r3 5f3 5
Dup ultima mutare devine: r1 1f1 2r2 3f2 3r3 5f3 5
Timp maxim de executare/test: 0.5 secunde
Memorie: total 16 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 5 KB
pentru i de la 1 la 2 N
` dac pe poziµia i nu avem sticluµa care trebuie:
t facem swap între i ³i pozitia pe care se a sticluµa ce trebuie a³ezat pe poziµia i
La ecare pas aducem pe poziµia corect cel puµin o sticluµ , deci rezult c sunt necesare cel
mult 2 N astfel de mut ri pentru a duce conguraµia iniµial la conguraµia nal .
Complexitate: O N
22 p[i]=i,
23 v[i]=i;
24
25 for(int i=1;i<n;++i)
26 {
27 if (v[2*i]!=n+i)
28 {
29 v[p[n+i]]=v[2*i];
30 p[v[2*i]]=p[n+i];
31 fout<<2*i<<" "<<p[n+i]<<"\n";
32 }
33
34 if (v[2*i+1]!=i+1)
35 {
36 v[p[i+1]]=v[2*i+1];
37 p[v[2*i+1]]=p[i+1];
38 fout<<2*i+1<<" "<<p[i+1]<<"\n";
39 }
40 }
41
42 return 0;
43 }
25.2 gradina
Problema 2 - gradina 100 de puncte
P cal a reu³it s duc la bun sfâr³it în elegerea cu boierul c ruia-i fusese slug ³i, conform
învoielii, boierul trebuie s -l r spl teasc dându-i o parte din livada sa cu pomi fructiferi. Boierul
este un om foarte ordonat, a³a c livada sa este un p trat cu latura de N metri unde, pe vremuri,
fuseser plantate N rânduri cu câte N pomi ecare. Orice pom fructifer putea identicat
cunoscând num rul rândului pe care se a ³i poziµia sa în cadrul rândului respectiv. Cu timpul,
unii pomi s-au uscat ³i acum mai sunt doar P pomi. P cal trebuie s -³i delimiteze în livad o
gr din p trat cu latura de K metri.
Cerinµe
Cunoscând dimensiunile livezii ³i gr dinii, num rul pomilor din livad ³i poziµia ec ruia,
determinaµi num rul maxim de pomi dintr-o gr din p trat de latur K ³i num rul modurilor
în care poate amplasat gr dina cu num rul maxim de pomi.
Date de intrare
Fi³ierul gradina.in conµine:
- pe prima linie numerele naturale N , P ³i K , separate prin câte un spaµiu, cu semnicaµia din
enunµ;
- pe urm toarele P linii câte 2 numere naturale Lin ³i Col, separate printr-un spaµiu, repre-
zentând num rul rândului, respectiv poziµia în rând a ec rui pom din livad .
Date de ie³ire
Fi³ierul gradina.out va conµine:
- pe prima linie num rul maxim de pomi fructiferi dintr-o gr din p trat cu latura de K
metri;
- pe a doua linie num rul de posibilit µi de a amplasa gr dina astfel încât s conµin num rul
maxim de pomi determinat.
Restricµii ³i preciz ri
a 2 & N & 1000
1&P &N
2
a
a 1&K&N
Exemple:
CAPITOLUL 25. ONI 2013 518
Pentru a putea determina gr dina cu num r maxim de pomi vom calcula un tablou bidimen-
sional S cu sume parµiale:
S ij = suma elementelor din subtabloul care are colµul stânga-sus de coordonate (1,1) ³i
colµul dreapta-jos de coordonate i, j , adic num rul pomilor din aceast zon ;
Bazându-ne pe tabloul S , pentru ecare poziµie i, j , determin m num rul pomilor din sub-
tabloul care are colµul stânga-sus de coordonate i k 1, j k 1 ³i colµul dreapta-jos de
coordonate i, j , dup formula:
15 for(int i=1;i<=p;++i)
16 {
17 int x, y;
18 fscanf(fin,"%d%d",&x,&y);
19 a[x][y]=1;
20 }
21
22 fclose(fin);
23 }
24
25 void solve ()
26 {
27 for(int i=1;i<=n;++i)
28 for(int j=1;j<=n;++j)
29 a[i][j]+=a[i][j-1]+a[i-1][j]-a[i-1][j-1];
30
31 for(int i=k;i<=n;++i)
32 for(int j=k;j<=n;++j)
33 {
34 int np = a[i][j]-a[i-k][j]-a[i][j-k]+a[i-k][j-k];
35 if (np>pmax)
36 {
37 pmax=np;
38 nsol=1;
39 }
40 else
41 if (np==pmax)
42 ++nsol;
43 }
44 }
45
46 int main ()
47 {
48 read ();
49 solve ();
50
51 FILE *fout = fopen("gradina.out","wt");
52 fprintf(fout,"%d\n%d\n",pmax,nsol);
53 fclose(fout);
54 return 0;
55 }
25.3 split
Problema 3 - split 100 de puncte
Fie un ³ir a1 , a2 , ..., aN de numere naturale. Se împarte ³irul în patru secvenµe astfel încât
orice element din ³ir s aparµin unei singure secvenµe ³i ecare secvenµ s conµin cel puµin
dou elemente. Mai exact, se identic trei indici i $ j $ k astfel încât prima secvenµ este
format din elementele a1 , a2 , ..., ai , a doua din elementele ai1 , ai2 , ..., aj , a treia din elementele
aj 1 , aj 2 , ..., ak ³i ultima din elementele ak1 , ak2 , ..., an . Pentru ecare secvenµ se determin
costul ei ca ind diferenµa dintre valoarea maxim ³i cea minim din acea secvenµ .
Cerinµe
S se determine o împ rµire a ³irului în patru secvenµe astfel încât suma costurilor celor patru
secvenµe s e maxim .
Date de intrare
Fi³ierul split.in conµine pe prima linie num rul natural N . Pe linia a doua se g sesc N numere
naturale, separate prin câte un spaµiu, reprezentând elementele ³irului a.
Date de ie³ire
Fi³ierul split.out conµine pe prima linie un singur num r natural reprezentând suma maxim
a costurilor celor patru secvenµe. Pe linia a doua se a trei numere naturale i, j ³i k , separate
prin câte un spaµiu, cu semnicaµia din enunµ.
Restricµii ³i preciz ri
CAPITOLUL 25. ONI 2013 520
Exemple:
split.in split.out Explicaµii
11 29 Cele 4 secvenµe sunt:
9 7 3 0 2 1 8 6 0 11 4 479 9 7 3 0 (cost 9 - 0 = 9)
2 1 8 (cost 8 - 1 = 7)
6 0 (cost 6 - 0 = 6)
11 4 (cost 11 - 4 = 7)
O alt soluµie care obµine tot suma maxim 29 este 5 7
9, dar nu are i minim.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 16 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 5 KB
Se construiesc mai întâi liniar vectorii maxst, minst, maxdr, mindr, de lungime N :
minsti = valoarea minim din secvenµa a1..i
maxsti = valoarea maxim din secvenµa a1..i
mindri = valoarea minim din secvenµa ai..N
maxdri = valoarea minim din secvenµa ai..N
Pentru ecare j (4 & j & n 4):
avom c uta poziµia i plecând de la j spre stânga ³i determinând la ecare pas minimul ³i
maximul din intervalul i..j (aceste dou valori aparµin secvenµei a doua). Evident, prima secvenµ
are costul dat de maxsti 1 minsti 1.
a vom c uta poziµia k plecând de la j 1 dpre dreapta ³i determinând la ecare pas minimul
³i maximul din intervalul j 1..k (aceste dou valori aparµin secvenµei a treia). Evident, ultima
secvenµ are costul dat de maxdrk 1 mindrk 1.
a calculeaz costul celor 4 secvenµe ³i actualizeaz costul maxim al celor 4 secvenµe
2
Complexitatea total este O N .
25.4 momente
Problema 4 - momente 100 de puncte
G are un ceas digital care a³eaz ora printr-o valoare între 0 ³i 23 sub forma unui num r de
una sau dou cifre, minutul printr-o valoare între 0 ³i 59 sub forma unui num r de exact dou cifre
(prima cifr este 0 dac num rul de minute care trebuie a³at este mai mic decât 10) ³i secunda
printr-o valoare între 0 ³i 59 sub forma unui num r de exact doua cifre (dac num rul de secunde
care trebuie a³at este mai mic decât 10, atunci prima cifr este 0). Aceste informaµii apar în
ordinea: num rul de ore, num rul de minute, num rul de secunde ³i sunt separate prin câte un
spaµiu. Exemple: 23 39 17 (pentru ora 23, 39 minute ³i 17 secunde) , 1 00 01 (pentru ora 1, 0
minute ³i o secund ) sau 0 02 02 (pentru ora 0, 2 minute ³i 2 secunde).
G observ c dac al tur aceste trei valori poate construi un num r natural. Asfel, pentru
exemplele de mai sus obµine numerele 233917, 10001 ³i respectiv 202 (Atenµie! Num rul rezultat
nu începe cu 0 - eventualele cifre nule aate la începutul lui sunt eliminate!). G mai observ c
exist momente de timp, când num rul astfel format este un palindrom, cum este cazul celui de-al
doilea ³i celui de-al treilea exemplu. G denume³te aceste momente de timp momente palindromice
³i dore³te s ae câte astfel de momente sunt într-un interval de timp dat.
Un interval de timp este situat pe parcursul anului 2013 ind precizat prin data ³i ora exact
când începe ³i data ³i ora exact când se termin . Data este precizat prin doua numere care
reprezint luna ³i ziua, iar ora exact sub forma a³at de ceasul digital al lui G.
Cerinµe
Determinaµi câte momente palidromice au loc în k intervale de timp date.
CAPITOLUL 25. ONI 2013 523
Date de intrare
Fi³ierul de intrare momente.in conµine pe prima linie num rul natural k cu semnicaµia din
enunµ. Pe ecare dintre urm toarele k linii se a câte 10 valori naturale separate prin câte un
spaµiu. Primele cinci numere reprezint luna, ziua, ora, minutul ³i secunda când începe intervalul
de timp dat. Urm toarele cinci numere reprezint luna, ziua, ora, minutul ³i secunda când se
termin intervalul de timp dat.
Date de ie³ire
Fi³ierul de ie³ire momente.out va conµine k linii. Pe linia i (1 & i & k ) se va aa un singur
num r care va reprezenta num rul de momente palindromice din intervalul i.
Restricµii ³i preciz ri
a k & 100 000
a data de început precede data de sfâr³it pentru ecare interval de timp;
a în anul 2013 luna februarie are 28 zile;
a pentru 50% dintre teste vom avea k 1;
a se nume³te palindrom un num r care citit de la stânga la dreapta sau de la dreapta la stânga
are aceea³i valoare.
a dac intervalul de timp considerat începe sau se termin cu un moment palindromic, acesta
este num rat.
Exemple:
momente.in momente.out Explicaµii
1 24 Fi³ierul de intrare conµine un singur interval de timp, intre
2 28 23 44 32 28 februarie ora 23, 44 minute ³i 32 secunde ³i 1 martie
3 1 0 02 02 ora 0, 2 minute ³i 2 secunde.
In acest interval de timp sunt 24 momente palindomice
dupa cum urmeaza:
- în data de 28 februarie la orele 23 44 32 ³i 23 55 32;
- în data de 1 martie la orele 0 00 00, 0 00 01, 0 00 02, 0
Timp maxim de executare/test: 1.2 secunde
Memorie: total 16 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 5 KB
Ideea de plecare in rezolvarea problemei este sa determinam cate palindromuri sunt intr-o zi
intreaga (de la ora 0 la 23:59:59). Putem determina acest numar prin simulare directa, adica
testand daca ecare moment din acest interval este sau nu palindrom. Astfel determinam ca sunt
699 palindromuri într-o zi.
Obtinerea raspunsului pentru un singur interval necesit s determin m:
1 câte zile întregi sunt în intervalul dat (aceasta putem s o facem prin diverse metode -
chiar printr-o metod brut );
- un tabou precalculat în care reµinem momentele de timp care sunt palindromice ³i aplic m o
c utare binar în acest tablou => complexitate O k log 700 pentru întrega soluµie (100
de puncte);
- metoda brut : determinarea numerelor a³ate de ceas din secund în secund ³i num rarea
celor care sunt palindromice (obµinând cel mult 50 puncte)
Soluµiile bazate pe simularea brut (parcurgerea ec rui interval din secund în secund ) obµin
cel mult 20 puncte.
54 min := 0;
55 inc(ora);
56 end;
57 end;
58 end;
59
60
61 begin
62
63 mom[0] := 1;
64
65 precalc;
66
67 assign(fo,’momente.out’);
68 assign(fi,’momente.in’);
69 rewrite(fo);
70 reset(fi);
71 readln(fi,k);
72
73 for i := 1 to k do
74
75 begin
76
77 ct3 := 0; ct2 := 0; ct1 := 0; ctz := 0;
78
79
80 read(fi,luna1,zi1,ora1,min1,sec1);
81 read(fi,luna2,zi2,ora2,min2,sec2);
82
83
84 if ora1+min1+sec1=0 then
85 ctz:=1;
86
87 luna := luna1;
88 zi := zi1;
89 while not ((zi=zi2) and (luna=luna2)) do
90 begin
91 inc(zi);
92 if zifin[luna]+1=zi then
93 begin
94 zi := 1;
95 inc(luna)
96 end;
97 inc(ctz);
98 end;
99 dec(ctz);
100
101
102 ct2 := 699*ctz; //zile complete*699 /zi
103
104 nr := ora1*3600 + min1*60 + sec1;
105
106 if nr>0 then
107 ct1 := 699 - mom[nr-1]
108 else
109 ct1 := 0;
110
111 nr := ora2*3600 + min2*60 + sec2;
112
113 ct3 := mom[nr];
114
115 writeln(fo,ct1+ct2+ct3);
116
117 end;
118
119 close(fo);
120 end.
25.5 secvente
Problema 5 - secvente 100 de puncte
Consider m ³irul de numere naturale nenule distincte a1 , a2 , ..., aN . Not m cu Li lungimea
maxim a unei secvenµe de elemente cu valori consecutive care se poate obµine prin ordonarea
CAPITOLUL 25. ONI 2013 526
cresc toare a primelor i elemente din ³irul dat. De exemplu, pentru ³irul 7, 2, 3, 8, 20, 4, 10, 9
avem:
L1 1, L2 1, L3 2, L4 2, L5 2, L6 3, L7 3, L8 4.
Cerinµe
S se determine L1 , L2 , ..., LN .
Date de intrare
Fi³ierul secvente.in conµine pe prima linie num rul natural N . Pe ecare din urm toarele N
linii se g se³te câte un num r natural, deci pe linia i 1 se va aa elementul ai , pentru i 1...N .
Date de ie³ire
Fi³ierul secvente.out conµine exact N linii. Pe linia i (i 1...N ) se va a³a valoarea Li .
Restricµii ³i preciz ri
a 3 & N & 200 000 a 1 & ai & 1 000 000, pentru orice i 1...N a Pentru 35% din teste se
garanteaz c N & 1000
Exemple:
secvente.in secvente.out Explicaµii
8 1 L 1. ³irul : 7. Lungime maxim 1
7 1 L2. ³irul: 7,3. Lungime maxim 1
3 2 L 3. ³irul: 7,3,2. ³irul sortat este 2,3,7. Lungimea maxim este
2 2 2 (dat de secvenµa 2,3)
8 2 L 4. ³irul: 7,3,2,8. Lungime maxim 2 (dat de 2,3)
20 3 L5. ³irul: 7,3,2,8,20. Lungime maxim 2 (dat de 2,3).
4 3 L 6. ³irul: 7,3,2,8,20,4. ³irul sortat este 2,3,4,7,8,20. Lungimea
10 4 maxim este 3 (dat de secvenµa 2,3,4).
9 L 7. ³irul: 7,3,2,8,20,4,10. Lungime maxim 3 (dat de 2,3,4).
L 8. ³irul: 7, 3, 2, 8, 20, 4, 10, 9.
³irul sortat este 2,3,4,7,8,9,10,20. Lungimea maxim este 4 (dat
de secvenµa 7,8,9,10).
Timp maxim de executare/test: 0.2 secunde
Memorie: total 16 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 5 KB
Soluµie 35 pct
O prim idee ar s avem un vector de vizite pentru a ³ti la ecare pas dac un element se
a în secvenµa curent (care începe pe poziµia 1). Un algoritm de rezolvare este urm torul:
` vz v i = true;
` crt = num rul de valori de 1 consecutive în vectorul vz în jurul poziµiei v i
` dac crt % best
t best crt
` scrie best
CAPITOLUL 25. ONI 2013 527
Complexitate: O(N*N)
Soluµie 100 pct
Pornind de la ideea anterioar , putem renunµa la vz ³i s -l înlocuim cu pos, unde posx este:
Pentru valorile x care aparµin unei secvenµe de valori consecutive dar nu se a pe marginile
secvenµei, se observ c posx este irelevant.
Noul algoritm de rezolvare este:
best = 0
pentru ecare i de la 1 la N
` begin v i, poziµia unde începe secvenµa singurului element v i
` end v i, poziµia unde se termin secvenµa singurului element v i
` dac posv i 1! 0, adic elementul v i 1 se a deja într-o secvenµ
t begin posv i 1, actualiz m începutul secvenµei în care se a elementul v i
` dac posv i 1! 0, adic elementul v i 1 se a deja într-o secvenµ
t end posv i 1, actualiz m sfâr³itul secvenµei în care se a elementul v i
` deci elementul v i se a în interiorul secvenµei begin, end. Cum poziµiile de început
³i de sfâr³it al elementelor din interiorul intervalului sunt irelevante, actualiz m pos
doar pentru elementele din cap t:
t posbegin end
t posend begin
` dac end begin 1 % best:
t best end begin 1
` scrie best
20 void read()
21 {
22
23 scanf("%d\n", &n);
24
25 for (int i = 0; i < n; ++i)
26 {
27 scanf("%d", &v[i+1]);
28
29 assert(vz[v[i+1]] == false);
30 vz[v[i+1]] = true;
31 }
32 }
33
34 void solve()
35 {
36
37 int best = 0;
38
39 for (int i = 1; i <= n; ++i)
40 {
41 int begin = v[i], end = v[i];
42
43 if (pos[v[i]-1]) begin = pos[v[i]-1];
44 if (pos[v[i]+1]) end = pos[v[i]+1];
45
46 pos[begin] = end;
47 pos[end] = begin;
48
49 best = max(best, end - begin + 1);
50 printf("%d\n", best);
51 }
52 }
53
54 int main()
55 {
56 freopen(infile, "r", stdin);
57 freopen(outfile, "w", stdout);
58
59 read();
60 solve();
61
62 fclose(stdin);
63 fclose(stdout);
64 return 0;
65 }
25.6 spider
Problema 6 - spider 100 de puncte
Omul p ianjen (Spiderman) sare de pe o cl dire pe alta, aat în imediata vecin tate, în nord,
est, sud sau vest. Cl dirile din cartierul omului p ianjen au o în lµime exprimat în numere
naturale ³i sunt a³ezate pe m rânduri, câte n pe ecare rând.
Spiderman va alege s sar pe una dintre cl dirile vecine, care are în lµimea mai mic sau egal ,
iar diferenµa de în lµime este minim . Dac exist mai multe cl diri vecine de aceea³i în lµime,
omul p ianjen aplic ordinea preferenµial nord, est, sud, vest, dar nu sare înc o dat pe o cl dire
pe care a mai s rit. Scopul omului p ianjen este acela de a reu³i s fac un num r maxim de
s rituri succesive.
Cerinµe
Scrieµi un program care determin num rul maxim de s rituri succesive, pe care îl poate
efectua, pornind de la oricare dintre cl diri, precum ³i poziµiile cl dirilor care formeaz drumul
maxim.
Date de intrare
Fi³ierul spider.in conµine, pe prima linie, dou numere naturale, m ³i n, desp rµite printr-un
spaµiu. Fiecare dintre urm toarele m rânduri conµine n numere naturale, separate prin câte un
spaµiu, reprezentând în lµimile cl dirilor.
CAPITOLUL 25. ONI 2013 529
Date de ie³ire
Fi³ierul de ie³ire spider.out va conµine, pe prima linie, un singur num r natural k , repre-
zentând num rul maxim de s rituri. Urm toarele k linii vor conµine câte dou numere naturale,
separate printr-un spaµiu, reprezentând coordonatele cl dirilor care formeaz drumul maxim, în
ordinea parcurgerii. Dac exist mai multe soluµii, în ³ierul de ie³ire se va scrie drumul care
porne³te de la poziµia i, j cu i minim, iar dac exist mai multe soluµii cu acela³i i minim, se va
scrie în ³ier soluµia cu i ³i j de valoare minim .
Restricµii ³i preciz ri
a 0 $ m, n & 1000
a în lµimile cl dirilor sunt numere naturale din intervalul [1,10000000]
a în orice zon p tratic de 2x2 cl diri vecine exist cel mult 2 cl diri de aceea³i în lµime.
Exemple:
spider.in spider.out Explicaµii
55 8 Spiderman porne³te de pe blocul de 90 de metri aat în
35 3842 40 50 54 poziµia (5, 4), face 8 s rituri ³i ajunge în poziµia (1, 4), de
34 3830 75 50 53 unde nu mai are posibilit µi de a s ri.
70 7888 86 30 43
39 9088 23 25 33
35 8089 90 34 34
24
25
15
14
Timp maxim de executare/test: 3.0 secunde
Memorie: total 64 MB din care pentru stiv 8 MB
Dimensiune maxim a sursei: 5 KB
Soluµie 35 pct
Se denesc dou matrice: A si B cu maxim 1 000 de rânduri ³i maxim 1 000 de coloane,
precum ³i dou tablouri, v ³i w, având cel mult 1 000 000 de elemente. în matricea A se citesc
valorile în lµimilor cl dirilor (numere naturale din intervalul [1, 10 000 000]. Se construie³te câte
unui drum, pornind de la toate elementele matricei A, ³i se reµine drumul de lungime maxim .
Se utilizeaz o funcµie care prime³te, prin intermediul parametrului pas, num rul de ordine al
drumului care se construie³te. Funcµia întoarce în lµimea cl dirii cu diferenµa de în lµime minim ,
³i care respect condiµiile din enunµ. Funcµia veric în matricea B dac cl direa de coordonate
i, j a mai fost - sau nu - vizitat de Spiderman: dac B ij pas, atunci cl direa de coordonate
i, j a fost deja vizitat pe parcursul drumului cu num rul de ordine pas, deci cl direa nu este
eligibil . Dac B ij este diferit de pas, atunci se alege cl direa respectiv ³i lui B ij i se
atribuie valoarea pas.
Se utilizeaz un subprogram care prime³te, prin parametrii de intrare r ³i c, coordonatele unei
cl diri ³i construie³te drumul care poate parcurs pornind de la aceea cl dire. Pentru selectarea
unei cl diri se utilizeaz funcµia descris mai sus. Dac drumul cu num rul de ordine actual
este mai lung decât precedentul drum, se va reµine lungimea drumului în variabila k , precum ³i
elementele vectorului de direcµii v în vectorul w, care va avea lungimea k ³i va reµine direcµiile
corespunz toare drumului maxim. Elementele vectorului v se denesc astfel:
v i 1, dac direcµia aleas pentru s ritura i este Nord;
v i 2, dac direcµia aleas pentru s ritura i este Est;
v i 3, dac direcµia aleas pentru s ritura i este Sud;
v i 4, dac direcµia aleas pentru s ritura i este Vest.
Programul principal va apela acest subprogram pentru toate elementele matricei A, pornind
de la elementul de coordonate 1, 1, parcurgând matricea de la linia 1 la linia m, ³i elementele
CAPITOLUL 25. ONI 2013 530
pe linii, de la 1 la n. Datele unui drum se vor reµine doar dac lungimea sa este strict mai mare
decât cea mai mare lungime obµinut pân în acel moment. La scrierea datelor în ³ierul de ie³ire
(k ³i cooronatele cl dirilor care formeaz drumul maxim) se va porni de la coordonatele primei
cl diri, iar coordonatele cl dirilor care formeaz drumul maxim se vor determina prin interpretarea
corect a elementelor vectorului w.
Complexitate: O N N M M
Soluµie 100 pct
Pornind de la soluµia anterioar , observ m c , dac nu am avea dou valori identice pe poziµii
al turate, nu are sens s calcul m din ecare poziµie de început care este lungimea maxim ,
deoarece putem stoca într-o matrice auxiliar bestij lungimea maxim a unei secvenµe care
începe pe poziµia i, j , iar atunci când determin m un drum s actualiz m toate aceste costuri
ale poziµiilor prin care trece.
Cum putem avea dou valori vecine cu aceea³i valoare, acest tablou best trebuie schimbat puµin
în bestxy d având semnicaµia: lungimea maxim a unei secvenµe care începe pe poziµia x, y
care nu face prima s ritur în direcµia d (d poate avea valori de la 0 la 3, ecare valoare semnicând
una din cele 4 direcµii posibile).
Complexitate: O N M
42 }
43
44 pair<point, int> getNextPosition(point crt, point prv)
45 {
46
47 point ret = outside;
48 int dir = -1;
49
50 for (int t = 0; t < 4; ++t)
51 {
52 point nxt = make_pair(crt.first + ii[t], crt.second + jj[t]);
53 if (nxt != prv && valid(nxt) &&
54 getHeight(ret) < getHeight(nxt) &&
55 getHeight(nxt) <= getHeight(crt))
56 {
57 ret = nxt;
58 dir = t;
59 }
60 }
61
62 return make_pair(ret, dir);
63 }
64
65 void read()
66 {
67
68 scanf("%d %d\n", &n, &m);
69
70 for (int i = 0; i < n; ++i)
71 {
72 for (int j = 0; j < m; ++j)
73 {
74 scanf("%d", &h[i+1][j+1]);
75 }
76 }
77 }
78
79 int solve(int x, int y, int d)
80 {
81
82 if (best[x][y][d])
83 {
84 return best[x][y][d];
85 }
86
87 best[x][y][d] = 1;
88 point prv;
89
90 if (d == 4)
91 {
92 prv = outside;
93 }
94 else
95 {
96 prv = make_pair(x + ii[d], y + jj[d]);
97 }
98
99 pair<point, int> nxt = getNextPosition(make_pair(x, y), prv);
100
101 if (nxt.first != outside)
102 {
103 best[x][y][d] +=
104 solve(nxt.first.first, nxt.first.second, (nxt.second + 2) % 4);
105 }
106
107 return best[x][y][d];
108 }
109
110 void solve()
111 {
112
113 for (int i = 0; i < n; ++i)
114 {
115 for (int j = 0; j < m; ++j)
116 {
117 int dist = solve(i+1, j+1, 4);
CAPITOLUL 25. ONI 2013 532
ONI 2012
26.1 7segmente
Problema 1 - 7segmente 100 de puncte
Un indicator cu 7 segmente este un dispozitiv de a³aj electronic destinat
a³ rii unei cifre zecimale. Aceste dispozitive sunt utilizate pe scar larg în
ceasuri digitale, contoare electronice ³i alte aparate, pentru a³area informaµiilor
numerice. Cele 7 segmente au fost notate cu literele a, b, c, d, e, f, g, dup
modelul din gura al turat . A³area uneia din cifrele de la 1 la 9 const în
aprinderea anumitor segmente din cele 7, dup cum urmeaz :
Cifr 1 2 3 4 5 6 7 8 9
Segmente b, c a, b, a, b, c, b, c, f, a, c, d, a, c, d, a, b, c a, b, c, a, b, c,
aprinse d, e, g d, g g f, g e, f, g d, e, f, g d, f, g
Proiectarea diverselor sisteme de a³aj trebuie s µin cont ³i de puterea necesar pentru
a³area unei cifre. Pentru aprinderea unui segment este necesar o putere de 1 mW. Astfel, în
funcµie de cifra a³at , dispozitivul necesit o putere egal cu num rul de segmente aprinse la
a³area cifrei respective. Puterea necesar pentru a³area unui num r natural este egal cu suma
puterilor necesare a³ rii ec reia dintre cifrele sale.
Cerinµe
S se scrie un program care cite³te dou numere naturale nenule n ³i p, (num rul n având
toate cifrele nenule) ³i calculeaz :
a num rul natural k reprezentând puterea necesar pentru a³area num rului n;
a cel mai mare num r natural t, format numai din cifre nenule, mai mic sau egal decât n, care
necesit pentru a³are o putere de cel mult p mW .
Date de intrare
Prima linie a ³ierului de intrare 7segmente.in conµine dou numere naturale nenule n ³i p
(num rul n având toate cifrele nenule), desp rµite printr-un spaµiu, cu semnicaµia de mai sus.
Date de ie³ire
Fi³ierul de ie³ire 7segmente.out va conµine pe o singur linie, cele dou numere naturale
nenule k ³i t (num rul t având toate cifrele nenule), separate printr-un spaµiu, cu semnicaµia de
mai sus.
Restricµii ³i preciz ri
1 & n $ 10 ;
19
a
a 2 & p & 150;
a pentru rezolvarea primei cerinµe se va acorda 20% din punctaj, iar pentru rezolvarea celei
de-a doua cerinµe se va acorda 80% din punctaj.
Exemple:
533
CAPITOLUL 26. ONI 2012 534
7segmente.in 7segmente.outExplicaµii
7654 12 18 7511 Num rul n este 7654; puterea necesar pentru a³are este
3+6+5+4=18 mW, iar cel mai mare num r, mai mic sau egal cu
7654, format numai din cifre nenule, care necesit pentru a³are
o putere de cel mult 12 mW, este 7511.
Timp maxim de executare/test: 0.1 secunde
Memorie: total 2 MB din care pentru stiv 2 MB
Dimensiune maxim a sursei: 5 KB
Num rul de dispozitive de tip 7 segmente necesare pentru a³area num rului n este egal cu
num rul de cifre al lui n. Puterea necesar pentru a³area num rului n se calculeaz ca suma
puterilor necesare pentru a³area ec rei cifre în parte, în funcµie de num rul de segmente utilizat
la a³area ec rei cifrei, conform tabelului.
În vederea determin rii num rului t se calculeaz pentru început num rul de cifre pe care-l
poate avea acesta. Având în vedere c cifra ce consum cea mai mic putere este 1 (2 mW) ³i nu
sunt utilizate cifre de 0, determin m num rul de cifre al lui t ca ind min(num rul de cifre al lui
n, p/2).
Separ m cifrele lui n într-un vector ³i iniµializ m un alt vector, care are num rul de poziµii
egal cu num rul de cifre al lui t, cu 1. Din puterea dat sc dem puterea utilizat pentru cifrele
de 1 ³i apoi cât timp mai este putere de utilizat (putere disponibil ) ³i cifre de aat, determin m
secvenµial cifrele lui t.
Se porne³te de la vectorul care are pe toate poziµiile cifra 1 ³i se actualizeaz poziµiile acestuia
de la stânga la dreapta (de la cifra cea mai semnicativ c tre cifra cea mai puµin semnicativ ) cu
cifra ce µine cont de datele problemei pân când puterea disponibil devine nul sau se completeaz
num rul de cifre.
Pentru determinarea unei cifre se µine cont c aceasta trebuie s e cifra cea mai mare, mai
mic sau egal cu cifra de pe aceea³i poziµie a lui n ³i a c rei utilizare nu epuizeaz puterea
disponibil . La ecare selectare a unei astfel de cifre se reactualizeaz puterea r mas neutilizat .
O capcan care trebuie evitat este situaµia în care o cifr determinat pe o anumit poziµie
este strict mai mic decât cifra de pe aceea³i poziµie a lui n, situaµie în care la determinarea
urm toarelor cifre ale lui t nu trebuie s mai µinem cont de faptul c acestea trebuie s e mai
mici decât cifrele lui n de pe poziµiile corespunz toare.
17
18 pc=0;
19 for (i=0;i<w;i++)
20 pc+=x[s[i]-’0’];
21 printf("%d ",pc);
22
23 prest=p;
24 ok=0;
25 ok2=1;
26 for (i=0;i<w;i++)
27 {
28 for (j=(s[i]-’0’)*ok2+9*(1-ok2);j>0;j--)
29 if (x[j]+(w-i-1)*2<=prest)
30 break;
31
32 if (j>0)
33 {
34 ok=1;
35 printf("%d",j);
36 }
37 if (j==0 && ok==1)
38 printf("%d",j);
39 if (j<s[i]-’0’)
40 ok2=0;
41 prest-=x[j];
42 }
43
44 fclose(stdin);
45 fclose(stdout);
46 return 0;
47 }
42 case 5 : pc=pc+5;break;
43 case 6 : pc=pc+6;break;
44 case 7 : pc=pc+3;break;
45 case 8 : pc=pc+7;break;
46 case 9 : pc=pc+6;break;
47 }
48
49 n=n/10;
50 }
51
52 v[0]=i;
53 g<<pc<<" ";
54
55 // oglindesc cifrele
56 for(i=1;i<=v[0]/2;i++)
57 {
58 aux=v[i];
59 v[i]=v[v[0]+1-i];
60 v[v[0]+1-i]=aux;
61 }
62
63 // calculez numarul de cifre(nc) maxim pe care-l poate avea t
64 nc=p/2;
65 if (nc>=v[0]) nc=v[0];
66
67 // setez toate cifrele la 1
68 for(i=1;i<=nc;i++)
69 t[i]=1;
70
71 // din puterea data scad puterea utilizata pentru cifrele de 1
72 p=p-2*nc;
73
74 t[0]=nc;cc=1;
75 egalcif=1;
76 while (p>0&&cc<=t[0])
77 {
78 dmin=10;cifra=1;dmax=0;
79
80 // caut cifra corespunzatoare
81 for(i=2;i<=9;i++)
82 {
83 if (t[0]==v[0]&&egalcif==1)
84 if (i<=v[cc]&&abs(i-v[cc])<=dmin&&p-pw[i]+pw[1]>=0)
85 {
86 cifra=i;
87 dmin=abs(i-v[cc]);
88 }
89
90 if (t[0]<v[0]||egalcif==0)
91 if (i>=dmax&&p-pw[i]+pw[1]>=0)
92 {
93 cifra=i;
94 dmax=i;
95 }
96 }
97
98 // daca am setat o cifra mai mica, restul cifrelor pot fi mai mari
99 if (v[cc]-cifra!=0)
100 egalcif=0;
101
102 // asez cifra pe pozitia corecta si recalculez puterea
103 p+=pw[1];
104 p-=pw[cifra];
105 t[cc++]=cifra;
106 }
107
108 for(i=1;i<=t[0];i++)
109 g<<t[i];
110
111 g<<"\n";
112
113 f.close();
114 g.close();
115 return 0;
116 }
CAPITOLUL 26. ONI 2012 537
26.2 copaci
Problema 2 - copaci 100 de puncte
CAPITOLUL 26. ONI 2012 538
Se consider n copaci de diferite în lµimi, aaµi în linie dreapt la distanµe egale, numerotaµi
de la 1 la n. Pentru ecare copac se cunoa³te în lµimea sa Hi . Cum ³i copacii simt nevoia s
socializeze, ecare dintre ei are prieteni printre ceilalµi copaci.
Prietenii oric rui copac i se pot aa atât la stânga, cât ³i la dreapta sa. Relaµiile de prietenie
sunt denite în felul urm tor: pentru ecare copac i consider m un ³ir d1 , d2 , ..., dx reprezentând
prietenii copacului i situaµi în dreapta sa ³i un ³ir s1 , s2 , ..., sy reprezentând prietenii copacului
i situaµi în stânga acestuia. Copacii din cele dou ³iruri corespunz toare unui copac i formeaz
împreun lista prietenilor acestuia.
irurile corespunz toare copacului i se denesc astfel:
1. a d1 i 1 (dac i n, atunci copacul i nu are niciun prieten la dreapta sa, ³irul d r mânând
vid);
a pentru ecare k ' 2, dk este cel mai mic indice (1 & dk & n) cu proprietatea c dk % dk1
³i Hdk % Hdk1 . Dac dk nu exist , atunci lista de prieteni la dreapta ai copacului i s-a
încheiat ³i construirea ³irului se opre³te la acest pas.
2. a s1 i 1 (daca i 1, atunci copacul i nu are niciun prieten la stânga sa, sirul s r mânând
vid);
a pentru ecare k ' 2, sk este cel mai mare indice (1 & sk & n) cu proprietatea c sk $ sk1
³i Hsk % Hsk1 . Dac sk nu exist , atunci lista de prieteni la stânga ai copacului i s-a
încheiat ³i construirea ³irului se opre³te la acest pas.
De exemplu, în gura de mai jos sunt reprezentaµi 7 copaci, ecare având precizat sub el
valoarea în lµimii sale. Primul copac din stânga are indicele 1, iar ultimul are indicele 7.
Copacul 1 este prieten cu copacul 2 ind vecini, cu
copacul 5 (deoarece copacul 5 este primul din dreapta
lui 2 cu în lµimea mai mare strict decât în lµimea lui
2). La dreapta copacului 5 nu exista niciun copac cu
în lµimea mai mare strict decât a sa, deci singurii prieteni
ai copacului 1 sunt 2 ³i 5.
Pentru copacul 3, prietenii la stânga sa sunt copacii 2 ³i 1, iar cei de la dreapta sa sunt copacii
4 ³i 5. Pentru copacul 6, singurul prieten la stânga este copacul 5, iar la dreapta copacul 7.
Copacul 7 poate avea prieteni doar la stânga, ace³tia sunt 6 ³i 5 (la stânga copacului 5 nu mai
exist niciun copac cu în lµimea mai mare strict decât 8).
Gr dinarul Marian vrea s aleag 3 copaci diferiµi dintre cei n pentru a-i planta în alt gr din .
El dore³te ca dintre cei 3 copaci, oricum ar alege A si B , 2 dintre ei, atunci A este prieten cu B ³i
B este prieten cu A (relaµiile de prietenie se consider cele stabilite iniµial). Marian are mai multe
opµiuni ³i se întreab în câte moduri distincte poate alege cei 3 copaci cu proprietatea cerut .
Cerinµe
Determinaµi în câte moduri se pot alege 3 copaci diferiµi dintre cei n cu proprietatea c , oricum
am alege 2 copaci dintre cei 3, e ace³tia copacul A ³i copacul B , atunci A este prieten cu B ³i B
este prieten cu A.
Date de intrare
Fi³ierul de intrare copaci.in conµine pe prima linie un num r natural n, reprezentând num rul
de copaci, iar pe a doua linie n numere naturale nenule, separate prin câte un spaµiu, reprezentând
în lµimile copacilor.
Date de ie³ire
Fi³ierul de ie³ire copaci.out va conµine pe prima linie un num r natural reprezentând num rul
de moduri în care Marian poate alege 3 copaci cu proprietatea din enunµ.
Restricµii ³i preciz ri
a 1 & n & 200.000;
a 1 & Hi & 200;
a nu vor exista 2 copaci al turaµi cu aceea³i în lµime;
a dou triplete de copaci se consider distincte dac exist cel puµin un copac din primul triplet
care nu se a ³i în al doilea triplet;
a pentru 30% din teste, 1 & n & 200.
CAPITOLUL 26. ONI 2012 539
Exemple:
copaci.in copaci.out Explicaµii
7 4 Copacul 1 este prieten cu copacii: 2, 5
6423858 Copacul 2 este prieten cu copacii: 1, 3, 4, 5
Copacul 3 este prieten cu copacii: 1, 2, 4, 5
Copacul 4 este prieten cu copacii: 1, 2, 3, 5
Copacul 5 este prieten cu copacii: 1, 2, 4, 6, 7
Copacul 6 este prieten cu copacii: 5, 7
Copacul 7 este prieten cu copacii: 5, 6
Modurile in care Marian poate alege cei 3 copaci sunt:
(1, 2, 5), (2, 4, 5), (2, 3, 4), (5, 6, 7).
Timp maxim de executare/test: 0.7 secunde
Memorie: total 16 MB din care pentru stiv 4 MB
Dimensiune maxim a sursei: 10 KB
Se observ c dac am avea un triunghi (A, B, C) cu A < B < C, atunci copacul B trebuie s
aib în lµimea minim dintre cei 3 copaci.
O alt observaµie este c dac x m copacul B ca ind de în lµime minim dintre cei 3 copaci,
atunci exist cel mult un triunghi centrat in B.
Astfel trebuie s iter m de la 1 la N ³i x m copacul B, iar A ³i C le stabilim ca ind primii
copaci din stânga, respectiv din dreapta copacului B, cu proprietatea c au în lµimile mai mari sau
egale cu în lµimea copacului B. Acesta este un posibil triunghi, îns trebuie s veric m concret
dac A ³i C sunt prieteni reciproci. Pentru aceasta folosim 2 vectori ST i ³i DRi care semnic
pân unde în stânga, respectiv în dreapta, copacul i are în lµimea maxim . Vectorii se pot calcula
în O N Hmax sau, mai ecient, cu o stiv în complexitate O N . Ambele metode intr în
timp.
Complexitate nal : O N Hmax sau O N .
1 #include <iostream>
2 #include <algorithm>
3 #include <cstdio>
4 #include <cstring>
5
6 using namespace std;
7
8 #define maxn 200010
9 #define valmax 210
10
11 int N, sol;
12 int ST[maxn], DR[maxn], H[maxn];
13 int val[valmax];
14
15 /** functii calc_st() si calc_dr() se pot implementa eficient
16 folosind o stiva **/
17 void calc_st()
18 {
19 memset(val, 0, sizeof(val));
20 int i, j, p;
21
22 for(i=1; i<=N; i++)
23 {
24 p = 0;
25 for(j=H[i]; j<valmax; j++)
26 {
27 p = max(p, val[j]);
28 }
29
30 ST[i] = p;
31 val[ H[i] ] = i;
32 }
33 }
34
35 void calc_dr()
36 {
37 memset(val, 0, sizeof(val));
38 int i, j, p;
39
40 for(i=N; i>=1; i--)
41 {
42 p = N+1;
43 for(j=H[i]; j<valmax; j++)
44 {
45 if(val[j]) p = min(p, val[j]);
46 }
47
48 DR[i] = p;
49 val[ H[i] ] = i;
50 }
51 }
52
53 int main()
54 {
55 FILE *f1=fopen("copaci.in", "r"), *f2=fopen("copaci.out", "w");
56 int i, j, p, q;
57
58 fscanf(f1, "%d\n", &N);
59 for(i=1; i<=N; i++)
60 {
61 fscanf(f1, "%d", &H[i]);
62 }
63
64 calc_st();
65 calc_dr();
66
67 for(i=2; i<=N-1; i++)
68 {
69 // consideram copacul i ca fiind de inaltime minima
70 // din triunghiul (A, i, B)
71 // poate exista cel mult un triunghi centrat in i
72 p = ST[i], q = DR[i];
73 if(p == 0 || q == N+1) continue;
74
75 //trebuie sa verificam daca p vede pe i, daca q vede pe i
76 //si daca p si q se vad reciproc
CAPITOLUL 26. ONI 2012 542
77 if(ST[i] <= p && DR[i] >= q && DR[p] >= q && ST[q] <= p)
78 {
79 //cout<<p<<" "<<i<<" "<<q<<endl;
80 sol ++;
81 }
82 }
83
84 fprintf(f2, "%d\n", sol);
85
86 fclose(f1); fclose(f2);
87 return 0;
88 }
26.3 intersecµii
Problema 3 - intersecµii 100 de puncte
Dreptunghiul ABCD are laturile de lungimi w ³i h, numere naturale pare. Acest dreptunghi
este desenat pe o foaie de matematic ³i este descompus în w h p trate de latur 1.
Vârfurile A, B , C ³i D sunt plasate în colµurile unor p trate
de latur 1. Se alege un punct P din interiorul dreptunghiului
ABCD, situat în colµul unui p trat de latur 1 ³i se une³te prin seg-
mente de dreapt cu cele patru colµuri ale dreptunghiului. Unele
segmente intersecteaz p trate de latur 1 în exact dou puncte
distincte, altele într-un singur punct.
Numim p trat 2-intersectat, un p trat de latur 1 intersectat
de un segment în exact 2 puncte distincte. în dreptunghiul din gura al turat , segmentul P A
trece prin 3 p trate 2-intersectate, segmentul P B trece prin 9 p trate 2-intersectate, segmentul
P C trece prin 13 p trate 2-intersectate, iar segmentul P D prin 7.
Cerinµe
Se dau dou numere naturale w ³i h reprezentând lungimile laturilor dreptunghiului ABCD,
un num r natural n ³i n numere naturale x1 , x2 , ..., xn . Punctul P se plaseaz , pe rând, în toate
punctele interioare dreptunghiului ABCD care sunt colµuri ale unor p trate de latur 1. Pentru
ecare valoare xi (1 & i & n), determinaµi num rul de segmente distincte care trec prin exact
xi p trate 2-intersectate.
Date de intrare
Fi³ierul de intrare intersectii.in conµine pe prima linie trei numere naturale w, h (reprezen-
tând dimensiunile dreptunghiului) ³i n. Urm toarele n linii conµin câte un num r natural xi cu
semnicaµia de mai sus.
Date de ie³ire
Fi³ierul de ie³ire intersectii.out va conµine n linii. Pe ecare linie i va scris num rul de
segmente care trec prin exact xi p trate 2-intersectate, obµinute dup plasarea punctului P în
ecare colµ al unui p trat de latur 1 din interiorul dreptunghiului ABCD.
Restricµii ³i preciz ri
a 2 & w, h & 2 000 numere naturale pare;
a 2 & n & 100 000;
a punctul P se alege doar în interiorul dreptunghiului;
a pentru 40% din teste 2 & w, n, h & 500.
Exemple:
intersectii.in intersectii.out Explicaµii
46235 12 4 Se pot obµine 12 segmente care trec prin exact 3 p trate
2-intersectate ³i 4 segmente care trec prin exact 3 p trate
2-intersectate.
Timp maxim de executare/test: 0.2 secunde
Memorie: total 2 MB din care pentru stiv 2 MB
Dimensiune maxim a sursei: 5 KB
CAPITOLUL 26. ONI 2012 543
Se observ c dimensiunile dreptunghiului sunt numere pare, dar, nu putem restrânge analiza
problemei la un sfert din dimensiunea dreptunghiului iniµial decât dac studiem unele cazuri
particulare.
Nu are importanµ cum alegem colµul x, deci putem studia doar cazul colµului A iar la
nal vom multiplica rezultatul cu patru. Putem considera c vârful A, este originea unui sistem
cartezian de coordonate.
Pentru a calcula num rul de intersecµii al unui segment P A, se observ c pentru un punct
P de coordonate x ³i y prime intre ele, din acest dreptunghi, avem intersectate exact x y 1
p trate de latura 1, iar daca x ³i y nu sunt prime între ele, atunci dac d cmmdc x, y , num rul
de intersecµii al segmentului P A va in acest caz x y d.
Pentru a reduce complexitatea algoritmului, putem face o optimizare a calculului valorii cmmdc
pentru toate posibilit µile de alegere ale coordonatelor punctului P realizând o variant 2D a
ciurului lui Eratostene. Vom folosi un vector de vizitare a coordonatelor ³i pentru un punct P xy
nevizitat, cu cmmdc x, y 1, marc m ca vizitate punctele din dreptunghi de coordonate d x
³i d y nevizitate ca având un num r de intersecµii dat de valoarea d x y 1. Astfel voi
contoriza toate valorile distincte de intersecµii, având astfel posibilitatea de a r spunde la ecare
test în timp 1.
Deci complexitatea algoritmului devine O h w n. .
35
36 if (W%2==0)
37 for (j=1;j<=H12;j++)
38 {
39 x=W2;
40 y=j;
41 while (y){r=x%y; x=y; y=r;}
42 s[W2+j-x]+=4;
43
44 x=W2;
45 y=H-j;
46 while (y){r=x%y ;x=y; y=r;}
47 s[W2+H-j-x]+=4;
48 }
49
50 if (H%2==0)
51 for (i=1;i<=W12;i++)
52 {
53 x=i;
54 y=H2;
55 while (y){r=x%y; x=y; y=r;}
56 s[i+H2-x]+=4;
57
58 x=W-i;
59 y=H2;
60 while (y){r=x%y; x=y; y=r;}
61 s[W-i+H2-x]+=4;
62 }
63
64 if (W%2==0 && H%2==0)
65 {
66 x=W2;
67 y=H2;
68 while (y){r=x%y; x=y; y=r;}
69 s[W2+H2-x]+=4;;
70 }
71
72 for (i=1;i<=Q;i++)
73 {
74 scanf("%d",&k);
75 printf("%d\n",s[k]);
76 }
77
78 fclose(stdout);
79 fclose(stdin);
80 return 0;
81 }
26 scanf("%d",&k);
27 printf("%d\n",4*s[k]);
28 }
29
30 fclose(stdout);
31 fclose(stdin);
32 return 0;
33 }
10 int main()
11 {
12 freopen("intersectii.in","r",stdin);
13 freopen("intersectii.out","w",stdout);
14 scanf("%d%d%d",&W,&H,&NT);
15
16 for(i=1;i<W;i++)
17 for(j=1;j<H;j++)
18 if(!v[i][j])
19 {
20 n=i+j-1;
21 for(I=i,J=j,N=n;I<W && J<H;I+=i,J+=j,N+=n)
22 {
23 v[I][J]=1;
24 c[N]++;
25 if(poz<N) poz=N;
26 }
27 }
28
29 //for(i=1;i<=poz;++i) c[i]+=c[i-1];
30 for(;NT;NT--)
31 {
32 scanf("%d",&i);
33 if(i>poz)
34 printf("0\n");
35 else
36 printf("%d\n",4*c[i]);
37 }
38
39 return 0;
40 }
42 {
43 if(d[j] == 1 || d[i] == 1)
44 a[j] = 1;
45
46 p = j / d[j];
47 q = i / a[p];
48
49 if(q % d[j] == 0)
50 a[j] = d[j] * a[p];
51 else
52 a[j] = a[p];
53
54 if(i == 1)
55 {
56 p = j;
57 res[p] += 4;
58 }
59 else
60 if(j == 1)
61 {
62 p = i;
63 res[p] += 4;
64 }
65 else
66 if(i == j)
67 {
68 p = i;
69 res[p] += 4;
70 }
71 else
72 {
73 p = i + j - a[j];
74 res[p] += 4;
75 }
76 }
77 }
78
79 while(T--)
80 {
81 fscanf(f1, "%d\n", &p);
82 fprintf(f2, "%d\n", res[p]);
83 }
84
85 fclose(f1);
86 fclose(f2);
87 return 0;
88 }
26.4 palindrom
Problema 4 - palindrom 100 de puncte
Cu mult timp în urm , într-un t râm foarte, foarte îndep rtat, a existat o µar numit Tna-
map. Locuitorii acestei µ ri puteau s aplice instantaneu transform ri asupra cifrelor unui num r,
utilizând un tablou de corespondenµe T.
O cifr c a unui num r poate înlocuit cu
cifra corespunz toare ei, T c.
Dalv ³i Sogard, doi indivizi speciali ai acestei societ µi ciudate se aau în drum spre INO când
au con³tientizat c pot transforma instantaneu, folosind num r minim de transform ri de cifre,
orice num r N într-un palindrom divizibil cu un num r natural K . Dac sunt mai multe astfel
de numere, îl determin pe cel mai mare.
Voi puteµi?
Cerinµe
Cunoscând valorile T0 , T1 , ..., T9 , num rul ce urmeaz a transformat N ³i num rul K
(divizorul palindromului), determinaµi:
1. Num rul maxim care se poate obµine aplicând transform ri succesive num rului N dat.
2. Cel mai mare dintre palindromurile divizibile cu K , ce se pot obµine din num rul N ,
efectuând un num r minim de transform ri asupra cifrelor num rului dat, respectiv asupra cifrelor
numerelor obµinute pe parcurs.
CAPITOLUL 26. ONI 2012 548
Date de intrare
Pe prima linie a ³ierului palindrom.in sunt memorate 10 cifre distincte, separate prin câte
un spaµiu, reprezentând valorile T0 , T1 , ..., T9 .
Pe a doua linie sunt memorate cifrele num rului N , iar pe cea de a treia linie un num rul
natural K .
Date de ie³ire
Fi³ierul palindrom.out va conµine pe prima linie num rul maxim care se poate obµine aplicând
transform ri succesive num rului N , iar pe a doua linie palindromul divizibil cu K , de valoare
maxim , ce se poate obµine din num rul N , efectuând un num r minim de transform ri asupra
cifrelor.
Restricµii ³i preciz ri
1 & N $ 10
1.000.000
a ;
a N are un num r par de cifre;
a 2 & K & 20;
a se garanteaz faptul c toate testele au soluµie;
a pentru rezolvarea primei cerinµe se va acorda 20% din punctaj, iar pentru rezolvarea celei
de-a doua cerinµe se va acorda 80% din punctaj.
Exemple:
palindrom.in palindrom.out Explicaµii
0465127893 4994
1234 4224 1234 4234 4634 4734 4834 4934 4954
3 4924 4964 4974 4984 4994
Num rul N trece prin urm toarele st ri înainte de a de-
veni palindrom cu valoarea maxim , divizibil cu 3: 1234
4234 4254 4224.
Timp maxim de executare/test: 0.4 secunde
Memorie: total 256 MB din care pentru stiv 64 MB
Dimensiune maxim a sursei: 10 KB
123 init();
124 solve();
125 write();
126
127 fclose(stdin);
128 fclose(stdout);
129 return 0;
130 }
65
66 void cerintaA()
67 {
68 for (int i = 0; i < N; ++i)
69 {
70 int j = 9;
71 while (cost[x[i]][j] == -1)
72 --j;
73 printf("%d", j);
74 }
75
76 printf("\n");
77 }
78
79 void cerintaB()
80 {
81 preprocesarePuteri10();
82
83 costMin[1][0] = 0;
84 for (int i = 1; i < K; ++i)
85 costMin[1][i] = -1;
86
87 for (int i = 0, L = N / 2; i < L; ++i)
88 {
89 int st = x[i];
90 int dr = x[N - i - 1];
91 k = i & 1;
92
93 for (int ii = 0; ii < K; ++ii)
94 partial[ii][0] = partial[ii][1] =
95 costMin[k][ii] = rez[i][ii] = back[i][ii] = -1;
96
97 for (int j = 9; i == 0 ? j >= 1 : j >= 0; --j)
98 {
99 if (cost[st][j] != -1 && cost[dr][j] != -1)
100 {
101 int costTranf = cost[st][j] + cost[dr][j];
102 int restAdaugat = (j * putere[i] + j * putere[N-1-i]) % K;
103
104 if (partial[restAdaugat][0] == -1
105 || costTranf < partial[restAdaugat][0])
106 {
107 partial[restAdaugat][0] = costTranf;
108 partial[restAdaugat][1] = j;
109 }
110 }
111 }
112
113 for (int j = 0; j < K; ++j)
114 printf("part %d: %d %d\n", j, partial[j][0], partial[j][1]);
115
116 for (int j = 0; j < K; ++j)
117 {
118 for (int l = 0; l < K; ++l)
119 {
120 if (partial[l][0] == -1 || costMin[1-k][j] == -1)
121 continue;
122
123 int restTarget = (j + l) % K;
124
125 if (costMin[k][restTarget] == -1
126 || costMin[k][restTarget]
127 > costMin[1 - k][j] + partial[l][0])
128 {
129
130 costMin[k][restTarget] = costMin[1-k][j] + partial[l][0];
131 rez[i][restTarget] = partial[l][1];
132 back[i][restTarget] = j;
133 }
134
135 if (costMin[k][restTarget]
136 == costMin[1 - k][j] + partial[l][0])
137 {
138 if (compar[j][restTarget] == 0)
139 {
140 if (rez[i][restTarget] < partial[l][1])
CAPITOLUL 26. ONI 2012 553
141 {
142 costMin[k][restTarget] = costMin[1 - k][j]
143 + partial[l][0];
144 rez[i][restTarget] = partial[l][1];
145 back[i][restTarget] = j;
146 }
147 }
148 else
149 if (compar[j][restTarget] == 1)
150 {
151 costMin[k][restTarget] = costMin[1 - k][j]
152 + partial[l][0];
153 rez[i][restTarget] = partial[l][1];
154 back[i][restTarget] = j;
155 }
156 }
157 }
158 }
159
160 for (int j = 0; j < K; ++j)
161 printf("%d : %d %d %d\n", j,costMin[k][j],rez[i][j],back[i][j]);
162
163 //refac comparatiile
164 for (int j = 0; j < K; ++j)
165 for (int l = 0; l < K; ++l)
166 if (compar[j][l] == 0)
167 if (rez[i][j] > rez[i][l])
168 compar[j][l] = 1;
169 else if (rez[i][j] < rez[i][l])
170 compar[j][l] = -1;
171 }
172
173 int poz = 0;
174 int i = N / 2 - 1;
175 while (i >= 0)
176 {
177 rezFinal[cnt++] = rez[i][poz];
178 poz = back[i][poz];
179 --i;
180 }
181
182 for (int i = N / 2 - 1; i >= 0; --i)
183 printf("%d", rezFinal[i]);
184 for (int i = 0; i < N / 2; ++i)
185 printf("%d", rezFinal[i]);
186 printf("\n");
187 printf("%d\n", costMin[k][0]);
188 }
189
190 int main(int argc, char *argv)
191 {
192 citire();
193
194 preprocesareCosturiTranzitie();
195
196 cerintaA();
197 //cerintaB();
198
199 return 0;
200 }
89
90 for(i=1; i<=jumatate; i++)
91 fprintf(f2, "%c", sol[i]);
92
93 for(i=jumatate; i>=1; i--)
94 fprintf(f2, "%c", sol[i]);
95
96 fprintf(f2, "\n");
97
98 //a doua cerinta
99 for(i=jumatate+1; i>=1; i--)
100 for(j=0; j<K; j++)
101 D[i][j] = inf;
102
103 D[jumatate+1][0] = 0;
104
105 for(i=jumatate; i>=1; i--)
106 {
107 int cif1 = A[i] - ’0’;
108 int cif2 = A[N-i+1] - ’0’;
109
110 for(j=0; j<K; j++)
111 {
112 int start = 0;
113 if(i == 1) start = 1; //prima cifra a palindromului nu poate fi 0
114
115 for(p=start; p<=9; p++)
116 if(ajunge[cif1][p] >= 0 && ajunge[cif2][p] >= 0)
117 {
118 int nou_rest = (j + p * (put[N-i] + put[i-1])) % K;
119 D[i][nou_rest] = min(D[i][nou_rest], D[i+1][j] +
120 ajunge[cif1][p] + ajunge[cif2][p]);
121 }
122 }
123 }
124
125 int cost = D[1][0];
126 int rest = 0;
127
128 if(cost >= N * 10)
129 {
130 fprintf(f2, "-1\n");
131 fclose(f1);
132 fclose(f2);
133 return 0;
134 }
135
136 for(i=1; i<=jumatate; i++)
137 {
138 //calculez sol[i]
139 int cif1 = A[i] - ’0’;
140 int cif2 = A[N-i+1] - ’0’;
141
142 int finish = 0;
143 if(i == 1) finish = 1;
144
145 for(q=9; q>=finish; q--)
146 {
147 if(ajunge[cif1][q] >= 0 && ajunge[cif2][q] >= 0)
148 {
149 p = (q * (put[N-i] + put[i-1])) % K;
150 int nou_rest = rest - p;
151 if(nou_rest < 0) nou_rest += K;
152
153 if(D[i+1][nou_rest]+ajunge[cif1][q]+ajunge[cif2][q] == cost)
154 {
155 //este ok ok ok
156 sol[i] = (q + ’0’);
157
158 cost -= (ajunge[cif1][q] + ajunge[cif2][q]);
159 rest = nou_rest;
160
161 break;
162 }
163 }
164 }
CAPITOLUL 26. ONI 2012 556
165 }
166
167 for(i=1; i<=jumatate; i++)
168 fprintf(f2, "%c", sol[i]);
169
170 for(i=jumatate; i>=1; i--)
171 fprintf(f2, "%c", sol[i]);
172
173 fprintf(f2, "\n");
174
175 fclose(f1);
176 fclose(f2);
177 return 0;
178 }
26.5 sstabil
Problema 5 - sstabil 100 de puncte
Numim num r sstabil orice num r natural care este format dintr-o singur cifr sau care are
suma oric ror dou cifre vecine strict mai mare decât nou .
Asupra oric rui num r care nu este sstabil se pot efectua operaµii de înlocuire a oric ror dou
cifre vecine care au suma strict mai mic decât zece cu o cifr egal cu suma lor.
Operaµiile de înlocuire pot aplicate, în acela³i condiµii, ³i asupra numerelor rezultate dup
ecare înlocuire, de câte ori este nevoie, pân când se obµine un num r sstabil.
De exemplu, 291 este num r sstabil deoarece 2+9>9 ³i 9+1>9, iar 183 nu este sstabil pentru
c 1+8<10. Din num rul 2453, efectuând o singur înlocuire, putem obµine 653 sau 293 (num r
sstabil) sau 248. Num rul 653, neind sstabil, permite o nou operaµie de înlocuire, obµinând
astfel num rul 68, care este sstabil. Analog, din num rul 248 se poate obµine num rul sstabil 68.
Cerinµe
Scrieµi un program care s determine cel mai mare num r natural sstabil care se poate obµine
dintr-un num r natural dat, aplicând una sau mai multe operaµii de înlocuire de tipul menµionat.
Date de intrare
Fi³ierul de intrare sstabil.in conµine pe prima linie un num r natural n, reprezentând num rul
de cifre al num rului dat, iar pe linia a doua, separate prin câte un spaµiu, cifrele acestui num r.
Date de ie³ire
Fi³ierul de ie³ire sstabil.out va conµine pe o linie num rul sstabil maxim obµinut.
Restricµii ³i preciz ri
a 1 & n & 1 000 000
Exemple:
sstabil.in sstabil.out Explicaµii
510451 191 10451 1091 191
552832 785
52832 7832 785
Timp maxim de executare/test: 1.0 secunde
Memorie: total 16 MB din care pentru stiv 4 MB
Dimensiune maxim a sursei: 5 KB
De la dreapta la stânga se determin cifrele , cât mai mici, ale unui num r sstabil. Procedând
astfel vom obµine un num r sstabil cu num r maxim de cifre ³i care are primele cifre cele mai mari
(faµ de un alt num r sstabil care ar avea acela³i num r de cifre). Vom demonstra în continuare.
Demonstraµia soluµiei pentru problema âsstabil: ...
CAPITOLUL 26. ONI 2012 557
22 j=r; s=0;
23 do
24 {
25 s=s+a[j];
26 j--;
27 } while (s<10);
28
29 p=r;
30 t=a[p];
31
32 while (s-t>9 || t+b[k]<10)
33 {
34 p--;
35 t=t+a[p];
36 }
37
38 k++;
39 b[k]=t;
40 r=p-1;
41 }
42
43 for (i=k;i>=1;i--)
44 printf("%d",b[i]);
45
46 fclose(stdout);
47 fclose(stdin);
48 return 0;
49 }
26.6 unuzero
Problema 6 - unuzero 100 de puncte
Se consider un ³ir format din N 2 cifre binare, care conµine cel puµin o cifr 1 ³i cel puµin
trei cifre 0; prima ³i ultima cifr a ³irului sunt 0.
Numim 1-secvenµ o succesiune format numai din cifre 1, aate pe poziµii consecutive în acest
³ir, delimitat de câte o cifr 0.
Corina construie³te un astfel de ³ir, în care num rul de cifre 1 ale ec rei 1-secvenµe s e
cuprins între dou numere naturale date, p ³i q (p & q ).
Cerinµe
Scrieµi un program care s determine un num r natural K , egal cu restul împ rµirii la 666013
a num rului de ³iruri distincte, de tipul celui construit de Corina.
Date de intrare
Fi³ierul de intrare unuzero.in conµine pe prima linie num rul natural N , iar pe cea de a doua
linie numerele naturale p ³i q (p & q ), separate printr-un spaµiu.
Date de ie³ire
Fi³ierul de ie³ire unuzero.out va conµine pe prima linie num rul natural K cerut.
Restricµii ³i preciz ri
a 1 & p & q $ N $ 1 000 000. a Pentru 20% din teste N & 25, iar pentru alte 40% din teste
25 $ N & 1 000.
Exemple:
unuzero.in unuzero.out Explicaµii
523 8 0000110
0001100
0001110
0011000
0011100
0110000
0110110
0111000
CAPITOLUL 26. ONI 2012 560
Se observ c problema nu poate obµine decât 20 de puncte dac vom încerca s gener m toate
soluµiile posibile pe care apoi s contoriz m si 60 de puncte pentru lungimi mai mici de 1000.
Ideea de rezolvare se bazeaz pe observarea unei relaµii de recurenµ ce se poate deduce dup o
scurt analiz . Putem considera c utiliz m cifrele zero ³i unu iar secvenµele c utate sunt formate
din valori successive de unu. Dac presupunem c am format deja o secvenµ de 1 pentru o lungime
dat , atunci în stânga va evident 0.
Fie U i, num rul de conguraµii corecte de lungime i, terminate cu 1 ³i Z i, num rul de
conguraµii corecte de lungime i, terminate cu 0.
Atunci, avem relaµia de recurenµ urm toare:
ia
U i = Z j
j ib
31 s[i]=s[i-1]+z[i];
32 s[i]%=mod;
33 }
34
35 out<<(z[n]+u[n]-1+(z[n]+u[n]-1<0?mod:0))%mod<<’\n’;
36 out.close();
37 return 0;
38 }
7 int u[1000100],z[1000100],n;
8
9 int main()
10 {
11 ifstream in("unuzero.in");
12 ofstream out("unuzero.out");
13
14 in>>n>>a>>b;
15 z[0]=1;
16 z[1]=1;
17 if(a==1) u[1]=1;
18 for(int i=2;i<=n;++i)
19 {
20 z[i]=z[i-1]+u[i-1]; // daca punem 0
21 z[i]%=mod;
22 for(int j=i-b;j<=i-a;++j) // daca punem 1
23 {
24 if(j>=0)
25 {
26 u[i]+=z[j];
27 u[i]%=mod;
28 }
29 }
30 }
31
32 out<<(z[n]+u[n]-1+(z[n]+u[n]-1<0?mod : 0))%mod<<’\n’;
33 out.close();
34 return 0;
35 }
44
45 fprintf(f2, "%d\n", (mod + n[N] - 1) % mod);
46
47 fclose(f1);
48 fclose(f2);
49 return 0;
50 }
Capitolul 27
ONI 2011
27.1 poligon
Problema 1 - poligon 100 de puncte
Poligonul de tragere este un teren special amenajat în cadrul c ruia se fac exerciµii ³i se execut
trageri cu arme de foc. Comandantul plaseaz câte o µint în toate punctele aate la distanµele
Ri , 1 & i & n faµ de punctul de tragere (origine) ³i care au coordonatele carteziene numai numere
naturale nenule.
Speciali³tii în armament români au creat recent o nou arm sub forma unui tun laser care
î³i lanseaz razele pe o traiectorie rectilinie ³i are capacitatea de a distruge toate µintele aate pe
direcµia de tragere.
Cerinµe
tiind c tunul laser se g se³te în originea sistemului de
coordonate, s se scrie un program care s determine: num -
rul de µinte, num rul minim de lovituri de tun laser necesare
pentru a distruge toate µintele precum ³i num rul de µinte
doborâte la ecare lovitur .
Spre exemplu, dac avem n 6 distanµe (5, 7, 10, 13, 15,
17) pentru care se încearc plasarea µintelor, atunci în poligon
se vor plasa 10 µinte, va nevoie de 6 lovituri pentru a doborî
toate µintele iar la ecare lovitur se vor doborî respectiv 1,
1, 3, 3, 1, 1 µinte.
Date de intrare
Fi³ierul de intrare poligon.in conµine pe prima linie num rul n de distanµe la care vor
plasate µinte, iar pe a doua linie n numere naturale nenule distincte separate printr-un spaµiu, ce
reprezint aceste distanµe.
Date de ie³ire
Fi³ierul de ie³ire poligon.out va conµine 3 linii. Pe prima linie se va scrie num rul µintelor
plasate în poligon. Pe a doua linie se va scrie num rul minim de lovituri de tun laser cu care se pot
doborî toate µintele, iar pe a treia linie se va scrie num rul de µinte doborâte la ecare lovitur ,
separate printr-un spaµiu, în ordinea cresc toare a unghiurilor direcµiilor cu axa OX .
Restricµii ³i preciz ri
a 1 & n & 1000
a 1 & Ri & 1000
a pentru ecare set de date de intrare, în poligon va exista cel puµin o µint .
a se acord :
- 20% din punctaj pentru determinarea corect a num rului de µinte.
- 40% din punctaj pentru determinarea corect a num rului minim de lovituri.
- 40% din punctaj pentru determinarea corect a num rului de µinte doborâte la ecare lovi-
tur .
564
CAPITOLUL 27. ONI 2011 565
Exemple:
poligon.in poligon.out Explicaµii
6 10 Avem 6 distante: 5,10,15,7,13,17.
5 10 15 7 13 17 6 În poligon vor plasate 10 µinte (punctele negre marcate pe
113311 gur ) care pot doborâte din 6 lovituri iar la ecare lovitur
se vor doborî câte 1, 1, 3, 3, 1, 1 µinte.
Timp maxim de executare/test: 0.4 secunde
Memorie: total 2 MB
Dimensiune maxim a sursei: 5 KB
Observ m c pentru a determina µintele active din poligon trebuie determinat num rul de
2 2 2
soluµii al ecuaµiei R x y unde R reprezint raza cercurilor de activare. în vederea rezolv rii
³i cerinµelor ulterioare, coordonatele µintelor active se vor înc rca într-o structura de date, pe care
se vor face interog ri suplimentare. Mic³orarea timpului de rezolvare a acestei ecuaµii are la baz
observaµia c soluµiile sunt simetrice faµ de prima bisectoare.
În vederea determin rii num rului minim de lovituri trebuie s determin m câte drepte dis-
tincte se formeaz unind coordonatele µintelor active cu originea sistemului de axe. Având în
vedere îns c trebuie s determin m ³i num rul de puncte coliniare de pe ecare dreapta, în
sens trigonometric, vom face sortarea coordonatelor µintelor active dup panta acestora. Se poate
utiliza relaµia conform c reia dac dou puncte A x1 , y1 ³i B x2 , y2 sunt coliniare cu originea
sistemului de axe atunci x1 y2 x2 y1 .
Dup sortare se determin câte puncte fac parte din aceea³i categorie ³i se a³eaz rezultatele.
32
33 f2<<c<<"\n";
34 for (i=1;i<c;i++)
35 for (j=i+1;j<=c;j++)
36 if (x[i]*y[j]>x[j]*y[i])
37 {
38 aux=x[i]; x[i]=x[j]; x[j]=aux;
39 aux=y[i]; y[i]=y[j]; y[j]=aux;
40 }
41
42 x[0]=0; y[0]=1;
43 s=0;
44 for (i=1;i<=c;i++)
45 {
46 if (x[i-1]*y[i]<x[i]*y[i-1])
47 s++;
48 }
49
50 f2<<s<<"\n";
51 s=1;
52 for (i=2;i<=c;i++)
53 {
54 if (x[i-1]*y[i]==x[i]*y[i-1])
55 {
56 s++;
57 }
58 else
59 {
60 f2<<s<<" ";
61 s=1;
62 }
63 }
64
65 f2<<s;
66 f2.close();
67 f1.close();
68 return 0;
69 }
27.2 stalpi
Problema 2 - stalpi 100 de puncte
Între doi stâlpi verticali aaµi pe malurile unui râu (de o parte ³i de alta a râului) se a
legate dou cabluri bine întinse, paralele cu solul, având distanµa dintre ele egal cu d centimetri.
Cablurile sunt folosite pentru traversarea râului în caz de inundaµii. Stâlpii sunt notaµi cu A ³i B ,
iar cablurile cu 1 ³i 2 ca în gura de mai jos.
Pe cabluri exist desenate câte n puncte colorate cu diverse culori, culorile ind codicate prin
numerele 1, 2, 3,..., k . Poziµia punctelor pe ecare cablu este dat prin distanµa faµ de stâlpul
A pentru ecare punct. Punctele de pe ecare cablu sunt numerotate cu 1, 2, 3 ,..., n. Pe ecare
cablu exist cel puµin un punct colorat cu ecare culoare. Pentru a u³ura deplasarea pe cablu,
primarul hot r ³te s lege cu sârm perechi de puncte de aceea³i culoare, unul de pe primul cablu,
iar cel lalt de pe al doilea cablu, astfel încât:
- pentru ecare culoare s existe o singur pereche de puncte între care s e leg tur ;
- lungimea total de sârm folosit s e minim .
Cerinµe
S se scrie un program care determin lungimea minim a sârmei ce va folosit pentru
rezolvarea problemei ³i o mulµime de perechi de puncte ce urmeaz a legate pentru a obµine
acest minim.
Date de intrare
Fi³ierul de intrare stalpi.in va conµine:
- pe prima linie numerele naturale nenule n, d separate printr-un spaµiu;
- pe a doua linie n perechi de numere, formate din distanµa faµ de stâlpul A la ecare punct
³i culoarea asociat punctului, separate prin câte un spaµiu, aate pe cablul 1;
CAPITOLUL 27. ONI 2011 567
- pe a treia linie n perechi de numere, formate din distanµa faµ de stâlpul A la ecare punct
³i culoarea asociat punctului, separate prin câte un spaµiu, aate pe cablul 2.
Date de ie³ire
Fi³ierul de ie³ire stalpi.out va conµine pe prima linie valoarea minim cerut , iar pe urm toa-
rele k linii numerele de ordine ale punctelor ce vor legate cu sârm , separate printr-un spaµiu,
întâi cele de pe cablu 1, urmate de cele de pe cablu 2, în ordinea cresc toare a culorilor.
Restricµii ³i preciz ri
a 1 & n & 10 000
a 1 & k & 100
a 1 & d & 1 000
a Distanµa dintre cei doi stâlpi A ³i B este 30 000.
a Distanµele de la stâlpul A la puncte sunt numere naturale.
a Distanµa minim va a³at trunchiat la primele 3 zecimale.
a Toate punctele de pe un cablu sunt distincte.
a Se acord 40% din punctaj pentru determinarea corect a minimului din cerinµ .
Exemple:
stalpi.in stalpi.out Explicaµii
3 100 211.803 Sunt n 3 perechi de puncte, k 2 culori, codicate cu 1 ³i 2.
50 1 200 2 100 1 32 Necesarul minim de sârm este 211.803.
250 2 100 1 300 2 21 Se leag punctul P3 de punctul Q2 (ambele au culoarea 1).
Se leag punctul P2 de punctul Q1 (ambele au culoarea 2).
Timp maxim de executare/test: 0.2 secunde
Memorie: total 4 MB
Dimensiune maxim a sursei: 5 KB
Folosind datele de intrare, pentru ecare culoare c din mulµimea r1, 2, ..., k x se construiesc doi
vectori:
a a0 , a1 , ..., a30000 , unde ai este codul punctului aat la distanµa i de stâlpul A de pe
primul cablu (0 dac nu exist punct).
b b0 , b1 , ..., b30000 , unde bi este codul punctului aat la distanµa i de stâlpul A de pe al
doilea cablu (0 dac nu exist punct).
Parcurgem folosind acela³i indice i (0, 1, 2, ..., 30 000) ambii vectori a ³i b ³i actualiz m trei
variabile xa, xb ³i min (iniµial min este 20 000), astfel:
dac ai j 0 si xa=0, atunci xa=i
daca bi j 0 si xb=0, atunci xb=i
dac ai j 0 si xb j 0 si |i-xb|<min, atunci xa=i; min=|i-xb|
dac bi j 0 si xa j 0 si |i-xa|<min, atunci xb=i; min=|i-xb|
CAPITOLUL 27. ONI 2011 568
Õ
S d2 xa xb2
Introducem xa ³i xb în doi vectori x ³i y .
A³ m s ³i elementele vectorilor x ³i y .
În algoritm am folosit:
Se construiesc tablourile cablu1[ ] ³i cablu2[ ], ecare de câte 30 000 de elemente de tip int.
Pentru ecare punct de pe ecare cablu, poziµia i din ³irul de date citit ³i perechea (distanµ ,
culoare) specice ec rui punct le-am memorat prin
cablu1[distanµ ] = i*100+culoare-1, respectiv
cablu2[distanµ ] = i*100+culoare-1
În procesul de citire a datelor ³i construire a tablourilor cablu1[ ] ³i cablu2[ ] am calculat
num rul de culori k ca ind valoarea maxim a valorilor culorilor citite.
Pentru ecare culoare cul, în ordinea 1,2, ..., k , am utilizat tablourile cablu1[ ] ³i cablu2[ ]
pentru sortarea în complexitate O n a punctelor de aceea³i culoare de pe ecare cablu, preluând
distanµa faµ de cap tul stâng al cablului pe care se a ³i poziµia din ³irul datelor de intrare în
tablourile x1[] ³i z1[] cu n1 elemente, respectiv x2[] ³i z2[] cu n2 elemente.
Folosind un algoritm asem n tor cu cel de la interclasarea a doi vectori ordonaµi am determinat
în complexitate O n diferenµa cea mai mic dif t, în valoare absolut , dintre distanµele faµ de
capetele din stânga ale cablurilor, ale celor dou puncte de aceea³i culoare cul aate pe cabluri
diferite, x1i ³i x2j , 1 & i & n1 ³iÔ1 & j & n2.
Apoi am calculat, cu formula dif t dif t d d, lungimea sârmei care va uni cele dou
puncte, ca lungime a ipotenuzei într-un triunghi dreptunghic de catete dif t ³i d ³i am ad ugat-o
sumei dmin. Am memorat prin xcul i1 ³i y cul i2 perechea de poziµii i1 ³i i2, din ³irul de
date de intrare, corespunz toare celor dou puncte alese.
La nal am a³at cu trei zecimale exacte valoarea dmin ³i apoi cele k perechi xi, y i,
1 & i & k.
81 if (dif<0)dif=-dif;
82 if (dif<dift)
83 {
84 dift=dif;
85 i1=z1[i];
86 i2=z2[j];
87 }
88
89 if (x1[i]<x2[j])
90 i++;
91 else
92 j++;
93 }
94
95 x[cul]=i1;
96 y[cul]=i2;
97 dmin=dmin+sqrt((double)dift*dift+d*d);
98 }
99
100 w1=(int)floor(dmin);
101 w2=(int)floor((dmin-w1)*1000);
102 f2<<w1<<".";
103 if (w2<10)
104 f2<<"00"<<w2;
105 else
106 if (w2<100)
107 f2<<"0"<<w2;
108 else
109 f2<<w2;
110
111 f2<<"\n";
112 for (cul=1;cul<=k;cul++)
113 {
114 f2<<x[cul]<<" "<<y[cul]<<"\n";
115 }
116
117 f2.close();
118 f1.close();
119 return 0;
120 }
27.3 tort
Problema 3 - tort 100 de puncte
De ziua lui, Gigel a primit un tort de form dreptunghiular , ornat cu un caroiaj ce împarte
tortul în m n p trate, în ecare p trat aându-se câte o cirea³ sau o c p³un . Caroiajul cu
fructe este reprezentat printr-o matrice cu 0 ³i 1, 0 însemnând cirea³ ³i 1 c p³un .
S rb toritul are dreptul s taie k felii de tort. O felie se poate obµine prin t ierea dup liniile
caroiajului, dintr-un cap t în cel lalt, având l µimea egal cu 1, de pe oricare latur a tortului,
codicate cu N, E, S, V. Gigel ind mare amator de c p³uni vrea s taie cele k felii astfel încât
num rul c p³unilor din aceste felii s e cât mai mare.
Spre exemplu, dac tortul iniµial este reprezentat ca o matrice având 6 6 linii ³i coloane,
dup 3 t ieturi N, E, V bucata r mas ³i feliile obµinute vor conform gurii al turate.
Cerinµe
S se scrie un program care s determine num rul de posibilit µi de t iere a k felii de tort,
pentru a obµine un num r maxim de c p³uni. Dou variante în care difer doar ordinea de t iere,
CAPITOLUL 27. ONI 2011 571
dar r mâne aceea³i bucat de tort, nu sunt considerate distincte. De exemplu, dac num rul
maxim de c p³uni se poate obµine prin una din variantele : VSNNV sau VVNSN, acestea nu sunt
considerate distincte.
Date de intrare
Pe prima linie a ³ierului de intrare tort.in sunt scrise dimensiunile tortului, m ³i n ³i num rul
k al feliilor de tort t iate de Gigel, separate prin câte un spaµiu. Pe urm toarele m linii e descris
caroiajul cu fructe printr-o matrice cu valori de 0 ³i 1.
Date de ie³ire
Prima linie a ³ierului tort.out va conµine num rul maxim de c p³uni care poate obµinut
din cele k felii de tort. Pe linia a doua se va g si num rul de posibilit µi distincte de a obµine
num rul maxim de c p³uni.
Restricµii ³i preciz ri
a 2 & m, n & 500
a 1 & k $ min m, n
Exemple:
tort.in tort.out Explicaµii
6 6 3 10 Tortul este format dintr-un caroiaj cu m 6 linii ³i n 6
0 1 1 1 0 1 5 coloane ³i se pot t ia k 3 felii.
1 0 0 0 0 1 Se pot obµine maxim 10 c p³uni.
0 0 0 1 0 0 Cele 5 posibilit µi de a t ia cele 3 felii sunt: NNS, NSE, NSV,
0 1 0 1 0 1 VEV ³i NEV
1 0 0 0 0 0
1 1 1 0 0 1
Timp maxim de executare/test: 0.2 secunde
Memorie: total 4 MB
Dimensiune maxim a sursei: 5 KB
Dup t ierea celor k felii din tort, r mâne un dreptunghi de dimensiuni m m1 n n1,
unde m1 ³i n1 reprezint numarul feliilor orizontale, respectiv verticale (n1 n2 k ). Trebuie ca
acest dreptunghi s conµin cât mai puµine valori 1 (capsuni). Construim o matrice în care pentru
1 & i & m ³i 1 & j & n memoram num rul de cap³uni din dreptunghiul cu vârfurile opuse 1, 1
³i i, j , dup care num rul de cap³uni din orice submatrice se gase³te în O 1. Vom determina
pentru ecare k1 cu valori de la 0 la k toate submatricele de dimensiuni m k1 n k k1 cu
num r minim de 1 printr-o singura parcurgere a matricei obµin nd o complexitate O m n k ,
sucient pentru dimensiunile date.
Algoritm tort
citeste m,n,k
pt. i=1,m
pt. j=1,n citeste Aij sf.
sf.
B[1,1]=A[1,1]; min=m*n+1;
pt. i=2,m B[i,1]=B[i-1,1]+A[i,1] sf.
pt. j=2,n B[1,j]=B[1,j-1]+A[1,j] sf.
pt. i=2,m
pt. j=2,n Bij=B[i,j-1]+B[i-1,j]-B[i-1,j-1] sf.
sf.
pt. k1=0,k1
pt. i=m-k1,m
pt. j=n-k+k1,n
S=Bij-B[i-m+k1,j]-B[i,j-n+k-k1]+B[i-m+k1,j-n+k-k1]
CAPITOLUL 27. ONI 2011 572
27.4 ape
Problema 4 - ape 100 de puncte
CAPITOLUL 27. ONI 2011 573
Mihai crede c m pricep la informatic ³i m roag s îl ajut la efectuarea unor calcule. Mi-a
povestit c în vacanµ a fost la µar la bunici. Bunicii lui se ocup de piscicultur ³i au preluat
spre utilizare o zon de teren unde se a lacuri, hele³tee ³i b lµi. Sunt pl tite taxe speciale în
funcµie de suprafeµele acestor ape. Bunicului i se pare c cei de la ociul unde se pl tesc taxele au
date gre³ite în dosare, despre ariile acestor suprafeµe de ap ³i l-a rugat pe Mihai s îi calculeze cu
aproximaµie aceste arii. Mihai a studiat problema ³i s-a hot rât s înconjoare ecare ap , mergând
pe conturul acesteia. Pasul lui are lungimea de 1 metru. La ecare pas Mihai folose³te o busol
³i î³i noteaz într-un carneµel direcµia înspre care a fost efectuat pasul Nord, Sud, Est sau Vest.
Dup ecare pas Mihai actualizeaz ³i num rul de pa³i pe care i-a f cut.
Cerinµe
Se dore³te s se ae, pentru ecare traseu:
a) Dimensiunile pe direcµiile Vest-Est ³i respectiv Nord-Sud ale unei suprafeµe dreptunghiulare
de arie minim care cuprinde în interior sau pe margini suprafaµa apei.
b) Sensul în care a fost parcurs traseul: 0- pentru sens orar, respectiv 1- pentru sens invers
orar;
c) Aria suprafeµei apei înconjurate, din interiorul traseului.
Date de intrare
Fi³ierul de intrare ape.in are pe prima linie num rul P de pa³i ai traseului. în linia 2 se a
un ³ir de P litere mari, f r spaµii între ele, din mulµimea {N, S, E, V} reprezentând traseul.
Date de ie³ire
Fi³ierul de ie³ire ape.out va conµine patru numere naturale separate prin câte un spaµiu: pri-
mul num r reprezint dimensiunea pe direcµia Vest-Est ³i al doilea num r reprezint dimensiunea
pe direcµia Nord-Sud a suprafeµei dreptunghiulare de arie minim care cuprinde în interior sau pe
margini suprafaµa apei delimitat de traseu; al treilea num r reprezint sensul parcurgerii, iar al
patrulea num r reprezint aria.
Restricµii ³i preciz ri
a 1 & P & 10 000
a Pentru 30% din teste traseele vor avea lungimea maxim 2 000.
a Dac dimensiunile suprafeµei dreptunghiulare de arie minim sunt corecte, atunci se va
acorda 10% din punctaj/test.
a Dac sensul traseului este determinat corect, atunci se vor primi 10% puncte/test.
a Aria suprafeµei apei este un num r natural nenul.
Exemple:
ape.in ape.out Explicaµii
16 3315 C suµele marcate cu '-' reprezint traseul, iar p tratele
NNVVSVSSESEEENNV negre reprezint apa.
Zona m rginit de linia îngro³at
reprezint suprafaµa dreptunghiu-
lar minimal ce conµine p tratele
negre, care reprezint apa.
C suµa marcat cu * este poziµia
de pornire.
Timp maxim de executare/test: 0.1 secunde
Memorie: total 2 MB
Dimensiune maxim a sursei: 5 KB
prof. Pit-Rada Ionel Vasile, Colegiul Naµional Traian, Drobeta Turnu Severin
CAPITOLUL 27. ONI 2011 574
39 if (a==’S’)
40 switch (b)
41 {
42 case ’S’ : {s=s+x; y--; break;}
43 case ’V’ : {x--; break;}
44 case ’E’ : {s=s+x; x++; break;}
45 }
46 else
47 switch (b)
48 {
49 case ’S’ : {y--; break;}
50 case ’E’ : {x++; break;}
51 case ’N’ : {s=s-x-1; y++; break;}
52 }
53
54 if (x>xM) xM=x;
55 if (x<xm) xm=x;
56 if (y>yM) yM=y;
57 if (y<ym) ym=y;
58 a=b;
59 }
60
61 f2<<(xM-1-xm)<<" "<<(yM-1-ym)<<" ";
62
63 if (s<0)
64 {
65 sens=1;
66 s=-s;
67 s=s-P;
68 }
69 else
70 sens=0;
71
72 f2<<sens<<" "<<s<<endl;
73 f1.close();
74 f2.close();
75 return 0;
76 }
27.5 ec
Problema 5 - ec 100 de puncte
Alexandru are la dispoziµie un tablou p tratic de dimensiune n cu numere întregi ³i k ecuaµii
de tipul I ³i II. Ecuaµiile de tipul I sunt de forma: ax b c, cu a, b, c numere naturale, iar
2
ecuaµiile de tipul II sunt de forma: ax bx c d, cu a, b, c, d numere naturale.
Alexandru î³i propune s determine pentru ecare tip de ecuaµie: num rul lor ³i câte dintre
ele au r d cinile în tabloul dat.
Cerinµe
S se scrie un program care determin num rul de ecuaµii de tipul I, câte dintre acestea au
exact o r d cin în tablou, respectiv num rul de ecuaµii de tipul II ³i câte dintre acestea au exact
ambele r d cini în tablou.
Date de intrare
Fi³ierul de intrare ec.in va conµine: pe prima linie numerele naturale n ³i k separate printr-un
spaµiu, pe urm toarele n linii elementele tabloului separate prin câte un spaµiu, iar pe urm toarele
k linii ecuaµiile în forma din enunµ, câte una pe ecare linie.
Date de ie³ire
Fi³ierul de ie³ire ec.out va conµine pe prima linie dou numere separate printr-un spaµiu re-
prezentând num rul de ecuaµii de tipul I, respectiv num rul de ecuaµii de tipul I care au exact o
r d cin , aat în tablou, iar pe a doua linie tot dou numere separate printr-un spaµiu repre-
zentând num rul de ecuaµii de tipul II, respectiv num rul de ecuaµii de tipul II cu exact dou
r d cini, ambele r d cini în tablou.
CAPITOLUL 27. ONI 2011 576
Restricµii ³i preciz ri
a 1 & n & 500
a 1 & k & 1000
a Elementele tabloului sunt numere întregi cu maxim 4 cifre ecare;
a La ecare ecuaµie de tipul I a, b, c vor precizate, chiar dac acestea au valoarea 0 sau 1,
(de exemplu x 2 3 va apare 1x 2 3).
a La ecare ecuaµie de tipul II a, b, c, d vor precizate, chiar dac acestea au valoarea 0 sau 1,
2
(de exemplu x2 1 3 va apare 1x 0x 1 3).
a Pentru ecuaµiile de tipul I a, b, c sunt numere naturale cu maxim 4 cifre;
a Pentru ecuaµiile de tipul II a, b, c, d sunt numere naturale cu maxim 4 cifre;
a Se va acorda: 10% din punctaj pentru num rul de ecuaµii de tipul I, 30% din punctaj pentru
câte dintre ele au exact o r d cin în tablou, 20% din punctaj pentru num rul de ecuaµii de tipul
II ³i 40% din punctaj pentru câte dintre ele au exact ambele r d cini în tablou.
Exemple:
ec.in ec.out Explicaµii
25 21 Prima ecuaµie este de tipul I si are r d cina 0, care nu se g se³te
12 31 în tablou.
2 -1 A doua ecuaµie este de tipul II ³i are dou r d cini egale cu -1,
1x+0=0 care se g sesc în tablou.
20x2+40x+20=0 A treia ecuaµie este de tipul I ³i are r d cina 2, care se g se³te
101x+200=402 în tablou.
2x2+1x+4=0 A patra ecuaµie este de tipul II ³i nu are r d cinile în tablou.
1x2+1x+3=5 A cincea ecuaµie este de tipul II ³i are r d cinile -2 ³i 1, dar nu
sunt amândou în tablou.
Timp maxim de executare/test: 0.8 secunde
Memorie: total 4 MB
Dimensiune maxim a sursei: 5 KB
3 #include <cstring>
4 #include <cmath>
5
6 #define Lmax 100
7 #define Nmax 20000
8
9 using namespace std;
10
11 int N, M, L, nr_ec1, nr_ec2, sol_ec1, sol_ec2;
12 int v[Nmax];
13 char line[Lmax];
14
15 inline bool is_int(long double x)
16 {
17 return abs((int)x - x) < 0.000000000001L;
18 }
19
20 int main()
21 {
22 freopen("ec.in", "r", stdin);
23 freopen("ec.out", "w", stdout);
24
25 scanf("%d %d\n", &N, &M);
26
27 L = N*N;
28 for (int i = 0; i < L; ++i)
29 {
30 int x;
31 scanf("%d ",&x);
32 v[x+10000] = 1;
33 }
34
35
36 int coef[4], nr_coef;
37 for (int i = 0; i < M; ++i)
38 {
39 scanf("%s\n", line);
40 nr_coef = 0;
41 int val = 0;
42 for (int j = 0, size = strlen(line); j < size; ++j)
43 {
44 if (line[j] <= ’9’ && line[j] >= ’0’)
45 val = val * 10 + line[j] - ’0’;
46
47 if (line[j] == ’x’)
48 {
49 coef[nr_coef++] = val;
50 val = 0;
51 if (line[j + 1] == ’^’)
52 j+=3;
53 else
54 ++j;
55 }
56
57 if (line[j] == ’=’)
58 {
59 coef[nr_coef++] = val;
60 val = 0;
61 }
62 }
63
64 coef[nr_coef++] = val;
65
66 long double sol;
67
68 if (nr_coef == 3)
69 {
70 //ec gr1
71 ++nr_ec1;
72 if (coef[0] == 0) continue;
73 sol = ((long double)(coef[2] - coef[1])) / coef[0];
74 if (is_int(sol) && v[(int)sol+10000])
75 ++sol_ec1;
76 }
77 else
78 {
CAPITOLUL 27. ONI 2011 578
79 //ec gr 2
80 ++nr_ec2;
81 bool ok = true;
82 int delta = coef[1]*coef[1] - 4*coef[0]*(coef[2] - coef[3]);
83 if (coef[0] == 0)
84 {
85 if (coef[1] == 0)
86 continue;
87 sol = ((long double)(coef[3] - coef[2])) / coef[1];
88 if (is_int(sol) && v[(int)sol+10000])
89 ++sol_ec2;
90 continue;
91 }
92
93 if (delta < 0) continue;
94
95 sol = (long double)(-coef[1] + sqrtl(delta)) / (2*coef[0]);
96 if (!(is_int(sol) && v[(int)sol+10000]))
97 ok = false;
98
99 sol = (long double)(-coef[1] - sqrtl(delta)) / (2*coef[0]);
100 if (is_int(sol) && v[(int)sol+10000] && ok)
101 ++sol_ec2;
102 }
103 }
104
105 printf("%d %d\n%d %d\n", nr_ec1, sol_ec1, nr_ec2, sol_ec2);
106 return 0;
107 }
27.6 furnici
Problema 6 - furnici 100 de puncte
La Institutul de cercetare al insectelor s-a descoperit c dac furnicile sunt puse pe o bar
metalic , ele au un comportament bine denit dup urm toarele reguli:
1. Imediat cum a fost pus pe bar ea î³i începe deplasarea în sensul în care a fost orientat ,
cu viteza constant de 1cm/s. Furnica nu se opre³te cât timp se a pe bara metalic chiar
dac se ciocne³te cu alt furnic .
2. Dac pe drum nu se întâlne³te cu alt furnic ea î³i va continua deplasarea pân când va
c dea de pe bar .
3. Când dou furnici se întâlnesc, ele î³i schimb amândou instantaneu sensul de deplasare.
Cerinµe
tiind c pe o bar metalic de lungime L cm se plaseaz exact N furnici în poziµii cunoscute ³i
cu sensul iniµial de deplasare cunoscut, s se scrie un program care calculeaz num rul de secunde
dup care va c dea de pe bar ³i ultima furnic de la momentul iniµial. Toate furnicile î³i încep
deplasarea concomitent.
Date de intrare
Fi³ierul de intrare furnici.in conµine pe prima linie dou numere naturale L ³i N separate
printr-un spaµiu. Apoi urmeaz N linii cu câte 2 valori: pozi ³i sensi separate printr-un spaµiu,
pozi este un num r natural care reprezint coordonata la care se a furnica i la momentul iniµial,
iar sensi este un caracter din mulµimea {'S ', 'D'} ce arat sensul de deplasare iniµial pe care îl
are furnica i (S pentru stânga ³i D pentru dreapta).
Date de ie³ire
Fi³ierul de ie³ire furnici.out va conµine un singur num r care reprezint timpul la care a c zut
ultima furnic .
Restricµii ³i preciz ri
a 1 $ L $ 10 000 000
a 0 $ N $ 100 000
a 0 & pozi & L
CAPITOLUL 27. ONI 2011 579
Exemple:
furnici.in furnici.out Explicaµii
10 3 8 Bara are lungimea de 10 cm ³i pe bar vor plasate 3 furnici
4D la distanµele de 4, 8, 1 faµ de cap tul din stânga al barei ³i vor
8S avea urm toarele sensuri de deplasare: dreapta, stânga respectiv
1S stânga.
Primele dou furnici se vor întâlni dup 2 secunde în punctul
de coordonat 6 ³i î³i vor schimba sensul de deplasare.
Dup schimbarea de sens a doua furnic va parcurge înc 4cm
c tre dreapta ³i va c dea, în timp ce prima furnic dup schim-
barea de sens va parcurge înc 6 cm c tre stânga, pân la c dere.
În acest timp a treia furnic a c zut de pe bara dup 1 secund .
Pe bar nu vor mai furnici dup 8 secunde.
Soluµia 1: 20 puncte
Se memoreaz într-un vector de lungime L (lungimea barei metalice) pe poziµia k direcµia
în care se deplaseaz furnica ce se aa pe bara la punctul de coordonata k . Apoi se simuleaz
deplas rile cu pasul o unitate de timp pana când tot vectorul devine nul. Rezultatul este numarul
de pa³i. Pentru a evita ciocnirile în coordonate raµionale este sucient s se observe c cioncirile în
aceste coordonate sunt de forma k 0.5. Lungimea vectorului se dubleaz ³i direcµia de deplasare
a furnicilor care se a la coordonata k va salvat pe poziµia 2 k . Rezultatul este num rul de
pa³i / 2.
Complexitate : O(L*timpul_de_c dere_al_ultimei_furnici)
Soluµia 2: 50-60 puncte
Se observ c dac sort m furnicile cresc tor dup coordonata la care se a iniµial pe bar ,
furnica aat pe poziµia k în vectorul sortat va r mâne pe poziµia k tot timpul simul rii. (cu alte
cuvinte: dac are x furnici în stânga ³i y în dreapta, x ³i y r mân constante. Furnicile care cad
se consider prezente ³i ele).
În vectorul de furnici sortat memor m ca valoare real coordonata la care se a ecare furnic .
Parcurgem vectorul ³i calcul m timpul maxim în care furnicile se pot deplasa f r s se ciocneasc ,
La o nou parcurgere actualiz m coordonatele ³i schimb m sensurile la eventualele ciocniri (cel
puµin una).
CAPITOLUL 27. ONI 2011 580
Se observ c dac la pasul curent nu este nici o furnic orientat spre exteriorul barei, la pasul
viitor cel puµin una va orientat spre exterior ³i o scoatem din calcul µinând cont de timpul care
s-a scurs pân aceasta a c zut. Repet m pân când bara se elibereaz . Rezultatul este maximul
dintre ace³ti timpi.
2
Complexitate : O N
Soluµie 3: 100 puncte
Trebuie s se observe urm torul lucru :
În desen sunt dou furnici în punctele A ³i B care se deplaseaz în dreapta respectiv în stânga.
Deplasarea furnicii A : L©2 L©2 Y L Y
Deplasarea furnicii B : L©2 L©2 X L X
Se observ c dup L secunde furnicile sunt în acela³i loc ca la început dar cu sensuri de
deplasare inversate. S consideram scenariul în care furnicile trec una prin alta atunci când se
intalnesc:
Dup L secunde furnica A se va aa în punctul B iar furnica B în punctul A. Dac nu µinem
cont de notarea furnicilor (fapt care nu conteaz ) suntem în acela³i caz ca în regulile din enunµ
dup L secunde.
Aceasta proprietate este adevarat doar în cazul in care furnicile au aceea³i vitez (1cm/s
specicat în enunµ).
Proprietatea este adevarat ³i pentru N furnici.
Deci problema cere s se calculeze maximul dintre distanµele pe care le au de parcurs furnicile
neµinand cont de ciocnirile dintre ele.
Complexitate O N
ONI 2010
28.1 cern
Problema 1 - cern 100 de puncte
CERN este un acronim folosit pentru a desemna Laboratorul Eu-
ropean pentru Fizica Particulelor Elementare. Acronimul s-a p strat
de la vechea denumire în limba francez , ³i anume Conseil Européen
pour la Recherche Nucléaire. Acesta este cel mai mare laborator de
cercetare a particulelor elementare din lume, situat în suburbia nord-
vestic a Genevei, chiar pe graniµa dintre Elveµia ³i Franµa. Funcµia
primar a complexului CERN este de a furniza acceleratoare de par-
ticule elementare ³i alte tipuri de infrastructuri necesare zicii parti-
culelor de energii înalte.
Acceleratorul de particule CERN este dispus sub forma a 3 cercuri cu aceea³i raz , tangente
exterioare dou câte dou , numerotate pe gur cu 1, 2, 3. Traiectoria unei particule elementare
porne³te din unul din punctele marcate pe gur cu A, B, C, D, E, F ³i se deplaseaz cu vitez
constant de 10/unitatea de timp numai pe circumferinµa cercurilor.
La trecerea printr-un punct de tangenµ dintre dou cercuri particula î³i schimb atât sensul
de deplasare, cât ³i cercul pe care se deplaseaz .
Astfel, dac sensul de deplasare a fost la un moment dat trigonometric,
la trecerea printr-un punct de tangenµ devine invers trigonometric ³i dac
sensul de deplasare a fost invers trigonometric, la trecerea printr-un punct
de tangenµ devine trigonometric.
Cerinµe
o
tiind c cercurile ce formeaz acceleratorul sunt marcate din grad în grad începând cu 0 , în
sens trigonometric (a³a cum se indic în gura al turat ), s se scrie un program, care, cunoscând
punctul iniµial ³i sensul de deplasare al unei particule, s determine poziµia particulei în accelerator
dup un num r dat de unit µi de timp.
Date de intrare
Prima linie a ³ierului de intrare cern.in conµine un caracter p ce indic punctul de plecare al
particulei.
A doua linie a ³ierului de intrare conµine dou numere întregi s ³i t, separate printr-un spaµiu,
ce indic sensul de deplasare (1 pentru sens trigonometric ³i -1 pentru sens invers trigonometric),
respectiv num rul de unit µi de timp cât dureaz deplasarea.
Date de ie³ire
Pe prima linie a ³ierului de ie³ire cern.out se vor scrie dou numere naturale g ³i c, se-
parate printr-un spaµiu, ce reprezint num rul de grade, în sens trigonometric, respectiv cercul,
corespunz toare poziµiei nale unde se va g si particula dup trecerea celor t unit µi de timp.
Restricµii ³i preciz ri
582
CAPITOLUL 28. ONI 2010 583
a p " {'A','B','C','D','E','F'}
a s " {-1, 1}
a 0 & t & 1.000.000.000
a 0 & g & 359
a c " {1, 2, 3}
a pentru toate seturile de date de intrare, poziµia nal a particulei nu coincide cu unul dintre
punctele de tangenµ dintre cercuri.
Exemple:
cern.in cern.out Explicaµii
A 200 3 Particula pleac din punctul A în sens trigonometric ³i are traseul:
o
1 320 a 180 pe cercul 1 în sens trigonometric
o
a 60 pe cercul 2 în sens invers trigonometric
o
a 80 pe cercul 3 în sens trigonometric
o
Poziµia nal este la 200 pe cercul 3
Timp maxim de executare/test: 0.1 secunde
Memorie: total 2 MB din care pentru stiv 1 MB
Dimensiune maxim a sursei: 20 KB
Deoarece toate cercurile au aceea³i raz , triunghiul format cu centrele celor 3 cercuri este
o
echilateral ³i va avea în consecinµ toate unghiurile de 60 . În felul acesta punctele de plecare ale
particulei sunt a³ezate dup cum urmeaz :
o
a 'A' - 0 pe cercul 1
o
a 'B' - 60 pe cercul 1
o
a 'C' - 120 pe cercul 2
o
a 'D' - 180 pe cercul 2
o
a 'E' - 240 pe cercul 3
o
a 'F' - 300 pe cercul 3
Urm toarea observaµie legat de rezolvarea problemei este c dup
o
un num r de 6π unit µi de timp (1080 ) particula va trece din nou prin
punctul de plecare, indiferent care este acesta. Problema nu necesit tipuri de date structurate
îns presupune o analiza atent a tuturor situaµiilor în care apar treceri de la un cerc la altul ³i
o o
respectiv în care se fac treceri de la 360 la 0 în concordanµ cu sensul de deplasare.
Aceste situaµii sunt:
1. cercul 1 tangenµ cu cercurile 2 ³i 3
2. cercul 2 tangenµ cu cercurile 3 ³i 1
3. cercul 3 tangenµ cu cercurile 1 ³i 2
o
4. trecerea prin 360 pentru cercurile 1 ³i 3
Se analizeaz toate aceste situaµii ³i se stabile³te modul de trecere de la un cerc la altul µinând
cont desigur ³i de sensul de deplasare al particulei. Problema poate abordat iterativ, recursiv
sau cel mai interesant numai prin tratarea punctelor de tangenµ (soluµia cea mai rapid , ce nu
necesit instrucµiuni repetitive ci numai instrucµiuni de decizie).
75
76 cerc=3;
77 break;
78 case ’H’:
79 if(s==1)
80 if(cerc==3)
81 if (t>300)t=t-300,p=’I’; else fo<<120+t<<" 3\n",t=0;
82 else
83 if(t>60) t=t-60,p=’G’; else fo<<300+t<<" 2\n",t=0;
84 else
85 if(cerc==3)
86 if(t>60) t=t-60,p=’I’; else fo<<120-t<<" 3\n",t=0;
87 else
88 if(t>300) t=t-300,p=’G’; else fo<<(300-t)%360<<" 2\n",t=0;
89
90 cerc=1;
91 break;
92
93 case ’I’:
94 if(s==1)
95 if(cerc==1)
96 if(t>300)t=t-300,p=’G’; else fo<<(240+t)%360<<" 1\n",t=0;
97 else
98 if(t>60) t=t-60,p=’H’; else fo<<60+t<<" 3\n",t=0;
99 else
100 if(cerc==1)
101 if(t>60) t=t-60,p=’G’; else fo<<240-t<<" 1\n",t=0;
102 else
103 if(t>300) t=t-300,p=’H’; else fo<<(420-t)%360<<" 3\n",t=0;
104 cerc=2;
105 break;
106 }
107 s=-s;
108 }
109
110 fi.close();
111 fo.close();
112 return 0;
113 }
28.2 cmmmc
Problema 2 - cmmmc 100 de puncte
Denim noµiunea de pereche ordonat , perechea de numere naturale x, y cu x & y . Denim
cel mai mic multiplu comun al unei perechi ordonate ca ind cel mai mic multiplu comun al
numerelor care formeaz perechea.
Se dau k numere naturale n1 , n2 , ..., nk .
Cerinµe
S se determine pentru ecare dintre numerele ni (i = 1, 2, ..., k ):
a) câte perechi ordonate au cel mai mic multiplu comun egal cu ni .
b) dintre acestea, perechea ordonat care are suma minim .
Date de intrare
Prima linie a ³ierului cmmmc.in conµine un num r natural k . Urm toarele k linii din acest
³ier vor conµine câte un num r natural; linia i 1 va conµine num rul ni (i 1, 2, ..., k ) .
Date de ie³ire
Fi³ierul cmmmc.out va conµine k linii. Pe ecare dintre acestea se vor aa trei numere. Cele
trei numere de pe linia i vor reprezenta:
- primul, num rul de perechi ordonate care au cel mai mic multiplu comun egal cu ni ;
- urm toarele dou , numerele care alc tuiesc perechea ordonat care are cel mai mic multiplu
comun egal cu ni ³i a c ror sum este minim , a³ate în ordine cresc toare.
Restricµii ³i preciz ri
a 1 & k & 100
a 1 & ni & 2 000 000 000
a Pentru 20% dintre teste, k & 100 ³i ni & 1 000
a Fiecare dintre cele k linii ale ³ierului cmmmc.out trebuie s conµin exact trei numere
separate prin câte un spaµiu; în caz contrar, soluµia se consider gre³it ³i se obµin 0 puncte
pentru testul respectiv. Rezolvarea corect a cerinµei a) valoreaz 40% din punctajul unui test iar
rezolvarea corect a cerinµei b) 60%.
Exemple:
cmmmc.in cmmmc.out Explicaµii
2 525 Exist cinci perechi distincte care au cel mai mic multiplu comun
10 2 1 11 egal cu 10: (1,10), (2,10), (5,10), (2,5) (10,10). Dintre acestea
11 perechea cu cea mai mic sum este (2,5).
Pentru n=11 exist dou perechi ordonate care au cel mai mic
multiplu comun 11: (1,11), (11,11). Dintre acestea perechea cu
cea mai mic sum este (1,11).
Timp maxim de executare/test: 0.2 secunde
Memorie: total 2 MB din care pentru stiv 1 MB
Dimensiune maxim a sursei: 10 KB
A³adar num rul total al perechilor, care au cel mai mare divizor comun egal cu n este 2
q1 1 2 q2 1 ... 2 qk 1.
Observ m, c am num rat perechile formate din numere distincte de dou ori ³i perechea n, n
o singur dat , a³a c ad ug m unu ³i împ rµim la doi, pentru a r spunde la subpunctul a).
Pentru a rezolva subpunctul b), observ m c pentru a obµine suma minim , trebuie s consi-
der m ecare pi la puterea qi într-unul din numere, iar la puterea 0 în cel lalt num r. Încerc m
toate cele 2k perechi ce se pot forma astfel ³i alegem perechea cu suma minim .
Pentru a genera aceste perechi, iter m cu o variabil de la 0 la 2k 1, pe care o convertim în
baza doi. Dac cifra i în baza doi este egal cu 0, vom considera c pi apare în primul num r la
puterea qi ³i în al doilea num r la puterea 0, iar dac cifra i este egal cu 1, pi va ap rea în primul
num r la puterea 0 ³i în al doilea num r la puterea qi .
Pentru a implementa un algoritm cât mai rapid pentru descompunerea în factori primi, se reco-
mand generarea numerelor prime folosind Ciurul lui Erastotene. Aceast abordare implementat
cu grij duce la obµinerea punctajului maxim.
O alt soluµie posibil este determinarea tuturor divizorilor lui n ³i vericarea pentru ecare
pereche de divizori, dac are cel mai mare divizor comun egal cu n. Pentru a determina divizorii
unui num r este de ajuns s veric m divizorii pân la radicalul num rului ³i când am g sit
divizorul d, acesta va implica c am g sit ³i divizorul n©d. Cazul p tratelor perfecte trebuie tratat
separat.
Aceast abordare obµine 60 de puncte.
64 ifstream fin(IN_FILE);
65 ofstream fout(OUT_FILE);
66
67 int test, nSol;
68 LL n;
69 VPII factors;
70 VB isPrime;
71 VI primes;
72 VLL compacted;
73
74 void Erast()
75 {
76 int gyok = sqrt(double(MAX));
77 isPrime.RS(gyok + 1, true);
78 FOR(i, 2, gyok >> 1)
79 if (isPrime[i])
80 for(int j=i+i; j<=gyok; j+=i) isPrime[j]=false;
81 FOR(i, 2, gyok)
82 if (isPrime[i]) primes.PB(i);
83 }
84
85 void BuildFactors()
86 {
87 factors.CL, compacted.CL;
88 LL aux = n;
89 int iPrime = 0, gyok = sqrt(double(n));
90 while (iPrime < primes.SZ && aux > 1)
91 {
92 int exponent = 0, prime = primes[iPrime];
93 if (prime > gyok) break;
94 while (!(aux % prime))
95 {
96 ++exponent;
97 aux /= prime;
98 }
99 if (exponent) factors.PB(MP(prime, exponent));
100 if (aux < isPrime.SZ && isPrime[aux]) break;
101 ++iPrime;
102 }
103 if (aux > 1) factors.PB(MP(aux, 1));
104 FORN(i, factors.SZ)
105 {
106 LL factor = factors[i].X;
107 FOR(j, 2, factors[i].Y) factor *= factors[i].X;
108 compacted.PB(factor);
109 }
110 }
111
112 PLL Solve()
113 {
114 nSol = 1;
115 FORN(i, factors.SZ) nSol *= (2*factors[i].Y + 1);
116 nSol = nSol / 2 + 1;
117 PLL ans;
118 LL minSum = (LL)MAX + MAX + 1;
119 FORN(i, 1 << factors.SZ)
120 {
121 LL x = 1, y = 1;
122 FORN(j, factors.SZ)
123 if (i & (1 << j)) x *= compacted[j];
124 else y *= compacted[j];
125 if (minSum > x + y)
126 {
127 minSum = x + y;
128 ans = MP(x, y);
129 }
130 }
131 if (ans.X > ans.Y) swap(ans.X, ans.Y);
132 return ans;
133 }
134
135 int main()
136 {
137 Erast();
138
139 fin >> test;
CAPITOLUL 28. ONI 2010 592
28.3 simetric
Problema 3 - simetric 100 de puncte
O matrice p tratic A care are P linii ³i P coloane este simetric dac ³i numai dac pentru
orice indici i ³i j între 1 ³i P avem c Ai,j Aj,i . Astfel, matricea din gura 1 este simetric , iar
cea din gura 2 nu este, deoarece exist cel puµin o pereche de indici (de exemplu i 2 ³i j 3),
pentru care Ai,j este diferit de Aj,i .
Cerinµe
Se d o matrice cu M linii ³i N coloane în care toate elementele sunt numere naturale. Fie L
latura maxim a unei submatrici simetrice din aceast matrice. Pentru ecare dimensiune i între
1 si L s se determine câte submatrici simetrice ³i cu latura i ale matricii date exist .
Date de intrare
Prima linie a ³ierului simetric.in conµine numerele M ³i N , separate de exact un spaµiu,
reprezentând num rul de linii, ³i respectiv de coloane, ale matricii care se cite³te. Fiecare din
urm toarele M linii conµine câte N numere naturale, desp rµite de exact un spaµiu, reprezentând
elementele matricii.
Date de ie³ire
Fi³ierul de ie³ire simetric.out conµine exact L linii, unde L este latura maxim a unei sub-
matrici simetrice din matricea considerat . Linia i conµine num rul de submatrici simetrice de
latur i.
Restricµii ³i preciz ri
a 2 & M, N & 400
a Elementele matricii sunt numere naturale cuprinse între 1 ³i 30 000
Exemple:
CAPITOLUL 28. ONI 2010 593
28.4 pesti
Problema 4 - pesti 100 de puncte
Nicu³or trebuie s aib grij , pe perioada vacanµei, de cei n pe³ti aaµi în acvariile de la Muzeul
de ³tiinµe ale Naturii din Constanµa. Pe³tii sunt numerotaµi cu numerele distincte de la 1 la n ³i
sunt asezaµi în n acvarii identice, câte un pe³ti³or în câte un acvariu. Iniµial, pe³ti³orul numerotat
cu num rul 1 st în acvariul etichetat cu num rul 1, pe³ti³orul numerotat cu num rul 2 st în
acvariul etichetat cu num rul 2, ..., pe³ti³orul numerotat cu num rul n st în acvariul etichetat
cu num rul n. Cele n acvarii sunt a³ezate unul lâng altul, în ordinea cresc toare a etichetelor.
Cele n acvarii formeaz o grup .
Pentru ca pe³tii s se dezvolte frumos ³i s nu se plictiseasc , ei trebuie rea³ezaµi zilnic în
acvarii.
Astfel, în prima zi, Nicu³or formeaz dou subgrupe de acvarii.
CAPITOLUL 28. ONI 2010 596
În subgrupa din stânga a³eaz , în ordine, pe³tii din acvariile aate pe poziµii impare în grup
(primul acvariu din grup , al treilea, al cincilea etc).
În subgrupa din dreapta
a³eaz , în ordine, pe³tii din
acvariile aate pe poziµii pare
în grup (al doilea acvariu din
grup , al patrulea, al ³aselea
etc).
În ecare dintre urm toarele
zile, Nicu³or aplic operaµia des-
cris anterior pentru ecare su-
bgrup format în ziua prece-
dent .
Activitatea lui Nicu³or se încheie în ziua în care ecare dintre grupe este format din cel mult
dou acvarii.
Exemplu. Pentru n 9, la nalul celei de-a treia zi, pe³ti³orii sunt a³ezaµi în 5 grupe, conform
gurii al turate.
Cerinµe
Scrieµi un program care s citeasc dou numere naturale nenule n ³i x, n reprezentând num rul
de pe³ti³ori ³i x reprezentând num rul unui pe³ti³or, ³i care s determine:
- num rul z de zile în care Nicu³or î³i desf ³oar activitatea;
- eticheta y a acvariului în care se g se³te pe³ti³orul cu num rul x la încheierea activit µii lui
Nicu³or;
- prima zi, u, în care în pe³ti³orul cu num rul x a ajuns în acvariul etichetat cu num rul y ³i
nu a mai fost mutat.
Date de intrare
Fi³ierul de intrare pesti.in conµine o singur linie pe care sunt scrise cele dou numere naturale
n ³i x, separate printr-un spaµiu.
Date de ie³ire
Fi³ierul de ie³ire pesti.out conµine o singur linie pe care sunt scrise cele trei numere naturale
z , y ³i u (în aceast ordine), separate prin câte un spaµiu.
Restricµii ³i preciz ri
a 3 & n & 2 000 000 000;
a 1 & x & n.
a Dac un pe³te nu este mutat deloc atunci r spunsul la a treia cerinµ este 1.
a Evaluare: dac se r spunde corect la prima cerinµ se obµine 20% din punctaj. Dac se
r spunde corect la primele dou cerinµe se obµine 60% din punctaj. Dac se r spunde corect la
toate cele trei cerinµe se obµine 100% din punctaj.
Exemple:
pesti.in pesti.out Explicaµii
96 372 Nicu³or î³i desf ³oar activitatea timp de z 3 zile. Pe³ti³orul cu
num rul x 6 se va aa în ziua a treia în acvariul cu num rul y 7
³i ajunge în acest acvariu în ziua u 2.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 64 MB din care pentru stiv 32 MB
Dimensiune maxim a sursei: 10 KB
CAPITOLUL 28. ONI 2010 597
Cerinµa a) num rul z de zile pân la încheierea activit µii desf µurat de Nicu³or este cel mai
mare num r natural care veric inecuaµia 2 $ n, v ' 3.
z
28.5 plaja
Problema 5 - plaja 100 de puncte
Prim ria ora³ului Constanµa reamenajeaz plaja din staµiunea Mamaia. Aceasta este repre-
zentat ca o zon dreptunghiular cu l µimea de a unit µi ³i lungimea de b unit µi. Pe plaj
sunt trasate linii paralele cu laturile dreptunghiului astfel încât s formeze p trate cu latura de o
unitate, numite zone.
Pe plaj se vor pune obiecte: umbrele ³i prosoape. Se consider c dac un obiect intr în
interiorul unei zone, o ocup în întregime. Se poziµioneaz u umbrele de soare. într-o zon se
poate a³eza cel mult o umbrel .
N turi³ti vin ³i î³i a³eaz prosoapele pe plaj . Un prosop are form dreptunghiular ³i va
a³ezat paralel cu laturile dreptunghiului. Turi³tii î³i pot a³eza prosoapele pe zone libere sau
peste prosoape deja a³ezate. Un turist nu î³i poate a³eza îns prosopul pe plaj dac suprafaµa
acoperit de acesta include cel puµin o zon în care se a o umbrel .
M localnici au suprafeµe favorite pentru a³ezarea prosoapelor. O suprafaµ favorit are forma
unui dreptunghi cu laturile paralele cu laturile dreptunghiului care marcheaz plaja. Dup ce
turi³tii termin a³ezarea prosoapelor, localnicii veric dac zonele din suprafaµa favorit sunt
libere (neacoperite de prosoape a³ezate de turi³ti sau de umbrele).
Cerinµe
Scrieµi un program care s determine:
a num rul de turi³ti care au reu³it s î³i a³eze prosoapele pe plaj ;
a num rul de localnici ale c ror zone favorite sunt libere.
Date de intrare
Fi³ierul de intrare plaja.in conµine pe prima linie trei numere naturale, separate prin câte un
spaµiu, a, b ³i u, având semnicaµia din enunµ.
Fiecare din urm toarele u linii conµine o pereche de numere naturale x y , reprezentând o zon
în care se g se³te o umbrel .
Urm toarea linie din ³ier conµine un num r natural N , reprezentând num rul de turi³ti.
Urm toarele N linii descriu prosoapele turi³tilor. Fiecare linie conµine 4 numere naturale x1
y1 x2 y2 , ce reprezint colµurile unui prosop. Linia urm toare conµine o singur valoare, M ,
reprezentând num rul de localnici.
¬ ¬ ¬ ¬
Pe urm toarele M linii se a câte 4 numere, separate prin câte un spaµiu, x1 y1 x2 y2 , ce
reprezint colµurile unei suprafeµe favorite.
Date de ie³ire
CAPITOLUL 28. ONI 2010 599
Fi³ierul de ie³ire plaja.out conµine pe prima linie dou numere naturale separate printr-un
spaµiu. Primul num r reprezint num rul de turi³ti care ³i-au a³ezat prosoapele pe plaj , iar cel
de-al doilea num r reprezint num rul de localnici ale c ror zone favorite sunt libere.
Restricµii ³i preciz ri
a Colµul din stânga sus al zonei dreptunghiulare are coordonatele (1,1)
a 3 & a, b & 2 000
a 0 & u & 100
a 3 & m, n & 100 000
a Un prosop descris de x1 , y1 , x2 , y2 va avea 1 & x1 & x2 & a ³i 1 & y1 & y2 & b
a O suprafaµ favorit descris de x1 , y1 , x2 , y2 va avea 1 & x1 & x2 & a ³i 1 & y1 & y2 & b
¬ ¬ ¬ ¬ ¬ ¬ ¬ ¬
a Pentru lucrul în C/C++, se recomand citirea folosind scanf sau fscanf, deoarece sunt mai
rapide decât cin.
a Evaluare: dac se r spunde corect la prima cerinµ se obµine 40% din punctaj. Dac se
r spunde corect la ambele cerinµe se obµine 100% din punctaj.
Exemple:
plaja.in plaja.out Explicaµii
12 13 1 32 Ultimul turist nu î³i poate a³eza prosopul.
6 11
4
3477
5688
9 2 10 3
5 10 8 12
3
1 8 3 13
10 3 12 4
2 10 5 12
Zona favorit al celui de-al 2-lea localnic nu este liber .
Timp maxim de executare/test: 1.0 secunde
Memorie: total 64 MB din care pentru stiv 1 MB
Dimensiune maxim a sursei: 10 KB
Prima cerinµ cere determinarea num rului de dreptunghiuri care nu conµin în interiorul lor
nicio zon în care se g se³te o umbrel .
Rezolvarea pentru acest pas are complexitate O N U , testând pentru ecare dreptunghi din
cele N dac exist o umbrel pe care s o includ . Testarea se va face parcurgând efectiv lista de
umbrele. Aceast abordare garanteaz obµinerea a 40 de puncte.
Pentru a rezolva ecient ³i cea de-a doua cerinµ , proced m
în felul urm tor: atunci când avem un dreptunghi de coordonate
x1 y1 x2 y2 pe care trebuie s îl a³ez m pe plaj , increment m cu
1 valoarea din celulele x1 , y1 si x2 1, y2 1 ³i sc dem cu 1
valoarea din celulele x1 , y2 1 ³i x2 1, y1 , dup cum se observ
în desenul al turat.
Atunci când facem suma elementelor pe orice submatrice de
colµuri 1, 1 ³i i, j , observ m c se va aduna o unitate în orice
celul care aparµine dreptunghiului considerat. Astfel, de ecare dat când avem un dreptunghi
care trebuie a³ezat, adun m sau sc dem 1 în celulele menµionate. Dup amplasarea tuturor
celor N dreptunghiuri, calcul m suma Si,j pe orice submatrice de colµuri 1, 1 ³i i, j , folosind
urm toarea relaµie:
CAPITOLUL 28. ONI 2010 600
Si,j Si1,j Si,j 1 Si1,j 1 Vi,j , unde Vi,j este valoarea de pe poziµia i, j .
Dac Si,j % 0, atunci i, j este acoperit de cel puµin un prosop. Facem din nou sume parµiale
pe aceast matrice nou obµinut , în care consider m Si,j 1 dac ³i numai dac i, j este acoperit
¬ ¬ ¬ ¬
de cel puµin un prosop. Pentru a testa în O 1 dac o suprafaµ x1 , y1 , x2 , y2 din cele M este
în întregime liber , calcul m suma Sx¬2 ,y2¬ Sx¬2 ,y1¬ 1 Sx¬1 1,y2¬ Sx¬1 1,y1¬ 1 . Dac aceast sum
este 0, înseamn c suprafaµa este liber , iar în caz contrar va exista cel puµin o zon în înteriorul
suprafeµei care este acoperit .
Complexitatea nal este O N U A B M N .
54 }
55 printf("%d\n", Res);
56
57 return 0;
58 }
28.6 tango
Problema 6 - tango 100 de puncte
Un tango este format din fraze muzicale, ecare dintre acestea având 8 timpi muzicali. Timpii
muzicali au aceea³i durat .
La fel de important ca melodia unui tango este ³i dansul asociat ei. Mi³c rile efectuate în
timpul dansului se numesc guri. Succesiunea de guri efectuate în timpul dansului formeaz o
coregrae. Dou coregrai se consider diferite dac succesiunea gurilor care le alc tuiesc este
diferit . O coregrae frumoas asociat unui tango are particularitatea urm toare: atunci când
se termin o fraz muzical trebuie s se termine ³i o gur .
D ³i S se preg tesc pentru primul lor concurs de dans ³i ei lucreaza momentan la coregraa
de tango. Chiar dac va primul lor concurs, ei deja ³tiu n guri de dans ³i au calculat pentru
ecare dintre aceste guri câµi timpi muzicali dureaz . Fiindc le place foarte mult s danseze
împreun , ei vor s preg teasc o coregrae frumoas pentru o pies care dureaz exact k timpi
muzicali.
Cerinµe
Determinaµi num rul coregrailor frumoase modulo 999983 pentru o pies , care: dureaza exact
k timpi muzicali, respect condiµiile de mai sus ³i sunt formate doar din cele n guri cunoscute
de D ³i S (mai este prea puµin timp pân la concurs, ca ei s inveµe ³i guri noi).
Date de intrare
Pe prima linie a ³ierului de intrare tango.in se a numerele naturale nenule n ³i k , separate
printr-un singur spaµiu. Pe a doua linie se a exact n numere separate prin câte un spaµiu,
reprezintând lungimile gurilor.
Date de ie³ire
În ³ierul de ie³ire tango.out se va a³a num rul de coregrai posibile modulo 999983.
Restricµii ³i preciz ri
a n & 100 000
a k & 2 000 000 000
a k va întotdeauna divizibil cu 8
a 1 & lungimea unei guri & 8
a pentru 30% din teste va exista o singur gur de o anumit lungime
a pentru 50% din teste n & 30
a pentru 70% din teste lungimile gurilor vor numai valori din mulµimea {2, 4, 6, 8}
a Prin a modulo b se înµelege restul împ rµirii lui a la b.
Exemple:
tango.in tango.out Explicaµii
3 16 66049 Sunt 16 timpi muzicali deci o coregrae frumoas se va dansa pe
118 16 / 8 = 2 fraze muzicale.
Dac not m gurile cu litere, avem gura A de lungime 1, gura B
de lungime 1 ³i gura C de lungime 8. Prima fraz muzical poate
alc tuit din orice secvenµ alc tuit din opt buc µi de A sau B,
deci în total 28 = 256 posibilit µi. înc o posibilitate de alc tuire
a primei fraze este printr-un singur C. Rezult un total de 257
posibilit µi. Pentru a doua fraz avem tot atâtea posibilit µi, deci
în total exist 257 * 257 = 66049 coregrai frumoase posibile.
Cum 66049 modulo 999983 = 66049, se obµine rezultatul 66049.
CAPITOLUL 28. ONI 2010 602
Primul pas va s calcul m num rul de posibilit µi pentru a dansa guri care acoper exact
o fraz muzical . Trat m cazul în care gurile au lungime par ³i acestea sunt unice (acest caz
apare în 20% din teste). Vom încerca s descompunem o fraz în toate modurile posibile în guri.
Avem doar urm toarele posibilit µi:
1)8=2+2+2+2
2)8=2+2+4
3)8=2+4+2
4)8=2+6
5)8=4+2+2
6)8=4+4
7)8=6+2
8)8=8
În funcµie de ce guri avem disponibile, o parte din aceste posibilit µi pot disp rea. De exemplu
dac avem doar 2 ³i 6 atunci putem forma doar variantele 1), 4) ³i 7).
Trat m acum cazul în care avem doar timpi pari, dar nu sunt unici. S exemplic m c avem
2 guri de lungime 2 ³i 3 de lungime 6. Atunci pentru cazul 1) vor 24 moduri de a dansat
(pentru ecare gur de lungime 2 avem 2 posibilit µi), iar pentru cazurile 4) ³i 7) vor 6 moduri
de a dansate (2 * 3).
S extindem la cazul în care gurile au ³i timpi impari. în acest caz sunt mai multe moduri
de a descompune o fraz în guri:
8=1+1+1+1+1+1+1+1
8=1+1+1+1+1+1+2+0
...........................
8 = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8
Cum aceste cazuri sunt prea multe pentru a calculate de mân , se pot folosi 8 foruri imbricate
pentru a selecta valorile pentru x1, x2, ..., x8 (de la 0 la 8) astfel încât x1 + x2 .... + x8 = 8.
Pentru a nu num ra o posibilitate de mai multe ori, trebuie avut grij s nu gener m cazuri de
forma 8 = 1 + 2 + 0 + 2 + 3 + 0 + 0, ci doar cazuri în care 0-urile sunt la coad (vezi soluµia
ocial ). Alte metode mai elegante pentru a genera num rul de posibilit µi sunt programarea
dinamic specic problemei rucsacului, sau metoda backtracking.
Al doilea pas este s calcul m num rul de moduri de a dansa întreg tangoul.
Pentru a aa aceast valoare, trebuie s calcul m num rul de posibilit µi de a dansa o fraz
muzical la puterea (k / 8). Pentru a obµine punctaj maxim, acest calcul trebuie f cut folosind
exponenµiere logaritmic .
8 {
9 int n=0, k=0;
10 long long sol = 0;
11
12 freopen("tango.in","r",stdin);
13 freopen("tango.out","w",stdout);
14 scanf("%d %d", &n, &k);
15
16 //printf("%d %d\n",n,k);
17 //return 0;
18
19 for( int i = 1; i <= n; ++i)
20 {
21 int x;
22 scanf("%d", &x);
23 nr[ x ]++;
24 }
25
26 nr[ 0 ] = 1;
27 for( int i1 = 1; i1 <= 8; i1++)
28 {
29 if( nr[ i1 ] == 0) continue;
30 for( int i2 = 0; i1 + i2 <= 8; i2++)
31 {
32 if( i1 + i2 != 8 && i2 == 0) continue;
33 if( nr[ i2 ] == 0) continue;
34 for( int i3 = 0; i1 + i2 + i3 <= 8; i3++)
35 {
36 if( nr[ i3 ] == 0) continue;
37 if( i1 + i2 + i3 != 8 && i3 == 0) continue;
38 for( int i4 = 0; i1 + i2 + i3 + i4 <= 8; i4++)
39 {
40 if( nr[ i4 ] == 0) continue;
41 if( i1 + i2 + i3 + i4 != 8 && i4 == 0) continue;
42 for( int i5 = 0; i1 + i2 + i3 + i4 +i5 <= 8; i5++)
43 {
44 if( nr[ i5 ] == 0) continue;
45 if( i1 + i2 + i3 + i4 +i5 != 8 && i5 == 0) continue;
46 for( int i6 = 0; i1+i2+i3+i4+i5+i6 <= 8; i6++)
47 {
48 if( nr[ i6 ] == 0) continue;
49 if( i1+i2+i3+i4+i5+i6 != 8 && i6 == 0) continue;
50 for( int i7 = 0; i1+i2+i3+i4+i5+i6+i7 <= 8; i7++)
51 {
52 if( nr[ i7 ] == 0) continue;
53 if( i1+i2+i3+i4+i5+i6+i7 != 8 && i7 == 0)
54 continue;
55 for( int i8 = 0;
56 i1+i2+i3+i4+i5+i6+i7+i8 <= 8;
57 i8++)
58 {
59 if( i1+i2+i3+i4+i5+i6+i7+i8 == 8 )
60 {
61 long long temp =
62 ((long long ) nr[ i1 ] *
63 nr[ i2 ] * nr[ i3 ] ) % prim;
64 temp *=
65 ((long long )nr[ i4 ] * nr[ i5 ] *
66 nr[ i6 ] ) % prim;
67 temp %= prim;
68 temp = (long long)temp *
69 nr[ i7 ] * nr[ i8 ] % prim;
70 sol = ( sol + temp) % prim;
71 }
72 if( nr[ i8 ] == 0) continue;
73 }
74 }
75 }
76 }
77 }
78 }
79 }
80 }
81
82 int p = k / 8;
83 long long rez = 1;
CAPITOLUL 28. ONI 2010 604
ONI 2009
29.1 joc
Problema 1 - joc 100 de puncte
Pentru un concurs de design de jocuri, Gigel vrea s construiasc un joc. La joc particip n
concurenµi numerotaµi de la 1 la n. Fiecare concurent are la dispoziµie câte un ³ir de m înc peri,
numerotate de la 1 la m. Scopul jocului este de a g si o comoar ascuns în una din aceste
înc peri. Fiecare înc pere conµine un cod, num r natural, e egal cu 0, e având cel puµin 2 cifre.
Ultima cifr indic num rul de etape de penalizare, adic num rul de etape în care concurentul nu
are voie s p r seasc înc perea. Num rul obµinut prin eliminarea ultimei cifre a codului indic
num rul înc perii în care se va deplasa acesta la urm toarea etap sau la expirarea penaliz rii.
Exist dou excepµii de la regula de denire a codului: num rul 9999 codic o înc pere conµinând
o comoar , iar num rul 0 o înc pere conµinând o capcan .
În etapa 1 ecare juc tor intr în înc perea 1 din ³irul s u de înc peri. În funcµie de codul
g sit în înc pere sunt posibile urm toarele situaµii:
- codul g sit este 9999 ceea ce înseamn c juc torul este câ³tig tor ³i jocul se încheie la nalul
acestei etape;
- codul g sit este 0 ceea ce duce la eliminarea sa din joc;
- pentru celelalte coduri, dup efectuarea etapelor de penalizare, juc torul efectueaz o depla-
sare în înc perea indicat de cod. De exemplu la întâlnirea codul 157, dup efectuarea celor 7
etape de penalizare juc torul se va deplasa în camera 15.
Trecerea de la o etap la alta se realizeaz simultan pentru toµi concurenµii.
Cerinµe
Fiind dat num rul n de concurenµi, num rul m de înc peri alocate ec rui concurent, ³i codu-
rile din cele n m înc peri s se determine câ³tig torul jocului, num rul înc perii în care a g sit
comoara, num rul de etape parcurse pân când câ³tig torul g se³te comoara precum ³i num rul
de concurenµi eliminaµi din joc pân la etapa respectiv (inclusiv).
Date de intrare
Prima linie a ³ierului de intrare joc.in conµine dou numere naturale n ³i m, separate printr-
un spaµiu, reprezentând num rul concurenµilor, respectiv num rul înc perilor.
Urm toarele n linii conµin câte m numere naturale, separate prin câte un spaµiu, reprezentând
codurile din ecare înc pere.
Date de ie³ire
Prima linie a ³ierului de ie³ire joc.out va conµine patru numere naturale separate prin câte
un spaµiu, reprezentând indicele câ³tig torului, num rul înc perii unde a g sit comoara, num rul
etapei în care a câ³tigat ³i respectiv num rul de concurenµi eliminaµi din joc.
Restricµii ³i preciz ri
a 1 & n & 400
a 1 & m & 900
a Pentru toate testele de intrare se garanteaz c exist exact un câ³tig tor.
605
CAPITOLUL 29. ONI 2009 606
Exemple:
joc.in joc.out Explicaµii
48 2571Câ³tig juc torul al 2-lea, dup 7 etape, iar înc perea
0 9999 41 50 61 70 80 30 în care a g sit comoara este înc perea 5. în cele 7
30 80 60 60 9999 21 40 50 etape a fost eliminat un singur concurent ³i anume
20 30 40 50 61 71 81 9999 primul concurent.
20 30 50 0 61 71 9999 41 Înc perile prin care trece juc torul câ³tig tor pân
la nal sunt:
1 3 6 2 8 5
Timp maxim de executare/test: 0.2 secunde
Memorie: total 2 MB din care pentru stiv 1 MB
Se citesc din ³ier numerele n (num rul de juc tori) ³i m (num rul de înc peri pentru ecare
concurent). Pentru ecare juc tor i (1 & i & n) se execut urm toarea secvenµ de pa³i:
- se cite³te în vectorul a ³irul s u de înc peri.
- se începe de la înc perea 1 (a1) ³i etapa 1
- pentru ecare înc pere la care a ajuns, se marcheaz înc perea ca ind vizitat , iar valoarea
din înc pere poate :
` 0 - juc torul este eliminat - se reµine într-un vector, pe poziµia i num rul etapei în care
a fost eliminat; se încheie analiza ³irului s u de înc peri
` 9999 - juc torul a câ³tigat; se compar num rul etapei cu un minim ³i se retine valoarea
minim , indicele juc torului ³i num rul înc perii în care a ajuns; se încheie analiza
³irului s u de înc peri
` o valoare nenul ³i < 9999; se calculeaz indicele j al înc perii în care urmeaz s se
catapulteze; sunt posibile dou cazuri:
t dac acest indice este egal cu înc perea în care a ajuns sau înc perea în care
urmeaz s ajung a mai fost vizitat , se încheie analiza ³irului de înc peri, deoarece
juc torul intr într-un ciclu innit de mut ri.
t indicele reprezint o înc pere nevizitat , se m re³te num rul etapei cu ultima cifr
a valorii codului ³i se reia vizitarea cu înc perea j .
Dup executarea secvenµei descrise pentru toµi juc torii, se num r câµi juc tori au fost pîn
în etapa în care a fost stabilit câ³tig torul (minimul calculat), inclusiv acea etapa ³i se scriu în
³ier numerele cerute.
17 {
18 for(j=1;j<=m;j++)
19 {
20 f>>a[j];
21 viz[j]=0;
22 }
23
24 etapa=1;
25 j=1;
26 viz[1]=1;
27 castigator=0;
28 while(!castigator&&t[i]!=-1)
29 {
30 x=a[j];
31 viz[j]=1;
32
33 if(x==0)
34 {
35 t[i]=-1;
36 v[i]=etapa;
37 }
38 else
39 if(x==9999)
40 {
41 if(etapa<e_min)
42 {
43 c_min=i;
44 e_min=etapa;
45 i_min=j;
46 }
47 castigator=1;
48 }
49 else
50 {
51 if(j==x/10) break;
52 j=x/10;
53 if(viz[j]==1)
54 break;
55 else
56 etapa=etapa+x%10+1;
57 }
58 }
59 }
60
61 nrp=0;
62 for(i=1;i<=n;i++)
63 if(t[i]==-1&&v[i]<=e_min)
64 nrp++;
65 g<<c_min<<" "<<i_min<<" "<<e_min<<" "<<nrp<<endl;
66 f.close();
67 g.close();
68 return 0;
69 }
29.2 perspic
Problema 2 - perspic 100 de puncte
Se consider o matrice p tratic cu N linii ³i N coloane ce conµine toate numerele naturale de
la 1 la N N . Asupra matricei se denesc trei tipuri de operaµii codicate astfel:
a C i j - interschimbarea coloanelor i ³i j ale matricei
a R i j - interschimbarea liniilor i ³i j ale matricei
a E i j x y - interschimbarea elementului de pe linia i ³i coloana j cu elementul de pe linia x
³i coloana y .
Asupra matricei se efectueaz un set de M astfel de operaµii.
Cerinµe
Se cere s se determine num rul minim de aplic ri complete ale acestui set de operaµii dup
care se ajunge din nou în starea iniµial . În cadrul setului operaµiile se efectueaz mereu în aceea³i
ordine ³i nu se poate s ri peste o operaµie. Deoarece num rul acesta poate foarte mare se cere
restul împ rµirii sale la 13007.
CAPITOLUL 29. ONI 2009 608
Date de intrare
Fi³ierul perspic.in conµine pe prima linie numerele naturale N ³i M , separate printr-un spaµiu,
reprezentând dimensiunea matricei ³i respectiv num rul de operaµii dintr-un set. Pe urm toarele
M linii se descriu operaµiile setului.
Date de ie³ire
Fi³ierul perspic.out va conµine restul împ rµirii la 13007 al num rului minim determinat.
Restricµii ³i preciz ri
a 1 & N & 100
a 1 & M & 10.000
a Pentru 60% din teste num rul minim de aplic ri ale setului de operaµii necesare va mai
mic decât 2.000.000.000.
Exemple:
perspic.in perspic.out Explicaµii
22 2 Matricea iniµial :
C12 12
R12 34
Matricea dup prima operaµie:
21
43
Matricea dup a doua operaµie (terminarea primului set):
43
21
Matricea dup a treia operaµie:
34
12
Matricea dup a patra operaµie(terminarea celui de al doilea set):
12
34
33 4
E1122
R12
C23
Timp maxim de executare/test: 0.1 secunde
Memorie: total 2 MB din care pentru stiv 1 MB
La un moment dat se va ajunge ca P aplicat de k ori lui i s dea din nou i. Practic, acest num r
k va reprezenta num rul minim de aplic ri ale setului dup care i se va aa din nou în poziµia
iniµial . Pentru orice multiplu al lui k acest lucru va de asemenea adevarat.
CAPITOLUL 29. ONI 2009 609
Vom avea
H i - num rul minim de aplic ri ale setului de operaµii pentru care i s se ae din nou în
poziµia iniµial .
Pentru c vrem ca toate numerele i s ajung din nou în poziµiile lor iniµiale vom c uta un
multiplu comun al tuturor valorilor H i, deci trebuie s calcul m
unde cmmdc a, b se calculeaz cu algorimul lui Euclid. Acest calcul va trece doar 60% din teste
deoarece rezultatul poate deveni foarte mare.
În general se pot parcurge toate numerele prime de la 1 la N N ³i, pentru ecare num r prim
p, se determin care este puterea cea mai mare e astfel încât s existe un i pentru care H i sa
e e
e divizibil cu p . Soluµia se va înmulµi cu p , obµinând în nal cmmmc dorit.
120 }
121
122 void dump_primes()
123 {
124 int i;
125 printf("primes:\n");
126 for (i = 0; i < np; ++i)
127 printf(" %d", P[i]);
128
129 printf("\n");
130 }
131
132 int cmmmc()
133 {
134 int i, res, j;
135 for (res = 1, i = 1; i < n * n; ++i)
136 for (j = 0; j < E[i]; ++j)
137 res = (((long long)res * (i % MOD)) % MOD);
138
139 return res;
140 }
141
142 int main(void)
143 {
144 freopen("perspic.in", "rt", stdin);
145 freopen("perspic.out", "wt", stdout);
146
147 read_eval();
148 // dump();
149 gen_primes();
150 // dump_primes();
151 cycles();
152 printf("%d\n", cmmmc());
153 return 0;
154 }
29.3 rafturi
Problema 3 - rafturi 100 de puncte
Într-o bibliotec se a C dulapuri identice a³ezate unul lâng altul pe peretele unei înc peri,
dulapurile ind numerotate de la stânga spre dreapta cu numerele naturale de la 1 la C . Fiecare
dulap conµine 1000 de rafturi, situate vertical unul deasupra altuia, rafturile ec rui dulap ind
numerotate de la 1 la 1000 de jos în sus.
Fiecare dulap este prev zut cu o scar cu care se poate ajunge la orice raft. Dac bibliotecara
urc scara unui anumit dulap D pân la un anumit nivel k , ea va putea aduna orice carte de pe
rafturile 1 pân la k inclusiv, din dulapul D ³i din dulapurile învecinate (dulapul D 1 ³i dulapul
D 1).
Cunoscând dulapurile ³i rafturile de unde trebuie luate c rµi, bibliotecara dore³te s adune
toate c rµile cerute, dar suma în lµimilor pân la care trebuie s urce s e minim .
Cerinµe
Scrieµi un program care s determine suma minim a în lµimilor pân la care trebuie s urce
bibliotecara pentru a aduna toate c rµile cerute.
Date de intrare
Prima linie a ³ierului de intrare rafturi.in conµine dou numere naturale C ³i N , separate
printr-un spaµiu, reprezentând num rul dulapurilor ³i respectiv num rul c rµilor pe care bibliote-
cara trebuie s le adune.
Urm toarele N linii conµin câte dou numere naturale a b, separate printr-un spaµiu, repre-
zentând num rul dulapului, respectiv num rul raftului de unde trebuie luat o carte.
Date de ie³ire
Fi³ierul de ie³ire rafturi.out va conµine un singur num r natural reprezentând suma minim
a în lµimilor pân la care trebuie s urce bibliotecara pentru a aduna toate c rµile cerute.
CAPITOLUL 29. ONI 2009 612
Restricµii ³i preciz ri
a 1 & C & 10.000
a 1 & N & 50.000
Exemple:
rafturi.in rafturi.out Explicaµii
10 4 11 Bibliotecara urc astfel:
54 -pe dulapul 1 la raftul 1
11 -pe dulapul 4 la raftul 8
62 -pe dulapul 6 la raftul 2
38
Timp maxim de executare/test: 0.1 secunde
Memorie: total 2 MB din care pentru stiv 1 MB
La citirea datelor reµinem în vectorul carti, pentru ecare dulap, în lµimea cea mai mare de
pe care trebuie luat cartea.
Construim un vector inaltimi în care la ecare pas vom calcula suma minim a în lµimilor
rafturilor de pe care sunt coborîte c rµile pân în acel moment.
Aceasta se obµine astfel:
inaltimi[0]=0
inaltimi[1]=carti[1]
inaltimi[2]=carti[2]
16
17 printf("\n");
18 }
19
20 void citire(void)
21 {
22 FILE *f;
23 int x,y;
24 long i;
25
26 f=fopen("rafturi.in","r");
27 fscanf(f,"%d%ld",&C,&N);
28 for (i=1;i<=N;i++)
29 {
30 fscanf(f,"%d%d",&y,&x);
31 if (carti[y]<x) carti[y]=x;
32 }
33 carti[0]=0;
34 // afisare(carti);
35 fclose(f);
36 }
37
38 void calcul(void)
39 {
40 long h;
41 int i,j;
42 inaltime[0]=0;
43 for (i=1;i<=C;i++)
44 {
45 inaltime[i]=MAXV+1;
46 h=carti[i];
47 if (inaltime[i-1]+h<inaltime[i])
48 inaltime[i]=inaltime[i-1]+h;
49 for (j=i-1; j>i-3 && j>0 ;j--)
50 {
51 if (h<carti[j])
52 h=carti[j];
53 if (inaltime[j-1]+h<inaltime[i])
54 inaltime[i]=inaltime[j-1]+h;
55 }
56 }
57 }
58
59 void afisare(void)
60 {
61 FILE *g;
62 g=fopen("rafturi.out","w");
63 fprintf(g,"%ld\n",inaltime[C]);
64 //printf("%ld\n",inaltime[C]);
65 fclose(g);
66 }
67
68 int main()
69 {
70 citire();
71 calcul();
72 afisare();
73 return 0;
74 }
29.4 br
Problema 4 - br 100 de puncte
N prieteni, numerotaµi de la 1 la N , beau bere f r alcool la o mas rotund . Pentru ecare
prieten i se cunoa³te Ci - costul berii lui preferate. Din când în când, câte un prieten, e el k ,
cump r câte o bere pentru o secvenµ de prieteni aaµi pe poziµii consecutive la mas , inclusiv
lui, în sensul acelor de ceasornic. El este dispus s cheltuiasc x bani ³i dore³te s fac cinste la
un num r maxim posibil de prieteni.
Cerinµe
CAPITOLUL 29. ONI 2009 614
Se cere num rul de beri pe care le va cump ra ecare prieten k în limita sumei x de bani de
care dispune. în caz c x este mai mare decât costul berilor pentru toµi prietenii de la mas , se
vor achiziµiona maxim N beri.
Date de intrare
Prima linie a ³ierului de intrare br.in conµine dou numere naturale N ³i T separate printr-un
spaµiu reprezentând num rul de prieteni ³i respectiv num rul de prieteni care doresc s fac cinste
prietenilor s i.
A doua linie a ³ierului de intrare conµine N numere naturale C1 , C2 ..., CN , separate prin câte
un spaµiu, reprezentând costurile berilor preferate de ecare prieten. Berea pentru prietenul i are
costul Ci .
Fiecare din urm toarele T linii conµine câte dou numere separate printr-un spaµiu:
k1 x1
k2 x2
...
kT xT
precizând indicele câte unui prieten care face cinste ³i respectiv suma de bani de care acesta
dispune.
Date de ie³ire
Fi³ierul de ie³ire br.out va conµine T linii, ecare cu un singur num r Di reprezentând num rul
de beri pe care le va cump ra prietenul ki cu suma de bani xi in condiµiile problemei.
Restricµii ³i preciz ri
a 1 & N & 15.000
a 1 & T & 10.000
a 1 & Ci & 100
a 1 & ki & N
a 1 & xi & 3.000.000
a Un program corect, care se încadreaz în timp pentru T & 4000, va obµine cel puµin 30 de
puncte
a Un program corect, care se încadreaz în timp pentru N & 2000, va obµine cel puµin 60 de
puncte
a Prietenii beau numai berea lor preferat .
Exemple:
br.in br.out Explicaµii
54 3 Prietenul 1 cump r câte o bere pentru el ³i pentru prietenii 2, 3.
10 5 15 22 13 4 Costul celor 3 beri este 30.
1 32 0 Prietenul 4 cump r 4 beri: câte una pentru el ³i pentru prietenii
4 50 5 5, 1, 2. Costul celor 4 beri este 50.
19 Cu 9 bani prietenul 1 nu poate cump ra nici m car berea lui.
4 200 Prietenul 4 cump r 5 beri. Costul celor 5 beri este sub limita de
cost 200.
Timp maxim de executare/test: 0.1 secunde
Memorie: total 16 MB din care pentru stiv 1 MB
29.5 origami
Problema 5 - origami 100 de puncte
Costel este pasionat de arta oriental a confecµion rii obiectelor de hârtie, origami, dar este
abia la început ³i trebuie s se familiarizeze cu operaµiile de îndoire corect a hârtiei. El are la
dispoziµie o foaie de hârtie p trat , rupt dintr-un caiet de matematic , având dimensiunea de
exact N N p tr µele. îndoiturile trebuie realizate exact pe o linie orizontal sau vertical .
Sunt permise dou tipuri de îndoituri:
- îndoitura de tipul 1, îndoitur vertical executat la X p tr µele faµ de marginea stâng
a foii: partea din stânga a foii se pliaz c tre dreapta, de-a lungul liniei verticale aate la
distanµa de X p tr µele faµ de marginea stâng ;
- îndoitura de tipul 2, îndoitur orizontal executat la X p tr µele faµ de marginea supe-
rioar a foii: partea de sus a foii se pliaz în jos, de-a lungul liniei aate la distanµa de X
p tr µele faµ de marginea de sus a hârtiei.
În urma realiz rii unei succesiuni de îndoituri, din foaia iniµial de hârtie se va obµine un obiect,
care va avea o form dreptunghiular , cu în lµimea H , l µimea M ³i având grosimea egal cu
num rul maxim de foi care se suprapun în cadrul obiectului obµinut.
Cerinµe
Dat ind o succesiune de îndoituri aplicat unei foi de dimensiune N N , scrieµi un program
care s determine în lµimea, l µimea ³i grosimea obiectului obµinut.
Date de intrare
Fi³ierul de intrare origami.in are urm toarea structur :
- prima linie a ³ierului conµine un num r natural N , reprezentând dimensiunea iniµial a
hârtiei;
- a doua linie conµine un num r natural K , reprezentând num rul îndoiturilor;
- pe urm toarele K linii se g sesc perechi de numere naturale nenule, A B , separate printr-un
spaµiu, reprezentând tipul îndoiturii (A este 1 dac se realizeaz o îndoitur vertical sau
A este 2 dac se realizeaz o îndoitur orizontal ), respectiv la ce distanµ se realizeaz
îndoitura;
Date de ie³ire
Fi³ierul de ie³ire origami.out va conµine, pe o singur linie, trei numere naturale nenule H , L,
G, separate prin câte un spaµiu, reprezentând în lµimea, l µimea ³i respectiv grosimea obiectului
obµinut.
Restricµii ³i preciz ri
a 2 & N & 170
a 1 & K & 2N 2
a A 1 sau A 2
a 1 & B $ în lµimea sau l µimea hârtiei la momentul respectiv (funcµie de tipul îndoiturii)
Exemple:
origami.in origami.out Explicaµii
4 326 Hârtia are 4 unit µi în lµime ³i 4 unit µi l µime. Prima îndoitur
3 se realizeaz de la stânga la dreapta, de-a lungul celei de-a treia
13 linii verticale faµ de marginea stâng a foii. Se obµine o foaie de
23 în lµime 4, l µime 3 ³i grosime 2. A doua îndoitur se realizeaz
11 îndoind partea superioar a foii, în jos, de-a lungul celei de-a
treia linii orizontale faµ se marginea de sus a foii. Se obµine
un obiect de în lµime 3, l µime 3 ³i grosime 4. Dup a treia
îndoitur se obµine obiectul nal, având în lµimea 3, l µimea 2
³i grosimea 6.
Timp maxim de executare/test: 0.1 secunde
Memorie: total 16 MB din care pentru stiv 1 MB
CAPITOLUL 29. ONI 2009 617
Reprezentarea foii de hârtie se va realiza cu ajutorul unui tablou bidimensional F , având iniµial
N linii ³i N coloane ³i elementele egale cu zero.
Deoarece îndoiturile se pot realiza doar pe liniile dintre elementele tabloului, F ij va repre-
zenta grosimea foii în zona p tr µelei de pe linia i ³i coloana j .
Matricea F va reecta modic rile aduse foii iniµiale dup ecare îndoitur din ³ierul de
intrare, astfel:
- Pentru îndoitura de tip 1:
` Cazul 1: Distanta faµ de marginea st ng a foii a liniei de-a lungul c reia se realizeaz
îndoitura (Lin) este mai mic decât jumatatea l µimii hârtiei, adic 2 Lin & M .
în acest caz, realizez îndoitura suprapunând primele Lin linii, oglindite, peste urm toa-
rele Lin linii, însumând elementele corespunz toare din F .
Mut apoi toate elementele matricei c tre stânga.
` Cazul 2: Distanta faµ de marginea st ng a foii a liniei de-a lungul c reia se realizeaz
îndoitura (Lin) este mai mare decât jumatatea l µimii hârtiei, adic 2 Lin % M .
Putem reduce acest caz la cazul precedent, mutând coloanele care, prin îndoire, dep ³esc
marginea dreapt a foii la sfâr³itul tabloului, oglindite.
Se aplic apoi procedeul de la cazul precedent, îndoind foaia la distanµa M Lin
elemente.
- Pentru îndoitura de tip 2 se procedeaz asem n tor.
3
Algoritmul are, în cazul cel mai defavorabil, complexitatea O N r N .
35 tmp = F[i][k];
36 for(j=k;j<M;j++) F[i][j] = F[i][j+1];
37 F[i][M] = tmp;
38 }
39
40 // indoi
41 for(j=1;j<=CatIndoi;j++)
42 for(i=1;i<=N;i++) F[i][2*CatIndoi-j+1] += F[i][j];
43
44 // mut elementele tabloului cu CatIndoi elemente la stanga
45 for(i=1;i<=N;i++)
46 for(j=1;j<=M-CatIndoi;j++) F[i][j] = F[i][j+CatIndoi];
47 M = M - CatIndoi;
48 }
49 else
50 {
51 //daca indoitura depaseste cumva marginea de jos a foii
52 if(2*Lin>N)
53 {
54 CatIndoi = N - Lin; // numarul de coloane ale indoiturii
55 Rest = Lin - CatIndoi; // cate coloane mut la sfarsit
56 }
57 else
58 {
59 CatIndoi = Lin;
60 Rest = 0;
61 }
62
63 // copiez primele Rest linii, oglindite, la sfarsitul tabloului,
64 // deplasand liniile in sus
65 for(k=Rest;k>=1;k--)
66 for(i=1;i<=M;i++)
67 {
68 tmp = F[k][i];
69 for(j=k;j<N;j++) F[j][i] = F[j+1][i];
70 F[N][i] = tmp;
71 }
72
73 // indoi
74 for(i=1;i<=CatIndoi;i++)
75 for(j=1;j<=M;j++) F[2*CatIndoi-i+1][j] += F[i][j];
76
77 // mut elementele tabloului cu CatIndoi elemente in sus
78 for(i=1;i<=N-CatIndoi;i++)
79 for(j=1;j<=M;j++)F[i][j] = F[i+CatIndoi][j];
80 N = N - CatIndoi;
81 }
82 }
83
84 int main()
85 {
86 ifstream f(Fin);
87 int N; // dimensiunea initiala a hartiei
88 int M; // latimea hartiei, initial = N
89 int Nr; // numarul indoiturilor
90
91 int Tip; // Tipul indoiturii: 1 verticala spre dreapta;
92 // 2 - orizontal de sus in jos
93 int Lin; // Linia de-a lungul careia facem indoitura
94 int Max; // Grosimea maxima
95 int i,j;
96
97 //citesc datele de intrare si indoi
98 f>>N>>Nr;
99 M = N; // initial hartia e patrata, pe urma nu
100
101 //initializez hartia
102 for(i=1;i<=N;i++) for(j=1;j<=M;j++) F[i][j] = 1;
103 for(i=1;i<=Nr;i++)
104 {
105 f>>Tip>>Lin;
106 indoaie(N,M,Tip,Lin);
107 }
108 f.close();
109
110 // aflu grosimea maxima si afisez datele de iesire
CAPITOLUL 29. ONI 2009 619
111 Max = 0;
112 for(i=1;i<=N;i++)
113 for(j=1;j<=M;j++)
114 if(F[i][j]>Max) Max = F[i][j];
115
116 ofstream g(Fou);
117 g<<N<<" "<<M<<" "<<Max<<’\n’;
118 /*
119 for(i=1;i<=N;i++)
120 {
121 for(j=1;j<=M;j++) g<<F[i][j]<<" ";
122 g<<’\n’;
123 }
124 */
125 g.close();
126 return 0;
127 }
29.6 patrate
Problema 6 - patrate 100 de puncte
Fiind date dou numere naturale n ³i p se cere s se g seasc un num r natural m & 350.000
cu proprietatea c el poate scris atât ca sum de p p trate perfecte nenule, cât ³i ca sum de
p 1 p trate perfecte nenule, ..., cât ³i ca sum de n p trate perfecte nenule.
Cerinµe
Date de intrare
Prima linie a ³ierului de intrare patrate.in conµine dou numere naturale n ³i p separate
printr-un spaµiu, având semnicaµia de mai sus.
Date de ie³ire
Prima linie a ³ierului de ie³ire patrate.out va conµine num rul natural m c utat.
Urmeaz n p 1 linii. Linia i a ³ierului, pentru i 2, 3, ..., n p 2, va conµine p i 2
numere naturale separate prin câte un spaµiu, cu proprietatea c suma p tratelor acestora este m.
Restricµii ³i preciz ri
a2 & n & 1000
a2&p&n
a Soluµia nu este unic , se va accepta orice soluµie corect ;
a Un program corect, care se încadreaz în timp pentru n & 30, va obµine cel puµin 30 de
puncte.
a Un program corect, care se încadreaz în timp pentru n & 150, va obµine cel puµin 70 de
puncte.
Exemple:
patrate.in patrate.out Explicaµii
2 2 2
43 18 18 1 1 4
2 2 2 2
114 18 2 1 2 3
2123
Timp maxim de executare/test: 0.4 secunde
Memorie: total 16 MB din care pentru stiv 1 MB
O prim idee, greu de implementat, este de a genera toate submulµimile de 2, 3, ..., n elemente
ale mulµimii numerelor naturale ³i apoi de ale c uta pe acelea cu proprietatea c dau aceea³i
sum a p tratelor. Acesta idee este inutilizabil din punct de vedere practic deoarece num rul de
submulµimi este foarte mare.
CAPITOLUL 29. ONI 2009 620
Soluµia se bazeaz pe o idee constructiv , mai precis pe construirea din aproape în aproape a
soluµiei.
S demonstr m pentru început, din punct de vedere matematic, c exist un num r natural
m care se poate scrie, simultan ca suma de 2, 3, ..., n p trate perfecte nenule, de numere întregi.
Vom demonstra prin inducµie aceast proprietate.
P(1):
2 2
Pentru n 2 se g se³te m2 1 1 2
2 2 2 2 2
Pentru n 3 se g se³te m3 1 4 2 2 3 17
P(k): Presupunem relaµia adev rat pentru n k , cu alte cuvinte exist un num r m care se
2 2 2 2 2
scrie ca suma de 2, 3, ..., k p trate de numere întregi nenule. A³adar mk a1 a2 b1 b2 b3
2 2 2
... l1 l2 ... lk
P(k+1): Vom demonstra acum ca ³i relaµia P(k+1) este adev rat .
Mai întâi vom utiliza un alt rezultat, u³or de demonstrat, ³i anume c orice num r natural
p ' 7 poate scris sub forma p a b c . Vom aplica acest rezultat pentru mk ³i vom obµine
2 2 2
2 2 2
3 numere întregi a, b, c, astfel încât mk a b c .
Odat mk scris sub acesta form avem :
2 2 2 2 2 2 2 2 2 2 2 2
mk1 mk c a2 b2 a1 a2 c b1 b2 b3 c ... l1 l2 ... lk c .
2 2 2
Exemplu m3 17 3 3 1 ,
2 2 2 2 2 2 2 2 2 2
de unde m4 17 1 3 3 1 4 1 2 2 3 1 18
A³adar P(k+1) este adev rat deci P(n) este adev rat pentru orice n natural.
Soluµia urm re³te mecanismul descris anterior, cu observaµia c pentru a genera un num r m
2 2 2
cât mai mic, f r a avea pretenµia c este cel mai mic, facem descompunerea mk a b c în
a³a fel încât c s e minim.
33 return -1;
34 }
35
36 int main()
37 {
38 int i,j,l,k;
39 freopen("patrate.in","r",stdin);
40 freopen("patrate.out","w",stdout);
41
42 scanf("%d", &n);
43 scanf("%d", &p);
44
45 j = 2;
46 A[0] = B[0] = 1;
47 C[0] = 0;
48 l = 1;
49 FOR(i, 3, n + 1)
50 {
51 j = doit(j);
52 A[l] = a ;
53 B[l] = b ;
54 C[l] = c ;
55 l++;
56 }
57 printf("%d\n", j);
58
59 FOR(i,p,n+1)
60 {
61 k = n - i;
62 printf("%d %d",A[k],B[k]);
63 FOR(j,k+1, l) printf(" %d",C[j]);
64 printf("\n");
65 }
66
67 return 0;
68 }
Capitolul 30
ONI 2008
30.1 ab
Problema 1 - ab 100 de puncte
Una din cele mai noi pasiuni ale lui Z h rel este s studieze diverse propriet µi ale permut rilor.
De exemplu, este interesat de permut rile în care cel mai lung sub³ir cresc tor ³i cel mai lung sub³ir
descresc tor au lungimi date.
Cerinµe
S se scrie un program care determin o permutare de lungime N în care cel mai lung sub³ir
cresc tor are lungime A ³i cel mai lung sub³ir descresc tor are lungime B .
Date de intrare
Fi³ierul de intrare ab.in va conµine pe prima linie numerele N A B .
Date de ie³ire
Fi³ierul de ie³ire ab.out va conµine pe prima linie N numere separate prin câte un spaµiu,
reprezentând o permutare care respect condiµiile de mai sus. Dac exist mai multe soluµii, se
va a³a cea minim din punct de vedere lexicograc.
Restricµii ³i preciz ri
a 1 & N, A, B & 30.000
a Se garanteaz c mereu exist soluµie pentru datele de intrare
a Se nume³te sub³ir al ³irului X x1 , x2 , ..., xN , un ³ir Y xi1 , xi2 , ..., xiM cu proprietatea
1 & i1 $ i2 $ ... $ iM & N
a Un ³ir x1 , x2 , ..., xK este mai mic din punct de vedere lexicograc decat un alt ³ir y1 , y2 , ..., yK
dac exist o poziµie p & K , astfel încat xp $ yp ³i x1 y1 , x2 y2 , ..., xp1 yp1
a Pentru un test se va acorda 70% din punctaj dac permutarea a³at are cel mai lung sub³ir
cresc tor de lungime A ³i cel mai lung sub³ir descresc tor de lungime B , dar nu este minim
lexicograc.
Exemple:
ab.in ab.out Explicaµii
423 1432 Cel mai lung sub³ir cresc tor are lungime 2 (1 4, 1 3 sau 1 2), iar cel
mai lung sub³ir descresc tor are lungime 3 (4 3 2).
O alt soluµie posibil este 2 4 3 1, dar aceasta nu este minim din punct
de vedere lexicograc.
Timp maxim de executare/test: 0.1 secunde
622
CAPITOLUL 30. ONI 2008 623
Mircea Pasoi
Vom prezenta un algoritm prin care se poate obµine o permutare de lungime N cu cel mai lung
sub³ir cresc tor de lungime A ³i cel mai lung sub³ir descresc tor de lungime B :
1) Se împart numerele de la 1 la N (luate în ordinea asta) în A grupuri de lungime cel mult B
ecare. Deasemenea, trebuie s existe cel puµin un grup de lungime x B .
2) Se inverseaz elementele din ecare grup
Orice sub³ir descresc tor va face parte dintr-un grup, iar cum lungimea unui grup este maxim
B (³i exist unul cu x B ), cel mai lung sub³ir descresc tor va avea lungime B .
Orice sub³ir cresc tor va format cu câte un element din ecare grup. Cum sunt A grupuri,
cel mai lung sub³ir cresc tor va avea lungime A.
Pentru a obµine o soluµie minim lexicograc trebuie ca grupurile de la început s e cât mai
mici ca m rime.
Exemplu pentru N 10, A 4, B 3
Se împarte în 4 grupuri, ecare de lungime maxim 3 astfel încât grupurile de la început s e
cât mai mici:
1 | 2 3 4 | 5 6 7 | 8 9 10
Se inverseaz elementele din ecare grup ³i se obµine permutarea:
1 4 3 2 7 6 5 10 9 8
37 printf("\n");
38
39 return 0;
40 }
30.2 iepuras
Problema 2 - iepuras 100 de puncte
Un iepura³ se g se³te într-o gr din plin de surprize. Harta gr dinii poate reprezentat sub
forma unei table dreptunghiulare cu m linii, numerotate de la 1 la m de sus în jos, ³i n coloane,
numerotate de la 1 la n de la stânga la dreapta. în ecare celul a acestei gr dini se poate g si
cel mult una dintre urm toarele surprize: s geat , pom, zid, trap , morcov, bomb .
O s geat indic una din direcµiile nord, sud, est, vest. Odat ajuns într-o celul conµinând
o astfel de s geat iepura³ul î³i va continua deplasarea în sensul indicat de s geat , iar aceasta
dispare.
Într-o celul în care se g se³te un pom sau un zid iepura³ul nu poate s p trund , îns dac
se love³te de un pom, el î³i p streaz direcµia, îns schimb sensul (dac se deplasa spre nord,
î³i va schimba sensul spre sud, dac se deplasa spre est, se va deplasa dup aceea spre vest etc).
Dac iepura³ul intr într-o celul conµinând o trap , toate zidurile aate pe teren dispar ³i vor
ap rea alte ziduri, în poziµii precizate. Dac iepura³ul va trece din nou printr-o celul conµinând o
trap , zidurile nou construite dispar ³i vor reap rea zidurile iniµiale. Mai exact exist dou grupe
de ziduri care comut la ecare trecere printr-o celul care conµine o trap .
Dac iepura³ul va trece de dou ori prin vecin tatea unei celule conµinând o bomb (adic
prin celulele învecinate la sud, nord, est sau vest cu celula conµinând bomb ), bomba va exploda
iar iepura³ul se transform instantaneu în îngera³. De asemenea, dac iepura³ul într într-o celul
conµinând o bomb se transform instantaneu în ingeras.
Iepura³ul va ronµ i toµi morcovii care îi ies în cale. Evident c dac trece a doua oar prin
aceea³i celul , la a doua trecere nu va mai g si morcov.
Surprizele din gr din sunt codicate astfel: 1 pentru s geat spre nord, 2 pentru s geat spre
vest, 3 pentru s geat spre sud, 4 pentru s geat spre est, 5 pentru pom, 6 pentru bomb , 7
pentru morcov, 8 pentru zid, 9 pentru trap . C suµele libere de pe harta gr dinii se codic cu
0.
Iniµial, se cunosc poziµia ³i sensul de deplasare ale iepura³ului. Expediµia acestuia se termin
în urm toarele situaµii:
- la explozia unei bombe, caz în care se transform în îngera³;
- la p r sirea gr dinii (adic la ie³irea în afara zonei dreptunghiulare date), caz în care se
r t ce³te;
- în momentul în care reu³e³te s ronµ ie toµi morcovii, caz în care este fericit.
Cerinµe
Fiind data harta gr dinii se cere s se determine starea nal a iepura³ului (îngera³, r t cit
respectiv fericit), num rul de morcovi ronµ iµi pân în momentul termin rii expediµiei, precum ³i
num rul de pa³i pe care îi face iepura³ul pân la acest moment.
Date de intrare
Pe prima linie a ³ierului de intrare iepuras.in se g sesc dou numere întregi m ³i n, separate
printr-un spaµiu, reprezentând num rul de linii, respectiv num rul de coloane ale h rµii.
Linia a doua a ³ierului conµine trei numere naturale, separate prin câte un spaµiu, reprezentând
linia si coloana poziµiei iniµiale a iepura³ului pe hart precum ³i direcµia spre care acesta este
orientat. Direcµia este codicat astfel: 1 pentru nord, 2 pentru vest, 3 pentru sud, 4 pentru est.
Urm toarele m linii conµin câte n numere întregi separate prin câte un spaµiu, reprezentând
codicarea h rµii gr dinii, conform celor precizate mai sus.
Urm toarea linie conµine un singur num r natural t reprezentând num rul de celule ce vor
conµine ziduri dup prima trecere printr-o celul conµinând o trap . Urm toarele t linii conµin
câte dou numere naturale i ³i j , separate printr-un spaµiu, reprezentând coordonatele câte unei
celule ce va conµine zid dup o prim trecere printr-o celul conµinând o trap .
Date de ie³ire
CAPITOLUL 30. ONI 2008 625
Fi³ierul de ie³ire iepuras.out va conµine pe prima sa linie unul dintre cuvintele INGERAS,
RATACIT respectiv FERICIT, corespunz tor st rii nale a iepura³ului.
A doua linie a ³ierului va conµine dou numere întregi separate printr-un spaµiu, reprezentând
linia ³i coloana ultimei poziµii de pe teren a iepura³ului, adic poziµia în care a murit, sau în care
a devenit fericit, respectiv ultima poziµie a sa de pe teren, înainte de a se r t ci.
A treia linie a ³ierului va conµine dou numere întregi separate printr-un spaµiu, reprezentând
num rul de morcovi cule³i pân în momentul termin rii expediµiei, respectiv num rul de pa³i pe
care îi face iepura³ul pân ajunge în starea nal .
Restricµii ³i preciz ri
a poziµia iniµial a iepura³ului este una valid , adic este o celul liber din interiorul terenului;
a pentru datele de test, se asigur c iepura³ul va face un num r nit de pa³i pân la terminarea
expediµiei sale;
a 1 & m, n & 200
a 0 & t & 20
a num rul maxim de ziduri aate la un moment dat pe teren este de cel mult 50, ³i este posibil
ca la un moment dat s nu existe niciun zid pe teren.
a Se garanteaz c pentru datele de intrare iepura³ul nu poate ajunge simultan în dou din
cele trei st ri.
a Pomii ³i trapele sunt obiecte care r mân permanent în teren, în poziµiile lor iniµiale.
a într-o celul a gr dinii se poate g si la un moment dat o singur surpriz (pom, zid, trap ,
morcov, s geat , bomb )
Exemple:
48 int k,i0,j0,d,i,j,n1=0,n2=0,pz=1;
49 long nrm,p=0,q=0;
50
51 ifstream f("iepuras.in");
52 ofstream g("iepuras.out");
53
54 nrm=0;
55 f>>m>>n;
56 f>>i0>>j0>>d;
57
58 for (i=1;i<=m;i++)
59 for (j=1;j<=n;j++)
60 {
61 f>>a[i][j];
62 if (a[i][j]==’7’) nrm++;
63 if (a[i][j]==’8’)
64 {
65 z1[n1].i=i;
66 z1[n1].j=j;
67 n1++;
68 }
69 }
70
71 f>>n2;
72 for (i=0;i<n2;i++)
73 f>>z2[i].i>>z2[i].j;
74 f.close();
75
76 i=i0;
77 j=j0;
78 while (1)
79 {
80 i=i+di[d-1];
81 j=j+dj[d-1];
82 p++;
83
84 if (i==3 && j==190)
85 cout<<"bla";
86
87 // afara
88 if (afara(i,j))
89 {
90 g<<"RATACIT"<<endl;
91 g<<i-di[d-1]<<" "<<j-dj[d-1]<<endl;
92 g<<q<<" "<<p;
93 break;
94 }
95
96 // morcov
97 if (a[i][j]==’7’)
98 {
99 q++;
100 a[i][j]=’0’;
101 }
102
103 // e bomba sau in vecinatatea unei bombe pregatita sa explodeze
104 if (explod(i,j))
105 {
106 g<<"INGERAS"<<endl;
107 g<<i<<" "<<j<<endl;
108 g<<q<<" "<<p;
109 break;
110 }
111
112 // a cules toti morcovii
113 if (q==nrm)
114 {
115 g<<"FERICIT"<<endl;
116 g<<i<<" "<<j<<endl;
117 g<<q<<" "<<p;
118 break;
119 }
120
121 if (a[i][j]==’9’)
122 {
123 if (pz==1)
CAPITOLUL 30. ONI 2008 628
124 {
125 for (k=0;k<n1;k++)
126 a[z1[k].i][z1[k].j]=’0’;
127
128 for (k=0;k<n2;k++)
129 a[z2[k].i][z2[k].j]=’8’;
130
131 pz=2;
132 }
133 else
134 {
135 for (k=0;k<n2;k++)
136 a[z2[k].i][z2[k].j]=’0’;
137
138 for (k=0;k<n1;k++)
139 a[z1[k].i][z1[k].j]=’8’;
140
141 pz=1;
142 }
143 }
144
145 // sageata, schimba directia
146 if (a[i][j]==’1’) { d=1; a[i][j]=’0’; }
147 if (a[i][j]==’2’) { d=2; a[i][j]=’0’; }
148 if (a[i][j]==’3’) { d=3; a[i][j]=’0’; }
149 if (a[i][j]==’4’) { d=4; a[i][j]=’0’; }
150
151 // pom sau zid, schimba directia
152 if (a[i+di[d-1]][j+dj[d-1]]==’5’ || a[i+di[d-1]][j+dj[d-1]]==’8’)
153 if (d==1)
154 d=3;
155 else
156 if (d==2)
157 d=4;
158 else
159 if (d==3)
160 d=1;
161 else
162 d=2;
163 }
164
165 g.close();
166 }
30.3 palind
Problema 3 - palind 100 de puncte
Ana a descoperit c are o adev rat pasiune pentru palindroame. Un ³ir de numere este
palindrom dac se cite³te la fel de la stânga la dreapta ³i de la dreapta la stânga (primul num r
este egal cu ultimul, al doilea cu penultimul etc). Ea are un ³ir cu N numere naturale ³i vrea ca
orice subsecvenµ de lungime impar a ³irului s e palindrom. Pentru a-³i îndeplini dorinµa ea
poate efectua asupra ³irului mai multe operaµii. O operaµie const în alegerea unui element din
³ir ³i incrementarea sau decrementarea lui cu o unitate. Bineînµeles, Ana dore³te s utilizeze un
num r minim de operaµii pentru ca ³irul obµinut s respecte proprietatea amintit mai sus (orice
subsecvenµ de lungime impar s e palindrom).
Cerinµe
Determinaµi pentru Ana num rul minim de operaµii pe care trebuie s -l efectueze pentru
ca orice subsecvenµ de lungime impar a ³irului obµinut în urma efectu rii operaµiilor s e
palindrom. De asemenea aaµi ³i num rul de ³iruri nale distincte pe care le poate obµine efectuând
acest numar minim de operaµii.
Date de intrare
Fi³ierul de intrare palind.in va conµine pe prima linie num rul T , reprezentând num rul de
seturi de date de intrare care urmeaz . în continuare urmeaz seturile de date de intrare, ecare
pe câte dou linii. Pe prima linie a unui set de date se a num rul N , având semnicaµia din
enunµ. Pe urm toarea linie se a elementele ³irului iniµial, separate prin câte un spaµiu.
CAPITOLUL 30. ONI 2008 629
Date de ie³ire
Fi³ierul de ie³ire palind.out va conµine T linii, pe linia i aându-se dou numere, reprezentând
raspunsul pentru al i-lea set de date de intrare. Primul numar este numarul minim de operaµii,
iar al doilea num rul de ³iruri distincte nale care se pot obµine efectuând num rul minim de
operaµii.
Restricµii ³i preciz ri
a 1 & T & 20
a 1 & N & 10.000
a Elementele ³irului sunt numere naturale din intervalul 1, 7.000
a subsecvenµ a unui ³ir este un sub³ir de numere care apar pe poziµii consecutive
a Toate testele folosite la corectare vor avea T 20
a Pentru 20% din teste 1 & N & 100
a Pentru 20% din teste valoarea maxim din oricare ³ir este cel mult 500 ³i N ' 101
Exemple:
palind.in palind.out Explicaµii
2 23 Pentru primul test, cele trei ³iruri posibile sunt:
3 01 1 2 1, 2 2 2 si 3 2 3.
123 Pentru al doilea test, singurul ³ir posibil este format din
1 elementul 3
3
Timp maxim de executare/test: 0.5 secunde pe Windows, 0.2 secunde pe Linux
Adrian Airinei
2 #include <string.h>
3
4 #define INF 2000000000
5 #define MAXN 7001
6 #define ABS(x) ((x) < 0 ? (-(x)) : (x))
7
8 int N, A[2][MAXN], cnt[2];
9 int sol[2][2];
10
11 void solve(void)
12 {
13 int i, val, t, x, j, nr, mmin = INF;
14
15 memset(A, 0, sizeof(A)), cnt[0] = cnt[1] = 0;
16
17 scanf("%d", &N);
18 for(i = 1; i <= N; i++)
19 scanf("%d", &x), A[i&1][ ++cnt[i&1] ] = x;
20
21 for(t = 0; t <= 1; t++)
22 {
23 nr = 0, mmin = INF;
24 for(i = 1; i < MAXN; i++)
25 {
26 for(val = 0, j = 1; j <= cnt[t]; j++)
27 val += ABS(i-A[t][j]);
28 if(val == mmin) nr++;
29 if(val < mmin) mmin = val, nr = 1;
30 }
31 sol[t][0] = mmin, sol[t][1] = nr;
32 }
33
34 printf("%d %d\n", sol[0][0]+sol[1][0], sol[0][1]*sol[1][1]);
35 }
36
37 int main(void)
38 {
39 freopen("palind.in", "rt", stdin);
40 freopen("palind.out", "wt", stdout);
41
42 int teste;
43
44 scanf("%d ", &teste);
45 while(teste--)
46 solve();//, brute();
47
48 return 0;
49 }
30.4 auto
Problema 4 - auto 100 de puncte
Se consider o autostrad dispus în linie dreapt având N puncte de acces (intrare ³i ie³ire). în
ecare punct de acces exist containere pentru colectarea de³eurilor, toate containerele au aceea³i
capacitate ³i în ecare punct de acces pot mai multe astfel de containere.
Firma care asigur cur µenia dispune de un singur mijloc de transport al containerelor. Acest
mijloc de transport poate înc rca exact un num r K de containere. Accesul mijlocului de transport
pe autostrad se face cu restricµii pentru a nu perturba tracul ³i din acest motiv trebuie ca la
ecare acces pe autostrad s e colectate exact atâtea containere cât este capacitatea ma³inii,
dar dintr-un punct de colectare trebuie s ia exact un container, deci dac se intr pe autostrad
la punctul de acces P , unde P & N K 1, atunci trebuie s ia containere de la punctele de
acces numerotate cu P, P 1, P 2, ..., P K 1, în aceste puncte de acces scade cu 1 num rul
containerelor r mase.
Firma trebuie s g seasc toate valorile posibile pentru K astfel încât s poat colecta toate
containerele.
Cerinµe
Se cere s se g seasc toate valorile posibile pentru K astfel încât s e adunate toate contai-
nerele.
Date de intrare
Fi³ierul de intrare auto.in va conµine pe prima linie num rul natural T , reprezentând num rul
de seturi de date de intrare. În continuare urmeaz seturile de date de intrare, ecare pe cate dou
linii. Pe prima linie a unui set se a num rul N , având semnicaµia din enunµ. Pe urm toarea
linie se a N numere naturale separate printr-un spaµiu, reprezentând num rul de containere din
ecare punct de acces.
Date de ie³ire
Fi³ierul de ie³ire auto.out va conµine T linii, pe linia i aându-se r spunsul pentru al i-lea set
de date de intrare. Valorile posibile pentru K se vor a³a în ordine crescatoare, separate printr-un
spaµiu.
Restricµii ³i preciz ri
CAPITOLUL 30. ONI 2008 633
a 2 & T & 30
a 2 & N & 9 000
a 1&K&N
a 0 & num rul de containere din ecare punct de acces & 10 000
Exemple:
auto.in auto.out Explicaµii
2 12
8 13
12342000
3
111
Timp maxim de executare/test: 0.8 secunde pe Windows, 0.2 secunde pe Linux
Pentru un K xat, putem calcula u³or în O N K dac reprezint soluµie sau nu. Aceast
3
abordare are complexitate O N ³i obµine aproximativ 30 puncte.
Putem folosi o stiv în care avem la un moment dat invervalele sortate cresc tor dup cap tul
dreapta. Când suntem la al i-lea punct de intrare scoatem din stiv intervalele care nu conµin
punctul acesta ³i eventual introducem dac este nevoie intervalul i, i k 1. Aceast soluµie are
2
complexitate O N ³i obtine 70 puncte.
Pentru a optimiza aceast soluµie observ m c dac suma tuturor valorilor este SU M este
necesar s consider m valorile posibile pentru K care este divizor al lui SU M . Astfel complexitatea
devine O N _DIV N , unde N _DIV este num rul de divizori ai lui SU M mai mici sau egali
cu N .
29 {
30 int i, j, k; long d = 0;
31
32 scanf("%d\n", &N), NR = 0;
33 assert(N >= 1 && N <= 9000);
34
35 for(i = 1; i <= N; i++) scanf("%d ", &A[i]), d += (long)A[i],
36 assert(A[i] >= 0 && A[i] <= 10000);
37
38 for(i = 1; i <= N; i++)
39 if(d % i == 0 && check(i)) sol[++NR] = i;
40
41 for(i = 1; i <= NR; i++)
42 for(j = i+1; j <= NR; j++)
43 if(sol[i] > sol[j]) k = sol[i], sol[i] = sol[j], sol[j] = k;
44
45 for(i = 1; i <= NR; i++) printf("%d ", sol[i]);
46 printf("\n");
47 }
48
49 int main(void)
50 {
51 int teste, start, end;
52
53 freopen("auto.in", "rt", stdin);
54 freopen("auto.out", "wt", stdout);
55
56 start = clock();
57
58 scanf("%d ", &teste);
59 while(teste--)
60 read_and_solve();
61
62 fprintf(stderr, "%ld\n", steps);
63
64 end = clock();
65
66 fprintf(stderr, "%lf\n", (double)(end-start)/CLOCKS_PER_SEC);
67
68 return 0;
69 }
30.5 div
Problema 5 - div 100 de puncte
Se citesc dou numere naturale M ³i N .
Cerinµe
S se elimine o secvenµ de cifre din num rul N pentru a obµine un num r divizibil cu M de
valoare maxim .
Date de intrare
Fi³ierul de intrare div.in conµine pe prima linie num rul natural nenul M iar pe a doua linie
num rul natural N .
Date de ie³ire
Fi³ierul de ie³ire div.out va conµine dou numere întregi i1 ³i i2 separate prin câte un spaµiu,
reprezentând indicii primei, respectiv ultimei cifre care vor ³terse. Cifrele lui N se indexeaz de
la 1, de la stânga la dreapta. Dac sunt mai multe soluµii se va scrie cea pentru care primul indice
este cel mai mic. Dac nu trebuie eliminat nici o cifr se vor scrie dou cifre de 0.
Restricµii ³i preciz ri
a 2 & M & 30000
a N are cel mult 5 000 cifre
a prima cifr a lui N este nenul
a o secvenµ este format din cifre aate pe poziµii consecutive în num rul N .
Exemple:
div.in div.out Explicaµii
2 1 10 ...
3333333333
7 00 ...
33332222
7 56 ...
3333322222
Timp maxim de executare/test: 1.0 secunde pe Windows, 0.3 secunde pe Linux
CAPITOLUL 30. ONI 2008 636
41 {
42 fprintf(out, "0 0") ;
43 return 0 ;
44 }
45
46 for (int i = n ; i >= 1 ; -- i)
47 {
48 suff[i] = suff[i + 1] + putere[n - i] * digits[i] ;
49 suff[i] %= m ;
50 }
51
52 bool found(false) ;
53 int ansi(1), ansj(n) ;
54
55 for (int i = 1 ; i <= n && !found; ++ i)
56 {
57 for (int j = 1 ; j <= n - i + 1 ; ++ j)
58 {
59 int interval = (psm[j-1]*putere[n-i-j+1]+suff[j+i]) % m ;
60 if (interval == 0 && !(j == 1 && digits[i + j] == 0))
61 {
62 found = true ;
63 if (ansi == 1 && ansj == n)
64 {
65 ansi = j ;
66 ansj = j + i - 1 ;
67 }
68 else
69 {
70 for (int idx1 = 1, idx2 = 1 ; idx1 <= n && idx2 <= n ;)
71 {
72 while (ansi <= idx1 && idx1 <= ansj)
73 idx1 ++ ;
74
75 while (j <= idx2 && idx2 <= j + i - 1)
76 idx2 ++ ;
77
78 if (digits[idx1] < digits[idx2])
79 {
80 ansi = j ;
81 ansj = j + i - 1 ;
82 break ;
83 }
84
85 idx1 ++ ;
86 idx2 ++ ;
87 }
88 }
89 }
90 }
91 }
92
93 fprintf(out, "%d %d", ansi, ansj) ;
94
95 }
30.6 teatru
Problema 6 - teatru 100 de puncte
Alina este mare iubitoare de teatru. Directorul teatrului i-a oferit ³ansa s joace în mai multe
spectacole, ca gurant, deocamdat . Costumiera de scen a decis s -i dea C costume diferite
dintre cele care sunt destinate acestei stagiuni. Alina va duce costumele acas ³i le va ajusta ca
s -i vin bine. Stagiunea dureaz N zile consecutive ³i în ecare zi se joac câte o pies . Aceea³i
pies se va juca, desigur în una sau mai mai multe zile ale stagiunii. Fiec rei piese i se asociaz un
unic costum de gurant, deci pentru ecare pies în care joac , Alina trebuie s îmbrace un singur
costum, acela asociat piesei respective. Costumele de guranµi sunt identicate prin literele mari
ale alfabetului englez: A, B, C, ..., X, Y, Z. Alina are voie s -³i aleag cele C costume diferite.
Cerinµe
CAPITOLUL 30. ONI 2008 638
Cunoscând costumul asociat ec rei zile a stagiunii, ajutaµi-o pe Alina s -³i aleag cele C
costume diferite, în a³a fel încât s poat juca într-un num r cât mai mare de piese consecutive.
Date de intrare
Fi³ierul de intrare teatru.in conµine pe prima linie dou numere naturale Z ³i C desp rµite
printr-un spaµiu. Z este num rul de zile din stagiune iar C este num rul de costume diferite pe
care Alina le poate primi. Pe linia a doua, se g sesc Z caractere, litere mari ale alfabetului englez.
Caracterul al i-lea identic costumul de gurant care trebuie îmbr cat în spectacolul din ziua i.
Date de ie³ire
În ³ierul de ie³ire teatru.out se va scrie pe prima linie un num r natural N , reprezentând
num rul maxim de spectacole consecutive în care Alina poate juca. Pe linia a doua se scriu N
caractere, f r spaµii între ele, corespunz toare costumelor care vor îmbr cate în cele N piese
de teatru alese, în ordinea spectacolelor în care va juca. Dac exist mai multe soluµii de lungime
N atunci se a³eaz cea c reia îi corespunde o zi de început mai aproape de începutul stagiunii.
Restricµii ³i preciz ri
a 1 & Z & 55 000
a 1 & C & 26
a C&Z
a Pentru 20% dintre teste Z & 350
Exemple:
teatru.in teatru.out Explicaµii
10 3 5 ...
XKUFKFEGXG KUFKF
15 4 6 ...
IAJRAMRCZJJCDNS AJRAMR
25 5 8 ...
LDSDGIFAURLPTZLDLPNLEGFRN LPTZLDLP
Timp maxim de executare/test: 0.2 secunde Windows, 0.1 secunde Linux
2 #include <string.h>
3
4 #define MAX_N 55005
5 #define FIN "teatru.in"
6 #define FOUT "teatru.out"
7
8 int N, C, bst_len, start;
9 char S[MAX_N], cnt[26];
10
11 int main(void)
12 {
13 int i, j, k;
14
15 freopen(FIN, "r", stdin);
16 freopen(FOUT, "w", stdout);
17
18 scanf("%d %d %s", &N, &C, S);
19
20 for (i = 0; i < N; ++i)
21 {
22 memset(cnt, 0, sizeof(cnt));
23 for (j = i, k = 0; j < N && k <= C; ++j)
24 {
25 if (!cnt[S[j]-’A’]) { ++k; cnt[S[j]-’A’] = 1; }
26 if (k == C && bst_len < j-i+1)
27 {
28 bst_len = j-i+1;
29 start = i;
30 }
31 }
32 }
33
34 printf("%d\n", bst_len);
35 for (i = start; i < start+bst_len; ++i)
36 printf("%c", S[i]);
37 printf("\n");
38
39 return 0;
40 }
34 printf("\n");
35 }
36
37 void Calculeaza()
38 {
39 long int i = 0, j = 0, nr = 0, p;
40
41 for ( i = 0; i < n; i++ )
42 for ( j = i; j < n; j++ )
43 {
44 for ( p = ’A’; p <= ’Z’; p++ )
45 f[p] = 0;
46
47 for ( p = i; p <= j; p++ )
48 f[s[p]] = 1;
49
50 nr = 0;
51 for ( p = ’A’; p <= ’Z’; p++ )
52 if ( f[p] ) nr++;
53
54 if ( nr == k && Lmax < j - i + 1)
55 {
56 Lmax = j - i + 1;
57 imax = i; jmax = j;
58 }
59 }
60 }
Capitolul 31
ONI 2007
31.1 Agitaµie
O rm produc toare de software organizeaz un interviu pentru ocuparea unui post de pro-
gramator, la care s-au prezentat N candidaµi. Ace³tia sunt ordonaµi în funcµiie de momentul la
care ³i-au trimis CV-ul ³i numerotaµi cu numere consecutive de la 1 la N .
Fiec rui candidat i-a fost realizat în prealabil un prol psihologic ³i i s-a determinat nivelul
de agitaµie provocat de interviul care urmeaz s aib loc, precum ³i un sens (cresc tor sau
descresc tor) de modicare a acestui nivel. Astfel, la ora la care s-a anunµat începerea interviului
(pe care o vom considera momentul 0), ecare candidat are un nivel de agitaµie iniµial. Pentru
ecare unitate de timp dup momentul 0 ³i pân în momentul în care candidatul este invitat
pentru interviu (pân atunci el trebuind s a³tepte), nivelul s u de agitaµie se modic cu 1:
pentru o parte din candidaµi nivelul cre³te cu 1 unitate, iar pentru ceilalµi nivelul scade cu 1
unitate. Dac nivelul de agitaµie a unui candidat ajunge la 0, din acel moment, pentru ecare
unitate de timp urm toare, nivelul de agitaµie va cre³te cu 1 (se schimb sensul de modicare a
nivelului de agitaµie).
Firma va invita candidaµii la interviu în grupuri, în ordinea numerot rii (toµi candidaµii având
numere de ordine mai mici decât un candidat K vor invitaµi într-un grup anterior sau în acela³i
grup cu candidatul K ). Înainte de a invita un grup, comisia ce conduce interviul poate decide
s a³tepte un num r întreg de unit µi de timp (zero sau mai multe). Pentru un grup, durata
interviului se consider neglijabil (ecare candidat trebuie doar s r spund la câteva întreb ri
de tip gril ). Din momentul în care un candidat este invitat la interviu, nivelul de agitaµie a
acestuia r mâne constant.
Deoarece rma dore³te ca, indiferent de rezultatul interviului, toµi candidaµii s r mân cu o
p rere bun , comisia va forma grupurile ³i va alege timpii de a³teptare în a³a fel încât suma total
a nivelelor de agitaµie a candidaµilor la sfâr³itul interviului s e minim .
Cerinµ
S se scrie un program care s determine suma total minim a nivelelor de agitaµie a candi-
daµilor la sfâr³itul interviului.
642
CAPITOLUL 31. ONI 2007 643
Date de intrare
Fi³ierul de intrare agitatie.in are pe prima linie num rul natural N , reprezentând num rul
de candidaµi. Pe urm toarele N linii se a câte dou numere întregi A ³i B , separate printr-un
spaµiu. A reprezint nivelul iniµial de agitaµie a candidatului, iar B reprezint sensul de modicare
a agitaµiei pentru ecare unitate de timp în care acesta a³teapt (dac B este 1, atunci nivelul
de agitaµie cre³te, iar dac B este 1, nivelul de agitaµie scade). Linia k 1 din ³ier va conµine
valorile corespunz toare candidatului cu num rul k .
Date de ie³ire
Fi³ierul de ie³ire agitatie.out va conµine pe prima (³i singura) linie suma total minim a
nivelelor de agitaµie a candidaµilor la sfâr³itul interviului.
Restricµii ³i preciz ri
a 1 & N & 3000
a 1 & nivelul iniµial de agitaµie a ec rui candidat & 3000
Exemplu
agitatie.in agitatie.out
6 23
10 1
3 -1
2 -1
1 -1
91
6 -1
Explicaµie:
Suma total minim este 23.
O posibil soluµie este urm toarea: Se formeaz 3 grupuri.
Primul grup este format doar din candidatul 1 ³i a³teapt 0 unit µi de timp. Prin urmare,
nivelul nal de agitaµie a candidatului 1 va 10.
Al doilea grup va a³tepta 2 unit µi de timp din momentul în care a terminat interviul primul
grup (deci va începe interviul la momentul 2), iar din grup vor face parte candidaµii 2, 3, 4 ³i 5.
Nivelele nale de agitaµie a acestor candidaµi vor : 1, 0, 1 ³i 11. Observaµi c nivelul de agitaµie
a candidatului 4 a sc zut întâi pân la 0, apoi a crescut la 1.
Al 3-lea grup va mai a³tepta 4 unit µi de timp (deci va începe interviul la momentul 6), iar
din grup va face parte doar candidatul 6. Nivelul nal de agitaµie a acestuia va 0.
Timp maxim de execuµie/test(Windows/Linux): 0.6 secunde
S presupunem c aceast valoare se obµine pentru poziµia k din vector. Dac SU M k este mai
mic decât 0, atunci introducând o perioad de a³teptare mai mare decât 0 înaintea candidatului
k , suma total a nivelelor de agitaµie va sc dea.
Perioada de timp cu care se m re³te timpul de a³teptare dinaintea candidatului k este m rit
cu valoarea minim a nivelului de agitaµie dintre toµi candidaµii j ' k având sensuri negative de
modicare a agitaµiei. Se modic corespunz tor valorile nivelelor de agitaµie a tuturor candi-
daµilor j ' k , iar pentru toµi candidaµii care ating nivelul de agitaµie 0, se schimb ³i sensul de
modicare a nivelului de agitaµie (din 1 în 1).
Acest algoritm se repet pân în momentul în care valoarea minim din vectorul SU M este
2
mai mare sau egal cu 0. Complexitatea acestei soluµii este O N .
31.2 Coduri
Întorcându-se de la ³coal în ziua în care a aat cum se face înmulµirea numerelor, Gigel a
auzit la televizor urm toarea armaµie: "Pentru a face avere, nu trebuie s aduni bani în viaµ ,
ci trebuie s-i înmulµe³ti".
Toate acestea l-au pus pe gânduri, a³a c s-a hot rât s inventeze propriul "sistem de codicare"
pentru numere reale mai mari decât 0 care s aib urm toarele propriet µi:
- ecare num r va codicat sub forma unui ³ir de valori întregi (pozitive ³i/sau negative)
- dac un num r real x are codul cx ³i un num r real y are codul cy , atunci num rul real
rezultat prin înmulµirea lui x ³i y trebuie s aib codul obµinut prin "adunarea" codurilor c x ³i
cy .
- dac un num r real x se poate scrie ca produs de numere y1 , y2 , ..., yk , atunci codul lui x se
obµine prin "adunarea" codurilor numerelor y1 , y2 , ..., yk .
Consider m un cod c1 format din n1 valori an1 ...a1 ³i un cod c2 format din n2 valori bn2 ...b1,
atunci codul c3 obµinut prin "adunarea" codurilor c1 ³i c2 va avea n3 valori dn3 ...d1 , cu propriet µile
urm toare:
an3 este maximul dintre n1 ³i n2
~
ai bi pentru i 1, ..., min n1 , n2
adi
ai pentru i minim n1 , n2 1, ..., n1 dac minim n1 , n2 n2
bi pentru i minim n1 , n2 1, ..., n2 dac minim n1 , n2 n1
Cerinµ
Dându-se N numere reale mai mari strict decât 0, s se scrie codicarea acestora în sistemul
inventat de Gigel.
Date de intrare
Fi³ierul de intrare coduri.in va conµine:
- pe prima linie din ³ier se a num rul N de numere reale
- pe urm toarele N linii cele N numere reale, ecare pe câte o linie.
Date de ie³ire
Fi³ierul de ie³ire coduri.out va conµine N linii:
- pe linia i (i între 1 ³i N ) : num rul de valori folosite pentru codicarea num rului cu indicele
i din ³ierul de intrare, urmat de un spaµiu ³i apoi valorile ce alc tuiesc codul num rului, separate
dou câte dou printr-un singur spaµiu.
Restricµii ³i preciz ri
a2 & N & 18
aSeparatorul între partea întreag ³i partea zecimal este virgula.
a Orice num r are dup virgul cel mult 5 cifre.
a Valorile din codurile numerelor din ³ierele de test trebuie s e cuprinse în intervalul
106, 106.
a Partea întreag a ec rui num r real este o valoare mai mic sau egal cu 20000.
a Toate numerele din ³ierele de test sunt strict pozitive ³i distincte dou câte dou .
CAPITOLUL 31. ONI 2007 646
a Num rul maxim de valori utilizat pentru codicarea unui num r este 2500.
a Dac exist mai multe soluµii de codicare, se va a³a una singur .
a Nu trebuie s existe dou numere diferite cu aceea³i codicare.
a 40% din teste vor conµine numai numere întregi, 30% din teste vor conµine numere întregi ³i
numere reale f r perioad ³i 30% din teste vor conµine numere întregi ³i numere reale cu ³i f r
perioad .
Exemplu
coduri.in coduri.out Explicaµii
8 2 11
10 3 -1 0 1 10=2*5 iar suma codurilor pentru 2 ³i 5
2 3 110 determin codul lui 10
5 3 210
0,3 3 -1 2 1 2,1=7*0,3 iar suma codurilor pentru 7 ³i 0,3
7 3 131 determin codul lui 2,1
2,1 2 1 11
1,(7) 2 12
1,2(34)
Timp maxim de execuµie/test(Windows/Linux): 0.2 secunde
Rezultatele nu corespund cu cele date în exemplu dar ... pare corect aici!
16 int nr1,nr2,nr3,aux,n10,x,y;
17
18 br=new BufferedReader(new FileReader("coduri.in"));
19 out=new PrintWriter(new BufferedWriter(new FileWriter("coduri.out")));
20
21 nrprime();
22 n=Integer.parseInt(br.readLine());
23 for(i=1;i<=n;i++)
24 {
25 nr=br.readLine();
26 nr1=0;
27 for(j=0;j<nr.length();j++)
28 if(nr.charAt(j)==’,’) break;
29 else nr1=nr1*10+nr.charAt(j)-’0’;
30
31 //System.out.print(i+" : "+nr+" --> ");
32
33 if(j==nr.length()) // intreg
34 {
35 x=nr1;
36 y=1;
37
38 //System.out.println("x = "+x+" y = "+y);
39
40 if(x==1) // 1 nu se mai desxcompune ... are codul "0"
41 {
42 out.println("1 0");
43 continue;
44 }
45
46 descfact(x,f1);
47 iuf1=iuf;
48
49 out.print(iuf1+" ");
50 for(k=iuf1;k>=2;k--) out.print(f1[k]+" ");
51 out.println(f1[1]);
52
53 continue;
54 }// if intreg
55
56 nr2=0;
57 for(k=j+1;k<nr.length();k++)
58 if(nr.charAt(k)==’(’) break;
59 else nr2=nr2*10+nr.charAt(k)-’0’;
60
61 if(k==nr.length()) // real neperiodic
62 {
63 x=nr1;
64 y=1;
65 aux=nr2;
66 while(aux!=0) { x*=10; y*=10; aux/=10;}
67 x+=nr2;
68
69 descfact(x,f1);
70 iuf1=iuf;
71
72 descfact(y,f2);
73 iuf2=iuf;
74
75 iuf=max(iuf1,iuf2);
76 out.print(iuf+" ");
77 for(k=iuf;k>=2;k--)
78 {
79 if(k<=iuf1 && k<=iuf2) out.print((f1[k]-f2[k])+" "); else
80 if(k<=iuf1)
81 out.print(f1[k]+" ");
82 else
83 out.print(-f2[k]+" ");
84 }
85 out.println(f1[1]-f2[1]);
86
87 continue;
88 }// if real neperiodic
89
90 // real periodic (nr1-nr2)/nr3
91 aux=nr2;
CAPITOLUL 31. ONI 2007 648
92 n10=1;
93 while(aux!=0) {nr1*=10; aux/=10; n10=n10*10;}
94 nr1+=nr2;
95 nr2=nr1;
96 nr3=0;
97 for(j=k+1;j<nr.length()-1;j++)
98 {
99 nr1=nr1*10+nr.charAt(j)-’0’;
100 nr3=nr3*10+9;
101 }
102 nr3=nr3*n10;
103 x=nr1-nr2;
104 y=nr3;
105
106 descfact(x,f1);
107 iuf1=iuf;
108 descfact(y,f2);
109 iuf2=iuf;
110
111 iuf=max(iuf1,iuf2);
112 out.print(iuf+" ");
113 for(k=iuf;k>=2;k--)
114 {
115 if(k<=iuf1 && k<=iuf2) out.print((f1[k]-f2[k])+" "); else
116 if(k<=iuf1)
117 out.print(f1[k]+" ");
118 else
119 out.print(-f2[k]+" ");
120 }
121 out.println(f1[1]-f2[1]);
122
123 }// for i
124
125 out.close();
126 }// main(...)
127
128 static void descfact(int nr, int[] f)
129 {
130 int i;
131 i=1;
132 f[1]=0;
133 while(nr>1)
134 {
135 while(nr%p[i]==0) {f[i]++; nr/=p[i];}
136 i++;
137 f[i]=0;
138 }
139 iuf=i-1;
140 }// descfact(...)
141
142 static void nrprime()
143 {
144 int i,j;
145 boolean ok;
146 int k;
147 p[1]=2; p[2]=3; p[3]=5; p[4]=7; p[5]=11;
148 p[6]=13; p[7]=17; p[8]=19; p[9]=23; // gata ...
149 k=9;
150 for(i=29;i<=99999;i=i+2)
151 {
152 ok=true;
153 for(j=2; j<=k && p[j]*p[j]<=i && ok; j++)
154 if(i%p[j]==0) ok=false;
155 if(ok)
156 {
157 p[++k]=i;
158 }
159 }// for
160 }// nrprime(...)
161
162 static int max(int a, int b)
163 {
164 if(a>b) return a; else return b;
165 }// max(...)
166 }// class
CAPITOLUL 31. ONI 2007 649
31.3 Lacuri
Pe un teren de form p trat sunt zone de uscat ³i lacuri. Harta terenului este memorat
într-un tablou bidimensional n n cu valori 1 (ap ) sau 0 (uscat). Liniile sunt numerotate de la
1 la n, de sus în jos ³i coloanele de la 1 la n, de la stânga la dreapta. Fiecare lac este înconjurat
de o suprafaµ de teren uscat. Excepµie fac doar lacurile situate la marginea terenului care sunt
înconjurate de uscat doar prin interiorul terenului nu ³i prin afara acestuia.
Cerinµ
Se dore³te s se traverseze terenul pe uscat, de la poziµia 1, 1 la poziµia n, n, pe un drum
de lungime minim , mergând pas cu pas. La un pas, se ajunge de la un p tr µel la altul învecinat
cu el spre nord, est, sud sau vest.
S se scrie un program care:
a Determin num rul lacurilor care sunt de form p trat ³i în acela³i timp sunt "pline de
1".
b În cazul în care toate lacurile sunt de form p trat ³i în acela³i timp "pline de 1", deter-
minaµi un drum cu proprietatea de mai sus.
Date de intrare
Fi³ierul de intrare lacuri.in are pe prima linie num rul n, iar pe urm toarele n linii este harta
terenului (ecare linie are n valori 0 sau 1, separate de câte un spaµiu).
Date de ie³ire
Fi³ierul de ie³ire lacuri.out va conµine:
a pe prima linie: num rul de lacuri ce sunt de form p trat ³i în acela³i timp "pline de 1";
a în cazul în care toate lacurile sunt de form p trat ³i în acela³i timp "pline de 1", urmeaz
liniile ce descriu drumul de lungime minim ales. Fiecare linie din ³ier conµine câte o pereche de
coordonate ale poziµiilor succesive prin care trece drumul (linia ³i coloana, separate cu un spaµiu),
începând cu 1, 1 ³i terminând cu n, n.
Restricµii ³i preciz ri
a 2 & n & 100
a Poziµiile 1, 1 ³i n, n sunt sigur libere (cu valoarea 0).
a Dac exist mai multe soluµii se va a³a oricare dintre ele.
a Pot cel mult 100 de lacuri ³i cel puµin unul; dac un lac este de form p trat , atunci
1 & latura & n 1.
a Indiferent de forma lor, lacurile sunt sigur "izolate", adic nu se "ating" deloc de alt lac. De
exemplu, dac un lac conµine poziµia 3, 3, atunci un alt lac nu poate conµine vreuna din poziµiile
învecinate cu 3, 3, adic : 2, 3, 2, 4, 3, 4, 4, 4, 4, 3, 4, 2, 3, 2 ³i 2, 2.
a Pentru cerinµa a se acord 30% din punctaj, iar pentru cerinµa b) se acord 70% din punctaj.
Exemplu
lacuri.in lacuri.out
6 4
0 0 0 0 0 0 1 1
0 1 0 1 1 1 1 2
0 0 0 1 1 1 1 3
0 0 0 1 1 1 2 3
1 1 0 0 0 0 3 3
1 1 0 0 1 0 4 3
5 3
5 4
5 5
5 6
6 6
Explicaµie:
a Prima linie conµine 4 (sunt 4 lacuri de form p trat ³i "pline de 1")
b Deoarece toate cele 4 lacuri sunt de form p trat ³i "pline de 1", se scrie ³i drumul ales:
de la 1, 1, 1, 2, 1, 3, 2, 3, 3, 3, ...., (6, 6.
Observaµii:
CAPITOLUL 31. ONI 2007 650
1 Dac în poziµia 3, 5 ar fost un 0, atunci lacul cu latura 3 nu ar mai fost "plin de 1" ³i
atunci prima linie ar conµinut doar valoarea 3 (ar fost doar 3 lacuri p trate ³i "pline de 1").
2 în exemplul iniµial, dac în poziµia 6, 1 ar fost valorea 0, atunci nu ar fost toate lacurile
p trate (cel din stânga-jos nu ar fost p trat) ³i s-ar a³at doar un 3 în ?ierul de ie³ire.
3 în exemplul iniµial, dac în poziµia 5, 2 ar fost valoarea 0, atunci s-ar a³at doar un
3, pentru c lacul din stânga-jos nu ar un lac p trat ³i "plin de 1".
Timp maxim de execuµie/test: 0.25 secunde
21 st.nextToken(); n=(int)st.nval;
22 a=new int[n+2][n+2];
23 b=new int[n+2][n+2];
24
25 for(i=1;i<=n;i++)
26 for(j=1;j<=n;j++)
27 {
28 st.nextToken(); a[i][j]=b[i][j]=(int)st.nval;
29 }
30
31 if(!suntnumaipatrate())
32 {
33 System.out.println("NU ... "+np);
34 out.println(np);
35 }
36 else
37 {
38 out.println(np);
39 System.out.println("DA ... "+np);
40 out.println("1 1");
41 i=1; // casuta pusa
42 j=2; // prima casuta mai departe (libera sau ocupata)
43 while(j<=n)
44 {
45 while(b[j][j]==1) j++;
46 System.out.println("i = "+i+" j = "+j);
47
48 if(j==i+1) // casute apropiate
49 {
50 if(b[i][i+1]==0)
51 out.println(i+" "+(i+1));
52 else
53 out.println((i+1)+" "+i);
54 out.println(j+" "+j);
55 i=j;
56 j=i+1;
57 }
58 else // casute departate i=pus j=nepus
59 {
60 if(b[i+1][i]==0) // in jos, apoi dreapta
61 {
62 for(k=i+1;k<=j;k++) out.println(k+" "+i);
63 for(k=i+1;k<=j;k++) out.println(j+" "+k);
64 }
65 else // dreapta, apoi in jos
66 {
67 for(k=i+1;k<=j;k++) out.println(i+" "+k);
68 for(k=i+1;k<=j;k++) out.println(k+" "+j);
69 }
70 i=j;
71 j=j+1;
72 }// else casute departate
73 }// while
74 }// else, toate patratele sunt pline de 1
75 out.close();
76 }// main
77
78 static boolean suntnumaipatrate()
79 {
80 int i,j,i0,j0,i1,j1;
81 boolean ok,okfin;
82
83 okfin=true;
84 for(i0=1;i0<=n;i0++)
85 for(j0=1;j0<=n;j0++)
86 if(a[i0][j0]==1)
87 {
88 ok=true;
89 for(j1=j0+1;j1<=n+1;j1++) if(a[i0][j1]==0) break;
90 j1--;
91 for(i1=i0+1;i1<=n+1;i1++) if(a[i1][j0]==0) break;
92 i1--;
93 System.out.print("patrat posibil: "+i0+" "+j0+" "+i1+" "+j1);
94
95 // verificare interior
96 for(i=i0+1;i<=i1-1 && ok;i++)
CAPITOLUL 31. ONI 2007 652
31.4 Secv
Se d un ³ir de N numere întregi A1 , A2 , ..., AN . Asupra acestui ³ir se poate efectua urm toarea
operaµie: se împarte ³irul în 3 secvenµe nevide, se calculeaz valoarea maxim din ecare secvenµ
³i apoi se face suma acestor valori. Cu alte cuvinte se aleg doi indici 0 $ i $ j $ N ³i se calculeaz
valorile
X maxrAk ¶1 & k & ix,
Y maxrAk ¶i 1 & k & j x,
Z maxrAk ¶j 1 & k & N x
³i suma S X Y Z .
Cerinµ
Calculaµi valoarea minim a lui S care se poate obµine în urma unei astfel de operaµii ³i
determinaµi cei doi indici care separ secvenµele pentru a obµine aceast valoare.
Date de intrare
CAPITOLUL 31. ONI 2007 653
Prima linie a ³ierului de intrare secv.in conµine un num r natural N reprezentând num rul
de elemente al ³irului de intrare, iar a doua linie conµine numerele întregi A1 , A2 , ..., AN separate
prin câte un spaµiu.
Date de ie³ire
Fi?³erul de ie³ire secv.out va conµine:
- pe prima linie: valoarea minim a sumei;
- pe a doua linie: dou numere naturale i, j separate printr-un spaµiu, reprezentând indicii
pentru care se obµine valoarea minim pentru S prin aplicarea operaµiei descrise mai sus.
Restricµii ³i preciz ri
a 3 & N & 30000
a A1 , A2 , ..., AN sunt numere întregi din intervalul 10000, 10000
a în cazul în care exist mai multe soluµii se poate a³a oricare dintre ele.
Exemplu
secv.in secv.out Explicaµii
7 10 Prima secvenµ : 3 2 - maximul este 3
3215632 23 A doua secvenµ : 1 - maximul este 1
A treia secvenµ : 5 6 3 2 - maximul este 6
Suma: 10
Timp maxim de execuµie/test: 0.1 secunde
11 {
12 int i,j,x,y,z,max,imax=0,smin;
13 int s1=oo,s2=oo,s3=oo;
14 int i1=0,j1=0,i2=0,j2=0,i3=0,j3=0;
15
16 st=new StreamTokenizer(new BufferedReader(new FileReader("10-secv.in")));
17 out=new PrintWriter(new BufferedWriter(new FileWriter("secv.out")));
18
19 st.nextToken(); n=(int)st.nval;
20 a=new int[n+1];
21
22 max=-oo;
23 for(i=1;i<=n;i++)
24 {
25 st.nextToken(); a[i]=(int)st.nval;
26 if(a[i]>max) { max=a[i]; imax=i;}
27 }
28
29 // max in prima secventa (daca imax <= n-2)
30 if(imax<=n-2)
31 {
32 x=max;
33 s1=oo; // minim
34 for(i=imax+1;i<=n-1;i++)
35 {
36 y=a[i];
37 z=-oo;
38 for(j=i+1;j<=n;j++) if(a[j]>z) { z=a[j]; j1=j;}
39 if(x+y+z<s1) { s1=x+y+z; i1=i; j1=i1+1;}
40 }// for
41 }// if
42
43 // x in a doua secventa
44 if((imax>1)&&(imax<n))
45 {
46 s2=max+a[1]+a[n];
47 i2=1;
48 j2=n-1;
49 }
50
51 // max in a treia secventa
52 if(imax>=3)
53 {
54 z=max;
55 s3=oo; // minim
56 for(j=2;j<=imax-1;j++)
57 {
58 y=a[j];
59 x=0;
60 for(i=1;i<=j;i++) if(a[i]>x) {x=a[i]; i3=i;}
61 if(x+y+z<s3) { s3=x+y+z; j3=j;}
62 }// for
63 i3=j3-1;
64 }// if
65
66 smin=min(min(s1,s2),s3);
67 out.println(smin);
68 if(smin==s1) out.println(i1+" "+j1); else
69 if(smin==s2) out.println(i2+" "+j2); else
70 out.println(i3+" "+j3);
71 out.close();
72 }// main
73
74 static int min(int a, int b)
75 {
76 if(a<b) return a; else return b;
77 }// min(...)
78 }// class
31.5 otron
Pe asfalt este desenat cu cret un ³otron, caroiaj format din n n c suµe având acelea³i
CAPITOLUL 31. ONI 2007 655
Cerinµ
S se scrie un program care s determine cel mai mare punctaj care se poate obµine jucând
³otron dup regulile stabilite.
Date de intrare
Fi³ierul de intrare sotron.in are pe prima linie dimensiunea n a ³otronului, iar pe urm toarele
n linii câte n numere separate de câte un spaµiu, reprezentând numerele scrise în ³otron.
Date de ie³ire
Fi³ierul de ie³ire sotron.out va conµine pe prima linie un singur num r reprezentând punctajul
maxim care se poate obµine jucând ³otron.
Restricµii ³i preciz ri
1 & n & 240
Exemplu
secv.in secv.out Explicaµii
5 21
0 -6 -5 -17 2 Punctajul obµinut este
1 -4 7 10 5 3+(-2)+3+7+10=21
-3 -2 3 -8 -8
-20 3 5 3 -5
-10 -15 2 2 -4
Timp maxim de execuµie/test(Windows/Linux): 0.1 secunde
trasee pornesc din ecare c suµ în care e scris un num r cu albastru, de pe prima coloan a
³otronului sau dintr-o c suµ cu num r scris cu alb de pe ultima linie a ³otronului.
Pentru a calcula punctajul maxim obµinut de un juc tor, se calculeaz pentru ecare astfel
de traseu suma maxim a numerelor unei succesiuni de c suµe vecine. Numerele scrise într-un
traseu determinant la un moment dat se pot memora într-un vector, astfel, acest problem este
echivalent cu determinarea unei secvenµe de sum maxim dintr-un vector.
37 {
38 x[++nc]=a[ii][jj]; // sus
39 x[++nc]=a[ii][++jj]; // dreapta
40 ii--;
41 }
42 smaxc=secvsummax(nc);
43 if(smaxc>smaxsol) smaxsol=smaxc;
44 }// for i
45
46 // ultima linie
47 for(j=1;j<=n;j++)
48 {
49 if(n%2==0 && j%2==0) continue;
50 if(n%2==1 && j%2==1) continue;
51
52 nc=0;
53 x[++nc]=a[n][j];
54 ii=n;
55 jj=j+1;
56 while(jj<=n)
57 {
58 x[++nc]=a[ii][jj]; // dreapta
59 x[++nc]=a[--ii][jj]; // sus
60 jj++;
61 }
62 smaxc=secvsummax(nc);
63 if(smaxc>smaxsol) smaxsol=smaxc;
64 }// for j
65
66 out.println(smaxsol);
67 out.close();
68 }// main(...)
69
70 static int secvsummax(int n)
71 {
72 int i,i1,i2,ic,sc,smax;
73 i1=i2=ic=1;
74 smax=sc=x[1];
75 for(i=2;i<=n;i++)
76 {
77 if(sc<=0) { ic=i; sc=x[i]; continue; } else sc=sc+x[i];
78 if(sc>=smax) { smax=sc; i1=ic; i2=i; }
79 }
80 //System.out.println("smax = "+smax+" x["+i1+"..."+i2+"]");
81 return smax;
82 }// secvsummax(...)
83 }// class
31.6 Triunghi
În comuna Triunghi din România sunt n µ rani codicaµi prin numerele 1, 2, ..., n. Dup
anul 1990 a început retrocedarea suprafeµelor de p mânt deµinute înainte de colectivizare. Fiecare
µ ran are un document prin care dovede³te c este proprietar pe o singur suprafaµ de teren de
form triunghiular . Din p cate, documentele dau b taie de cap primarului (care se ocup de
retrocedarea suprafeµelor de p mânt), pentru c sunt porµiuni din suprafeµele de p mânt care se
reg sesc pe mai multe documente.
În aceast comun exist o fântân cu ap , ind posibil ca ea s e revendicat de mai mulµi
µ rani. O suprafaµ de p mânt este dat prin coordonatele celor trei colµuri, iar fântâna este
considerat punctiform ³i dat prin coordonatele punctului.
Cerinµ
S se scrie un program care s determine:
a Codurile µ ranilor care au documente cu suprafeµe de p mânt ce conµin în interior sau pe
frontier fântâna.
b Codul µ ranului ce deµine un document cu suprafaµa de teren, care include toate celelalte
suprafeµe.
Date de intrare
CAPITOLUL 31. ONI 2007 658
Fi³ierul de intrare triunghi.in are pe prima linie num rul n de µ rani, pe urm toarele n linii
câte 6 valori numere întregi separate prin câte un spaµiu, în formatul: x1 y1 x2 y2 x3 y3, ce
reprezint coordonatele celor trei colµuri ale suprafeµei triunghiulare deµinute de un µ ran (x1, x2,
x3 abscise, iar y1, y2, y3 ordonate). Pe linia i 1 se a coordonatele colµurilor suprafeµei de
teren triunghiulare deµinute de µ ranul i, i 1, 2, ..., n. Ultima linie a ³ierului (linia n 2) va
conµine coordonatele fântânii în formatul x y , cu un spaµiu între ele (x abscis , iar y ordonat ).
Date de ie³ire
Fi³ierul de ie³ire triunghi.out va conµine pe prima linie r spunsul de la punctul a, adic :
num rul de µ rani care îndeplinesc condiµia din cerinµ ³i apoi codurile lor (în ordine cresc toare),
cu un spaµiu între ele. Dac nu exist µ rani cu condiµia din cerinµ , pe prima linie se va scrie cifra
0. Pe linia a doua se va scrie r spunsul de la punctul b, adic : codul µ ranului cu proprietatea
cerut , sau cifra 0, dac nu exist un astfel de µ ran.
Restricµii ³i preciz ri
a 2 & n & 65
a coordonatele colµurilor suprafeµelor de p mânt ³i ale fântânii sunt numere întregi din inter-
valul 3000, 3000
a cele trei colµuri ale ec rei suprafeµe de p mânt sunt distincte ³i necoliniare
a nu exist doi µ rani care s deµin aceea³i suprafaµ de p mânt
a nu se acord punctaje parµiale.
Exemplu
secv.in secv.out
3 212
10 0 0 10 10 10 2
0 100 100 0 -100 0
0 0 10 0 0 10
10 5
Explicaµie:
La punctul a, sunt doi µ rani care deµin suprafeµe de p mânt ce au în interior sau pe frontier
fântâna, cu codurile 1 ³i 2.
La punctul b, µ ranul cu codul 2 deµine o suprafaµ de teren care include, suprafeµele de
p mânt deµinute de ceilalµi µ rani (cu codurile 1 ³i 3).
Timp maxim de execuµie/test: 0.1 secunde
69 s1=aria(x1[imax],y1[imax],x2[imax],y2[imax],x3[i],y3[i]);
70 s2=aria(x2[imax],y2[imax],x3[imax],y3[imax],x3[i],y3[i]);
71 s3=aria(x1[imax],y1[imax],x3[imax],y3[imax],x3[i],y3[i]);
72 if(smax!=s1+s2+s3) { ok=false; break; }
73 }
74 if(ok) out.println(imax); else out.println(0);
75 out.close();
76 }// main(...)
77
78 static int aria(int x1, int y1, int x2, int y2, int x3, int y3) // dubla ...
79 {
80 int s=x1*y2+x2*y3+x3*y1-y1*x2-y2*x3-y3*x1;
81 if(s<0) s=-s;
82 return s;
83 }
84 }// class
Capitolul 32
ONI 2006
32.1 Factorial
autor Mânz Victor Liceul
teoretic "C. Brancoveanu" Bucuresti
Pentru un num r natural nenul, denim factorialul s u ca ind produsul tuturor numerelor
naturale nenule mai mici sau egale decât el ³i îl not m N ! (adic N ! 1 2 ... N ). Pentru
o baz de numeraµie B ³i un num r natural nenul N , se cere determinarea ultimei cifre nenule a
scrierii în baza B a lui N !.
Cerinµ
Se citesc 5 perechi de forma Ni , Bi , unde 1 & i & 5. Pentru ecare din cele 5 perechi citite,
aaµi ultima cifr nenul a scrierii în baza Bi a factorialului num rului Ni .
Date de intrare
Fi³ierul de intrare fact.in conµine 5 linii, pe ecare dintre ele ind scrise câte dou numere
naturale nenule Ni ³i Bi , scrise în baza 10, desp rµite printr-un spaµiu.
Date de ie³ire
Fi³ierul de ie³ire fact.out va conµine 5 linii. Pe linia i se va aa cifra corespunz toare unei
perechi Ni , Bi , citit de pe linia i din ³ierul de intrare.
Restricµii ³i preciz ri
1 & Ni & 1000000, pentru 1 & i & 5;
2 & Bi & 36, pentru 1 & i & 5;
în cazul în care Bi % 10, cifrele mai mari decât 9 vor reprezentate prin litere mari ale
¬ ¬ ¬ ¬ ¬ ¬
alfabetului englez (10 A , 11 B ,...,35 Z );
un test va punctat doar dac toate cele 5 rezultate cerute sunt corecte.
661
CAPITOLUL 32. ONI 2006 662
Exemplu
.in .out Explicaµie
5 10 2 5! 120, în baza 10, deci ultima cifr nenul este 2
7 10 4 7! 5040, în baza 10, deci ultima cifr nenul este 4
7 20 C 7! CC0, în baza 20, deci ultima cifr nenul este C
8 16 8 8! 9D80, în baza 16, deci ultima cifr nenul este 8
9 8 6 9! 1304600, în baza 8, deci ultima cifr nenul este 6
Timp maxim de execuµie/test: 1 secund (Windows), 0.3 secunde (Linux)
Soluµia comisiei
Se descompune mai întâi B în produs de factori primi. Retinem în di0 factorul prim
cu numarul de ordine i ³i în di1 puterea la care apare acesta în descompunerea lui B .
Apoi se parcurg numerele de la 1 la N ³i din ecare dintre acestea se elimin toµi factorii primi
ai lui B , reµinuµi în di0. Se p streaz totodat în di2 puterea la care ar aparut ace³tia
în descompunerea lui N !. Odat cu eliminarea factorilor primi ai lui B din N !, se calculeaz ³i
restul la împ rµirea cu B al produsului (notat p).
Se calculeaz apoi num rul de zerouri consecutive care se vor aa la sfâr³itul lui N !, reprezentat
în baza B : minimul rapoartelor dintre di2 ³i di1, notat min. Se face diferenta între di2
³i min di1, adic num rul de elemente di0 care mai trebuie înmulµite cu p ³i se fac aceste
înmulµiri moduloB . Acesta este rezultatul c utat.
35 if(x[i]<10) fprintf(fout,"%ld\n",x[i]);
36 else fprintf(fout,"%c\n",’A’+x[i]-10);
37 }
38
39 int main()
40 {
41 long n,b,i,j;
42 long x[lmax];
43
44 fin=fopen("fact.in","r");
45 fout=fopen("fact.out","w");
46 for(i=1;i<=5;i++)
47 {
48 fscanf(fin,"%ld %ld",&n,&b);
49 x[0]=x[1]=1;
50 for(j=1;j<=n;j++)
51 multiply(x,j,b);
52 print(x);
53 for(j=0;j<lmax;j++) x[j]=0;
54 }
55 fclose(fin);
56 fclose(fout);
57 return 0;
58 }
49
50 long minim()
51 {
52 long min=d[0][2]/d[0][1];
53 for(long i=1;i<nr;i++)
54 if(d[i][2]/d[i][1]<min)
55 min=d[i][2]/d[i][1];
56 return min;
57 }
58
59 long calcul()
60 {
61 long i,j,p=cifra();
62 long min=minim();
63 for(i=0;i<nr;i++)
64 for(j=0;j<d[i][2]-d[i][1]*min;j++)
65 p=(p*d[i][0])%b;
66 return p;
67 }
68
69 void scrie()
70 {
71 long x=calcul();
72 if(x<10)
73 fprintf(fout,"%ld\n",x);
74 else
75 fprintf(fout,"%c\n",’A’+(x-10));
76 }
77
78 int main()
79 {
80 for(int i=0;i<T;i++)
81 {
82 fscanf(fin,"%ld%ld",&n,&b);
83 desc(b);
84 scrie();
85 }
86
87 fclose(fin);
88 fclose(fout);
89 return 0;
90 }
26 }//descf(...)
27
28 static void calcul()
29 {
30 int i,ii,j,min;
31 descf(b);
32 p=1;
33 for(j=1;j<=m;j++) en[j]=0;
34 for(i=2;i<=n;i++) // n!
35 {
36 ii=i;
37 for(j=1;j<=m;j++) while(ii%fb[j]==0) { en[j]++; ii/=fb[j]; }
38 p=(p*(ii%b))%b;
39 }
40
41 min=en[1]/eb[1];
42 for(j=2;j<=m;j++) if(en[j]/eb[j]<min) min=en[j]/eb[j];
43 for(j=1;j<=m;j++) en[j]=en[j]-min*eb[j];
44 for(j=1;j<=m;j++) for(i=1;i<=en[j];i++) p=(p*(fb[j]%b))%b;
45 }// calcul()
46
47 public static void main(String[] args) throws IOException
48 {
49 int k;
50 StreamTokenizer st=new StreamTokenizer(
51 new BufferedReader(new FileReader("fact.in")));
52 PrintWriter out=new PrintWriter(
53 new BufferedWriter(new FileWriter("fact.out")));
54
55 for(k=1;k<=5;k++)
56 {
57 st.nextToken(); n=(int)st.nval;
58 st.nextToken(); b=(int)st.nval;
59 calcul();
60 if(p<=9) out.println(p); else out.println((char)(p-10+’A’));
61 }
62 out.close();
63 }// main(...)
64 }// class
32.2 Limbaj
autor Domsa Ovidiu
Universitatea 1 Decembrie 1918 Alba Iulia
Denim un limbaj de programare, cu instrucµiuni de atribuire ³i de decizie. Sintaxa instruc-
µiunilor este:
Instrucµiunea de atribuire
variabila=variabila
Instrucµiunea de decizie
if
semn variabila variabila
{da
instrucµiuni }
{ nu
instrucµiuni }
Variabilele limbajului sunt identicate printr-un singur caracter, liter mic , din alfabetul
englez. Valorile variabilelor sunt de tip întreg.
semn este unul din caracterele $ , % sau
¬ ¬ ¬ ¬ ¬ ¬
.
Liniile instrucµiunilor nu conµin spaµii.
Instrucµiunile din { } pot lipsi.
Cerinµ
Dac se dau valorile iniµiale ale tuturor variabilelor (de la a la z ), în ordine alfabetic începând
cu a, se cer valorile tuturor variabilelor de la a la z , dup execuµia secvenµei de program.
CAPITOLUL 32. ONI 2006 666
Date de intrare
Fi³ier de intrare: limbaj.in
Linia 1: Va Vb ... Vz - Valorile iniµiale ale variabilelor, de la a la z , separate prin câte un
spaµiu.
Linia 2: linie de program - Urm toarele linii, pân la sfâr³itul ³ierului conµin linii de program,
Linia 3: linie de program cu instrucµiuni corecte din punct de vedere sintactic.
....
Date de ie³ire
Fi³ier de ie³ire: limbaj.out
Linia 1: Va Vb ... Vz - ³irul valorilor variabilelor, de la a la z , în ordine alfabetic , pe un rând,
separate prin câte un spaµiu.
Restricµii ³i preciz ri
30000 $ a, b, .., z $ 30000
Num rul liniilor de program este mai mic decât 10000
Limbajul este case sensitive (se folosesc doar litere mici de la a la z ).
Exemplu
limbaj.in
13574000000000000000000000
if
=ab
nu
if
$ab
da
b=d
f=d
limbaj.out
17574070000000000000000000
Timp maxim de execuµie/test: 0.5 secunde (Windows), 0.1 secunde (Linux)
Soluµia comisiei
Soluµia problemei const în parcurgerea liniar a instrucµiunilor linie cu linie ³i p strarea
valorilor logice ale condiµiilor ³i respectiv a ramurilor da ³i nu într-un ³ir.
Semnicaµia poziµiei din ³ir este nivelul de imbricare la care ne a m. Practic parcurgem, f r
a evalua, acele instrucµiuni care nu aparµin nivelului ³i ramurii pe care ne a m.
În acest sens vom evalua instrucµiunile de atribuire doar cele care îndeplinesc condiµiile de a
se aa pe nivelul corespunz tor ³i pentru care valorile condiµiilor ³i respectiv a ramurilor sunt în
aceal³i timp adevarate.
5 {
6 int i=0;
7 for(i=0;i<strlen(string);i++)
8 {
9 if ((string[i]<91) && (string[i]>=65))
10 string[i]+=32;
11 }
12 return 0;
13 }
14
15 int main()
16 {
17 freopen("limbaj.in","rt",stdin);
18 freopen("limbaj.out","wt",stdout);
19
20 int v[26];
21 int nivel[2500];
22
23 memset(nivel,0,2500*sizeof(int));
24
25 int niv=0;
26 for(int i=0;i<26;i++)
27 scanf("%d",&v[i]);
28
29 int flag=0;
30 char string[200];
31
32 while(scanf("%s",string)>0)
33 {
34 to_lower(string);
35
36 if(flag=1 && strlen(string)==3 && string[1]==’=’)
37 {
38 v[string[0]-97]=v[string[2]-97];
39 continue;
40 }
41
42 if(!strcmp(string,"if"))
43 {
44 scanf("%s",string);
45 if(string[0]==’=’)
46 if(v[string[1]-97]==v[string[2]-97])
47 nivel[niv]=1;
48
49 if(string[0]==’>’)
50 if(v[string[1]-97]>v[string[2]-97])
51 nivel[niv]=1;
52
53 if(string[0]==’<’)
54 if(v[string[1]-97]<v[string[2]-97])
55 nivel[niv]=1;
56
57 niv++;
58 continue;
59 }
60
61 if(!strcmp(string,"fi"))
62 {
63 nivel[niv-1]=0;
64 niv--;
65 }
66
67 //sar peste toate liniile din da, daca asta e fals
68 if((!strcmp(string,"da")) && (nivel[niv-1]==0))
69 {
70 flag=0;
71 char string1[10];
72 int niv1=0;
73 while(flag==0)
74 {
75 scanf("%s",string1);
76 if(!strcmp(string1,"if")) niv1++;
77 if(!strcmp(string1,"fi")&&(niv1>0)) niv1--;
78 if(!strcmp(string1,"fi")&&(niv1==0)) flag=1;
79 if(!strcmp(string1,"nu")&&(niv1==0)) flag=1;
80 }
CAPITOLUL 32. ONI 2006 668
81
82 continue;
83 }
84
85 //sar peste toate liniile din nu, daca asta e fals
86 if((!strcmp(string,"nu")) && (nivel[niv-1]==1))
87 {
88 flag=0;
89 char string1[10];
90 int niv1=0;
91 while(flag==0)
92 {
93 scanf("%s",string1);
94 if(!strcmp(string1,"if")) niv1++;
95 if(!strcmp(string1,"fi")&&(niv1>0)) niv1--;
96 if(!strcmp(string1,"fi")&&(niv1==0)) flag=1;
97 }
98 continue;
99 }
100 }
101
102 //afisarea
103 for(int j=0;j<26;j++)
104 printf("%d ",v[j]);
105 printf("\n");
106
107 return 0;
108 }
Variant cu mesaje:
104 out.close();
105 }// main(...)
106 }// class
32.3 Panouri
autor G l µan Constantin, ISJ
Bistrita-Nasaud
Pe autostrada "Soarele Estului" sunt a³ezate de-a lungul ³oselei, la distanµe egale, panouri
publicitare ale unor rme. Aceea³i rm , poate s aib mai multe panouri publicitare ³i ecare
panou poate s apar în mai multe locuri. Panourile se identic prin numere naturale, num rul
total de panouri ind N .
Firma "X Corporation" are panouri de T tipuri diferite. Firma a primit aprobarea construirii
unui mare complex turistic în apropierea autostr zii; de aceea, pentru alegerea locului, este inte-
resat ³i de urm torul aspect: care este lungimea minim de ³osea, în care se pot întâlni, toate
cele T tipuri de panouri publicitare ale rmei, indiferent de ordinea acestora, ³i indiferent dac
între ele se mai interpun sau nu panouri ale altor rme.
Cerinµ
Cunoscând N - num rul total de panouri de la marginea autostr zii ³i ordinea amplas rii lor,
ca ³i cele T tipuri de panouri amplasate de rm , determinaµi num rul minim de intervale dintre
dou panouri între care rma "X Corporation" î³i reg se³te toate panourile sale.
Date de intrare
Fi³ierul de intrare panouri.in are pe prima linie numerele N ³i T .
Pe urm toarele N linii, sunt N numere naturale, nu neaparat diferite, câte unul pe linie,
reprezentând panourile, iar începând cu linia N 2, câte unul pe linie, cele T tipuri de panouri
diferite al rmei.
Date de ie³ire
Fi³ierul de ie³ire panouri.out va conµine pe prima linie un singur num r întreg pozitiv L,
reprezentând num rul cerut, sau 1 în caz c nu exist soluµie.
Restricµii ³i preciz ri
1&N & 15000
1 & T & 1000
Toate numerele reprezentând panouri sunt numere naturale din intervalul 1..1000.
Exemple
panouri.in panouri.out Explicaµie
62 2 Sunt N 6 panouri : 1 2 3 5 3 1.
1 Firma are T 2 tipuri de panouri: 5 ³i 1.
2
3 Cel mai scurt interval care conµine elementele
5 5 ³i 1, este între panourile al 4 - lea
3 ³i al 6 -lea, ³i conµine 2 intervale.
1
5
1
83 4 Sunt N 8 panouri de tipurile: 5 1 3 3 5 4 2 1.
5 Firma are T 3 tipuri de panouri: 3, 1 ³i 4.
1
3 Cel mai scurt interval care conµine elementele
3 1, 3 ³i 4, este între al 2 lea ³i al 6-lea panou,
5 ³i conµine 4 intervale.
4
2
1
3
1
4
CAPITOLUL 32. ONI 2006 673
Soluµia comisiei
Reformul m problema: ind dat un ³ir a1..n ³i o multime B cu m elemente, s se gaseasc
dou poziµii start ³i f inal, astfel încât toate elementele mulµimii B s e conµinute în subsecvenµa
astart, ..., f inal, cu proprietatea c diferenµa f inal start are valoare minim .
Cu alte cuvinte, s se gaseasc subsecvenµa de lungime minim astart..f inal care conµine
toate elementele mulµimii B .
Având în vedere valorile mici pentru tipurile de panouri (1 & tip & 1000), pentru operaµia
de c utare în O 1 a unui element în multimea B , denim ³irul b, cu bi 1 dac i aparµine
mulµimii B .
Denim de asemenea ³rul frecvenµelor f r, cu proprietatea c f ri x daca i aparµine lui B
³i i apare de x ori în subsecvenµa astart, ..f inal.
Fix m start ³i f inal la valoarea 1 ³i increment m poziµia f inal pân când toate elementele
mulµimii B se a în intervalul astart, ..f inal. Apoi incrementam start pân la valoarea maxim
la care astart, ..f inal mai conµine înc toate elementele mulµimii B .
În continuare, pentru ecare incrementare a poziµiei f inal, m rim cât se poate de mult poziµia
start, cu respectarea restricµiilor. În acest fel ne asigur m c pentru ecare poziµie f inal, avem o
subsecvenµ de lungime minim care conµine multimea B .
Algoritmul are complexitatea O n.
36 void ReadData()
37 {
38 ifstream fin(IN);
39 fin >> n >> m;
40 for (i = 1; i <= n; i++ )
41 fin >> a[i];
42 for (i = 1; i <= m; i++ )
43 {
44 fin >> x;
45 b[x] = 1;
46 }
47 fin.close();
48 }
49
50 void Solve()
51 {
52 s = 1; f = 1;
53 nr = 0;
54 if ( b[a[s]] == 1 )
55 fr[a[s]] = 1, nr = 1;
56
57 while (f < n && nr < m) // cautam cel mai mic al 2-lea indice f
58 // astfel ca in a[s..f]
59 { // sa fie continute toate numerele din b[]
60 f++;
61 if (b[a[f]] == 1) // face parte din b[]
62 {
63 if ( fr[a[f]] == 0 ) // o singura aparitie in secventa
64 nr++;
65 fr[a[f]]++;
66 }
67 }
68
69 if ( nr < m ) // nu exista solutie
70 {
71 // fout << nr << ’\n’;
72 fout << -1 << ’\n’;
73 fout.close();
74 return;
75 }
76
77 while (b[a[s]] == 0 || (b[a[s]] == 1 && fr[a[s]] > 1))
78 --fr[a[s++]]; // marim s cat se poate astfel ca in secventa a[s..f]
79 // sa apara toate numerele din b
80 best = DIM1;
81 if (best > f - s)
82 best = f - s, minx = s, maxx = f;
83
84 for (f = f + 1; f <= n; f++ )
85 {
86 if (b[a[f]] == 1)
87 fr[a[f]]++;
88
89 while (b[a[s]] == 0 || (b[a[s]] == 1) && (fr[a[s]] > 1))
90 --fr[a[s++]]; // la fiecare incrementare a indicelui f incercam
91 // sa marim pe cat posibil si indicele s
92
93 if (best > f - s)
94 best = f - s, minx = s, maxx = f;
95 }
96
97 fout << best << ’\n’;
98 // fout << min << " " << max << ’\n’;
99 fout.close();
100 }
81 }// class
32.4 Pereµi
autor Dom³a Ovidiu,
Universitatea 1 Decembrie 1918 Alba Iulia
Localitatea Târgovi³te este în plin modernizare. Prim ria decide s inventarieze toate cl dirile
din ora³ pentru a renova faµadele acestora. În acest sens analizeaz harta ora³ului ³i constat c
toµi pereµii sunt a³ezaµi doar pe direcµia Nord Sud sau Est Vest. Pereµii vizibili de c tre turi³ti
sunt doar aceia la care se poate ajunge din exteriorul ora³ului prin deplasarea pe cele dou direcµii
date, în oricare din cele 4 sensuri (N , E , S , V ). Harta ora³ului este întocmit pe un caroiaj format
din p trate cu latur 1.
Cerinµ
Cunoscându-se harta ora³ului, determinaµi lungimea pereµilor vizibili ce urmeaz a zugr viµi.
Date de intrare
Fi³ierul de intrare pereti.in are pe prima linie dimensiunile m (num rul de linii), n (num rul
de coloane) ale h rµii. Pe ecare dintre urm toarele m linii exist n numere naturale de la 0 la
15, separate prin câte un spaµiu, cu semnicaµia:
- reprezentarea binar a num rului pe 4 cifre semnic , începând de la stânga spre dreapta,
existenµa unui perete spre direcµiile N , E , S , V (1 - exist perete, 0 - nu exist perete;
explicaµii în gura de mai jos).
De exemplu valoarea 13 se reprezint în binar 1101, deci în mod corespunz tor, de la stânga
spre dreapta, vom avea pereµi spre N, E ³i V.
N
0 6 13 1
4 15 5 1
V 0 14 1 E
4 15 0
0 12 5 7
Date de ie³ire
Fi³ierul de ie³ire pereti.out va conµine pe prima linie num rul natural k reprezentând lungimea
pereµilor ce vor zugr viµi.
Restricµii ³i preciz ri
1 & m, n & 100
Pereµii aaµi la marginea h rµii sunt pereµi vizibili.
Datele de intrare sunt considerate corecte.
Exemplu
pereti.in pereti.out Explicaµie
5 4 22 Pentru poziµiile (5, 2) ³i (5, 3) peretele dintre ele
0 6 13 1 va zugr vit pe ambele feµe.
4 15 5 1
0 14 7 1 Peretele dinspre Nord al poziµiei (1,3) este perete
4 15 9 0 exterior, chiar dac se a pe marginea h rµii.
0 12 5 7
CAPITOLUL 32. ONI 2006 678
Soluµia comisiei
Se bordeaz matricea cu valorile corespunz toare, astfel încât toat harta se înconjor cu ziduri
exterioare. Se determin toate poziµiile (celulele) din matrice accesibile din pozitia 0, 0 care este
exterioar astfel:
Se construie³te un ³ir de perechi, i, j care vor marca pe rând poziµiile din matrice pe care
le-am parcurs deja.
Se porne³te din 0, 0, se determin toate poziµiile din matrice vecine cu acestea, în care se
poate ajunge, ³i se adaug la ³irul construit. Odat ad ugate, se trece la urm toarea poziµie din
³ir ³i se adaug din nou toµi vecinii accesibili din aceasta dar care nu gureaz în ³irul nostru.
Procedura continu pân când marc m toµi vecinii celulelor ad ugate în ³ir.
Pentru a marca elementele din matrice deja ad ugate în sir adun m 16 ec rei "celule". În
acela³i timp ad ug m num rul de pereµi vizibili din exterior, respectiv 1, 2 sau 3 în funcµie de
valoarea celulei.
Vericarea vecinilor se realizeaz f r a folosi descompunerea binar a valorilor. Se folose³te
operaµia AND între valorile numerice întregi (de exemplu, 8 and 11 = 8 deci exist perete spre
N).
23 read(f,a[i,j]);
24 readln(f);
25 end;
26 close(f);
27 end;
28
29 procedure bordare(var a:mat;m,n:byte);
30 var i:byte;
31 begin
32 for i:=0 to n+1 do
33 begin
34 a[0,i]:=8+ (a[1,i] and 8) div 4;
35 a[m+1,i]:=2+ (a[m,i] and 2)* 4 ;
36 end;
37 for i:=0 to m+1 do
38 begin
39 a[i,0]:=a[i,0]+1+(a[i,1] and 1) * 4;
40 a[i,n+1]:=a[i,n+1]+4+(a[i,n] and 4) div 4;
41 end;
42 end;
43
44 Procedure fill(x,y:byte);
45 var i:byte;
46 begin
47 a[x,y]:=a[x,y]+16;
48 for i:=1 to 4 do
49 if (a[x,y] and d[i]<>d[i]) and (a[x+dx[i],y+dy[i]]<16) then
50 fill(x+dx[i],y+dy[i]);
51 end;
52
53 Function numara(var a:mat;m,n:byte):longint;
54 var nr:longint;
55 i,j:byte;
56 begin
57 nr:=0;
58 for i:=1 to m do
59 for j:=1 to n do
60 begin
61 if a[i,j]>16 then
62 case a[i,j]-16 of
63 1,2,4,8: nr:=nr+1;
64 3,5,6,9,10,12: nr:=nr+2;
65 7,11,13,14: nr:=nr+3;
66 end;
67 end;
68 for i:=1 to n do
69 begin
70 if a[0,i]<>24 then inc(nr);
71 if a[m+1,i]<>18 then inc(nr);
72 end;
73 for i:=1 to m do
74 begin
75 if a[i,0]<>17 then inc(nr);
76 if a[i,n+1]<>20 then inc (nr);
77 end;
78 numara:=nr;
79 end;
80
81 begin
82 citire(a,m,n);
83 bordare(a,m,n);
84 fill(0,0);
85 assign(f,’pereti.out’);
86 rewrite(f);
87 writeln(f,numara(a,m,n));
88 close(f);
89 end.
1 import java.io.*;
2 class Pereti
3 {
4 static final int nord=8, est=4, sud=2, vest=1;
5 static int m,n,np,nz;
6 static int[][] a=new int[101][101];
7 static int[][] b=new int[101][101];
8
9 static void fill(int i, int j)
10 {
11 b[i][j]=nz;
12
13 if((a[i][j] & nord)!=0) np++;
14 if((a[i][j] & est) !=0) np++;
15 if((a[i][j] & sud) !=0) np++;
16 if((a[i][j] & vest)!=0) np++;
17
18 if((i-1>=1)&&(b[i-1][j]==0)&&((a[i][j]&nord)==0)) fill(i-1,j);// nord
19 if((i+1<=m)&&(b[i+1][j]==0)&&((a[i][j]&sud)==0)) fill(i+1,j);// sud
20 if((j-1>=1)&&(b[i][j-1]==0)&&((a[i][j]&vest)==0)) fill(i,j-1);// vest
21 if((j+1<=n)&&(b[i][j+1]==0)&&((a[i][j]&est)==0)) fill(i,j+1);// est
22 }// fill(...)
23
24 static void intra()
25 {
26 int i,j;
27 for(i=1;i<=m;i++) // de la vest
28 if((b[i][1]==0)&&((a[i][1]&vest)==0)) { nz++; fill(i,1); }
29 for(i=1;i<=m;i++) // de la est
30 if((b[i][n]==0)&&((a[i][n]&est)==0)) { nz++; fill(i,n); }
31 for(j=1;j<=n;j++) // de la nord
32 if((b[1][j]==0)&&((a[1][j]&nord)==0)) { nz++; fill(1,j); }
33 for(j=1;j<=n;j++) // de la sud
34 if((b[m][j]==0)&&((a[m][j]&sud)==0)) { nz++; fill(m,j); }
35 }// intra(...)
36
37 static void exterior()
38 {
39 int i,j;
40 for(i=1;i<=m;i++) if((a[i][1]&vest)!=0) np++; // vest
41 for(i=1;i<=m;i++) if((a[i][n]&est) !=0) np++; // est
42 for(j=1;j<=n;j++) if((a[1][j]&nord)!=0) np++; // nord
43 for(j=1;j<=n;j++) if((a[m][j]&sud) !=0) np++; // sud
44 }// exterior(...)
45
46 public static void main(String[] args) throws IOException
47 {
48 int i,j;
49 StreamTokenizer st=new StreamTokenizer(
50 new BufferedReader(new FileReader("pereti.in")));
51 PrintWriter out=new PrintWriter(
52 new BufferedWriter(new FileWriter("pereti.out")));
53 st.nextToken(); m=(int)st.nval;
54 st.nextToken(); n=(int)st.nval;
55 for(i=1;i<=m;i++)
56 for(j=1;j<=n;j++) { st.nextToken(); a[i][j]=(int)st.nval; }
57 np=0; // nr pereti
58 nz=0; // nr zone (fill!)
59 intra();
60 exterior();
61 out.println(np);
62 out.close();
63 }// main(...)
64 }// class
32.5 anµ
autor erban Marinel, Liceul de
Informatica "Gr. C. Moisil" Iasi
Cei n deµinuµi ai unei închisori, numerotaµi de la 1 la n, trebuie s sape un ³anµ dispus în linie
dreapt între dou puncte A ³i B , situate la distanµa de 250 km unul de cel lalt, pe care exist
251 borne kilometrice numerotate de la 0 la 250. Fiecare deµinut are îns o pretenµie, "e doar
CAPITOLUL 32. ONI 2006 682
democraµie, nu?": el dore³te s sape doar undeva în zona dintre borna x ³i borna y . Pe lâng
aceste pretenµii închisoarea se confrunt ³i cu o alt problem : nu are sucienµi paznici angajaµi.
Cerinµ
Cunoscându-se num rul n de deµinuµi ³i pretenµiile lor, s se determine locul (locurile) unde
vor pu³i deµinuµii s sape într-o zi de munc , respectându-se pretenµiile lor, astfel încât num rul
de paznici necesari pentru a p zi cei n deµinuµi s e minim. Intervalul în care poate p zi un
paznic nu poate conµine dou sau mai multe zone disjuncte dintre cele exprimate de deµinuµi în
preferinµele lor.
Date de intrare
Fi³ierul de intrare sant.in are pe prima linie num rul n de deµinuµi. Pe ecare dintre urm -
toarele n linii exist câte dou numere naturale, ai bi , separate printr-un spaµiu (ai & bi ), care
reprezint pretenµia deµinutului. Mai exact pe linia i 1 (1 & i & n) este descris pretenµia
deµinutului cu num rul de ordine i.
Date de ie³ire
Fi³ierul de ie³ire sant.out va conµine pe prima linie num rul natural k reprezentând num rul
minim de paznici necesari pentru paza celor n deµinuµi sco³i la lucru. Pe urm toarele 2k linii vor
descrise locurile unde vor pu³i s sape deµinuµii, astfel: ecare pereche de linii 2j, 2j 1
va conµine pe linia 2j trei numere naturale p xj yj , separate prin câte un spaµiu reprezentând
num rul de ordine al paznicului ³i bornele kilometrice xj c si yj unde va p zi paznicul p, iar pe
linia 2j 1 vor scrise numerele de ordine ale deµinuµilor care sap în aceast zon , separate prin
câte un spaµiu, ordonate cresc tor.
Restricµii ³i preciz ri
1 & n & 10000
Exemplu
.in .out Explicaµie
3 2 sunt necesari 2 paznici: paznicul 1 va p zi între
0 20 1 8 13 borna 8 ³i borna 13, iar deµinuµii p ziµi sunt 1 ³i 2;
8 13 1 2 paznicul 2 va p zi între borna 30 ³i borna 60, iar
30 60 2 30 60 deµinutul p zit este 3
3
4 3 sunt necesari 3 paznici: paznicul 1 va p zi între
10 203 1 10 20 borna 10 ³i borna 20, iar deµinutul p zit este 1;
2 53 1 paznicul 2 va p zi la borna 5, iar deµinuµii p ziµi
30 403 2 55 sunt 2 ³i 4; paznicul 3 va p zi între borna 30 ³i
5 7 33 2 4 borna 40, iar deµinutul p zit este 3
3 30 40
3
5 2 sunt necesari 2 paznici: paznicul 1 va p zi la
10 30 1 30 30 borna 30, iar deµinuµii p ziµi sunt 1, 2, 3 ³i 4;
30 32 1 234 paznicul 2 va p zi între borna 27 ³i borna 28,
0 30 2 27 28 iar deµinutul p zit este 5
27 30 5
27 28 !Soluµia nu este unic !
Soluµia comisiei
Problema cere, de fapt, determinarea num rului minim de intersecµii între segmentele deter-
minate de kilometrul minim ³i maxim între care sap un deµinut.
Pentru a le determina procedez astfel:
ordonez intervalele cresc tor dup kilometrul minim ³i descresc tor dup kilometrul maxim
pun primul deµinut (deci cel cu intervalul de s pare cel mai mare) în grija primului paznic
pentru toate celelalte
caut un paznic care mai p ze³te deµinuµi ³i care poate p zi ³i acest deµinut (adic
intersecµia segmentelor s e nevid )
dac g sesc
ajustez intervalul de s pare ca s poat s pa ³i acest deµinut
altfel (dac nu g sesc)
mai am nevoie de un paznic ³i îl dau în grija acestuia
Datorit faptului c intervalele sunt sortate, cresc tor dup cap tul inferior, în momentul când
un interval nu se mai intersecteaz cu cel deja determinat, este sigur c nici un alt interval ce îl
urmeaz nu se mai intersecteaz , lucru ce asigur determinarea num rului minim de paznici.
36 }
37 fclose(Fisier);
38 }
39
40 void Citeste(void)
41 {
42 int i;
43
44 Fisier=fopen("sant.in", "rt");
45 fscanf(Fisier, "%d", &N);
46 for (i=1; i<=N; i++)
47 {
48 fscanf(Fisier, "%d %d", &D[i].min, &D[i].max);
49 D[i].NrOrd=i;
50 }
51 fclose(Fisier);
52 }
53
54 int Cauta(unsigned char min, unsigned char max)
55 {
56 int i, Unde=-1;
57
58 for (i=1; i<= NrPaznici; i++)
59 {
60 if ((P[i].max>=min) && (P[i].max<=max)) Unde=i;//am gasit Paznicul i
61 if ((P[i].min>=min) && (P[i].min<=max)) Unde=i;//am gasit Paznicul i
62 if ((P[i].min<=min) && (P[i].max>=max)) Unde=i;//am gasit Paznicul i
63 }
64 return Unde;
65 }
66
67 unsigned char Maxim(unsigned char x, unsigned char y)
68 {
69 if (x>y) return x;
70 return y;
71 }
72
73 unsigned char Minim(unsigned char x, unsigned char y)
74 {
75 if (x<y) return x;
76 return y;
77 }
78
79 void Intersectie(int j, unsigned char min, unsigned char max)
80 {
81 P[j].min=Maxim(min, P[j].min);//modific kilometrul minim unde pazeste
82 P[j].max=Minim(max, P[j].max);//modific kilometrul maxim unde pazeste
83 }
84
85 void PunePaznici(void)
86 {
87 int i, j;
88 unsigned char min, max;
89
90 P[1].min=D[1].min;
91 P[1].max=D[1].max;
92 NrPaznici=1;
93 D[1].NrP=NrPaznici;
94 for (i=2; i<= N; i++) //pentru toti ceilalti detinuti
95 {
96 min=D[i].min; max=D[i].max;
97 j=Cauta(min, max); //caut un Paznic care mai pazeste detinuti
98 if (j>0) //daca gasesc
99 {
100 Intersectie(j, min, max);//ajustez kilometri din Paznic ca sa
101 D[i].NrP=j; //pazeasca si noul detinut
102 }
103 else //altfel
104 {
105 NrPaznici++; //iau un Paznic nou
106 P[NrPaznici].min=min;
107 P[NrPaznici].max=max;
108 D[i].NrP=NrPaznici; //si ii dau in grija detinutul
109 }
110 }
111 }
CAPITOLUL 32. ONI 2006 685
112
113 int main()
114 {
115 Citeste();
116 PunePaznici();
117 Afiseaza();
118 return 0;
119 }
65
66 for (j=i+1; j<=N; j++)
67 if (D[j].min<KMmin) //crescator dupa kilometrul minim
68 { KMmax=D[j].max; KMmin=D[j].min; pKMmin=j; }
69 else
70 if (D[j].min==KMmin)//pentru kilometrul minim egal
71 if (D[j].max>KMmax) //descrescator dupa cel maxim
72 { KMmax=D[j].max; KMmin=D[j].min; pKMmin=j; }
73
74 Aux=D[pKMmin];
75 D[pKMmin]=D[i];
76 D[i]=Aux;
77 }
78 }
79
80 void Sorteaza(int p, int u)
81 {
82 int i, j, pozm;
83 int min;
84 struct Detinut Aux;
85
86 for (i=p; i<u; i++)
87 {
88 min=D[i].NrOrd;
89 pozm=i;
90
91 for (j=i+1; j<=u; j++)
92 if (D[j].NrOrd<min)
93 {
94 min=D[j].NrOrd;
95 pozm=j;
96 }
97
98 Aux=D[i];
99 D[i]=D[pozm];
100 D[pozm]=Aux;
101 }
102 }
103
104 void Citeste(void)
105 {
106 int i, x, y;
107
108 Fisier=fopen("sant.in", "rt");
109 fscanf(Fisier, "%d", &N);
110
111 for (i=1; i<=N; i++)
112 {
113 fscanf(Fisier, "%d %d", &x, &y);
114 D[i].min=x;
115 D[i].max=y;
116 D[i].NrOrd=i;
117 }
118
119 fclose(Fisier);
120 }
121
122 void PunePaznici(void)
123 {
124 int i, j;
125 char min, max;
126
127 //pun primul detinut (deci cel cu intervalul cel mai mare sau)
128 //la primul Paznic
129 P[1].min=D[1].min;
130 P[1].max=D[1].max;
131 NrPaznici=1;
132 D[1].NrP=NrPaznici;
133
134 for (i=2; i<= N; i++) //pentru toti ceilalti detinuti
135 {
136 min=D[i].min; max=D[i].max;
137 j=Cauta(min, max); //caut un Paznic care mai pazeste detinuti
138 //si poate sa-l pazeasca si pe asta
139 if (j>0) //daca gasesc
140 {
CAPITOLUL 32. ONI 2006 687
17 while(i<j)
18 {
19 while(x2[i]<val) i++;
20 while(x2[j]>val) j--;
21 if(i<=j)
22 {
23 aux=x1[i]; x1[i]=x1[j]; x1[j]=aux;
24 aux=x2[i]; x2[i]=x2[j]; x2[j]=aux;
25 aux=o[i]; o[i]=o[j]; o[j]=aux;
26 i++;
27 j--;
28 }
29 }// while
30
31 if(li<j) qsort(li,j);
32 if(i<ls) qsort(i,ls);
33 }// qsort(...)
34
35 public static void main(String[] args) throws IOException
36 {
37 int k,np,xp;
38 StreamTokenizer st=new StreamTokenizer(
39 new BufferedReader(new FileReader("sant.in")));
40 PrintWriter out=new PrintWriter(
41 new BufferedWriter(new FileWriter("sant.out")));
42
43 st.nextToken(); n=(int)st.nval;
44 for(k=1;k<=n;k++)
45 {
46 st.nextToken(); x1[k]=(int)st.nval;
47 st.nextToken(); x2[k]=(int)st.nval;
48 o[k]=k;
49 }
50
51 qsort(1,n);
52
53 np=1;
54 xp=x2[1];
55 for(k=2;k<=n;k++) if(x1[k]>xp) { np++; xp=x2[k]; }
56 out.println(np);
57
58 // inca o data pentru ...!
59 np=1;
60 xp=x2[1];
61 out.println(np+" "+xp+" "+xp);
62 out.print(o[1]+" ");
63 for(k=2;k<=n;k++)
64 {
65 if(x1[k]>xp)
66 {
67 out.println();
68 np++;
69 xp=x2[k];
70 out.println(np+" "+xp+" "+xp);
71 out.print(o[k]+" ");
72 }
73 else out.print(o[k]+" ");
74 }// for k
75 out.close();
76 }// main(...)
77 }// class
32.6 Zumzi
autor Popescu Carmen, Colegiul
National "Gh. Lazar" Sibiu
Albinuµa zumzi locuie³te într-un stup format din N celule de form hexagonal . Cele N celule
numerotate de la 1 la N sunt dispuse sub form de spiral (ca în gur ).
CAPITOLUL 32. ONI 2006 689
15
14 16
13 5 17
4 6
12 1 18
3 7
11 2 19
10 8
9 20
23 21
22
Adic , celula din centrul stupului este numerotat cu 1. Plecând de la aceast celul spre sud
³i apoi în spiral , în sensul acelor de ceasornic, sunt numerotate celelalte celule.
Iniµial zumzi se g se³te în celula din centru (cea numerotat cu 1), ³i dore³te s ajung ,
trecând din celul în celul , la celula cu num rul de ordine X , unde se g se³te prietenul ei. zumzi
se poate deplasa dintr-o celul în oricare dintre celulele vecine, f r a p r si îns stupul.
Dou celule sunt vecine dac au o latur comun .
Unele celule ale stupului sunt ocupate de alte albine ³i de aceea zumzi nu poate s treac prin
ele.
Cerinµ
Problema v cere s determinaµi câte variante are zumzi ca dup exact K pa³i s ajung la
prietenul ei.
Date de intrare
Fi³ierul de intrare zumzi.in conµine pe prima sa linie valorile naturale N , M , K ³i X separate
printr-un spaµiu, având urm toarea semnicaµie:
Urm toarea linie a ³ierului de intrare conµine M numere naturale separate printr-un spaµiu
reprezentând numerele de ordine ale celulelor ocupate din stup.
Date de ie³ire
Fi³ierul text zumzi.out va conµine pe prima sa linie un singur num r natural reprezentând
num rul de variante pe care le are zumzi la dispoziµie de a ajunge la prietenul ei.
Restricµii ³i preciz ri
1&M $ N & 300
X j1
K & 100
zumzi nu are posibilitatea de a p r si stupul, iar în plus odat ajuns la prietenul ei nu îl
va mai p r si.
zumzi nu este o albin foarte inteligent de aceea ea poate trece de mai multe ori printr-o
celul , cu excepµia celulei nale, în care se a prietenul ei, celul în care va intra o singur
dat ³i nu o mai p r se³te.
Exemplu
CAPITOLUL 32. ONI 2006 690
Soluµia comisiei
Pentru memorarea "stupului" vom folosi o matrice p tratic T de ordinul 2 k 1, unde
valoarea lui k este data de relaµia:
3 k 1 k 1 $ n & 3 k k 1 1
adic k reprezint num rul de cercuri concentrice din stup (f r a num ra celula 1 ca un cerc).
i-1, j
N
i,j
SV SE
i+1-(j%2) , j-1 i+1-(j%2) , j+1
S
i+1, j
26 end;
27
28 procedure adun(x,y:nrmare;var z:nrmare);
29 var c,t,i,zero:integer;
30 begin
31 zero:=ord(’0’);
32 while length(x)>length(y) do
33 y:=y+’0’;
34 while length(y)>length(x) do
35 x:=x+’0’;
36 z:=’’;
37 for i:=1 to length(x) do
38 z:=z+’0’;
39 t:=0;
40 for i:=1 to length(x) do
41 begin
42 c:=ord(x[i])+ord(y[i])-2*zero+t;
43 t:=c div 10;
44 c:=c mod 10;
45 z[i]:=chr(c+zero);
46 end;
47 if t>0 then
48 z:=z+chr(t+zero);
49 end;
50
51 procedure compl;
52 var c,i,j,s:integer;
53 begin
54 i:=k+1; j:=k+1; s:=1;
55 t[i,j]:=s; poz[s].x:=i; poz[s].y:=j;
56 s:=s+1;
57 for c:=1 to k do
58 begin
59 i:=i+1;
60 while i<=k+c+1 do
61 begin
62 t[i,j]:=s;
63 poz[s].x:=i; poz[s].y:=j;
64 s:=s+1;
65 if s>n then exit;
66 i:=i+1; j:=j-1;
67 end;
68 i:=i-1;
69 while j>=k-c+1 do
70 begin
71 t[i,j]:=s;
72 poz[s].x:=i; poz[s].y:=j;
73 s:=s+1;
74 if s>n then exit;
75 j:=j-1;
76 end;
77 j:=j+1; i:=i-1;
78 while i>=k+1 do
79 begin
80 t[i,j]:=s;
81 poz[s].x:=i; poz[s].y:=j;
82 s:=s+1;
83 if s>n then exit;
84 i:=i-1;
85 end;
86 j:=j+1;
87 while i>=k-c+1 do
88 begin
89 t[i,j]:=s;
90 poz[s].x:=i; poz[s].y:=j;
91 s:=s+1;
92 if s>n then exit;
93 i:=i-1; j:=j+1;
94 end;
95 i:=i+1;
96 while j<=k+c+1 do
97 begin
98 t[i,j]:=s;
99 poz[s].x:=i; poz[s].y:=j;
100 s:=s+1;
101 if s>n then exit;
CAPITOLUL 32. ONI 2006 693
102 j:=j+1;
103 end;
104 j:=j-1; i:=i+1;
105 while i<=k+1 do
106 begin
107 t[i,j]:=s;
108 poz[s].x:=i; poz[s].y:=j;
109 s:=s+1;
110 if s>n then exit;
111 i:=i+1;
112 end;
113 i:=i-1;
114 end;
115 end;
116
117 procedure scrie(x:nrmare);
118 var i:integer;
119 begin
120 if length(x)=0 then
121 writeln(f,0)
122 else
123 begin
124 for i:=length(x) downto 1 do
125 write(f,x[i]);
126 writeln(f);
127 end;
128 end;
129
130 begin
131 assign(f,fin); reset(f);
132 readln(f,n,m,nrp,y); {n = numarul de celule, m = numarul de celule ocupate
133 nrp = numarul de pasi efectuati de ZUMZI
134 y = pozitia prietenului lui ZUMZI}
135 k:=1; s:=1; s1:=s+k*6;
136 while s1<n do
137 begin
138 s:=s1; k:=k+1;
139 s1:=s+k*6;
140 end;
141 a[0]:=1;
142 {a[i]=1 casuta i este ocupata
143 0 casuta i este libera}
144 for i:=1 to m do begin read(f,j); a[j]:=1; end;
145 close(f);
146 fillchar(p1,sizeof(p1),0);
147 fillchar(p2,sizeof(p2),0);
148
149 compl;
150
151 p1[1]:=’1’;
152 for i:=1 to nrp do
153 begin
154 fillchar(p2,sizeof(p2),0);
155 for j:=1 to n do
156 if not zero(p1[j]) then
157 begin
158 i1:=poz[j].x; j1:=poz[j].y;
159 for m:=1 to 6 do
160 begin
161 t1:=t[i1+di[m],j1+dj[m]];
162 if a[t1]=0 then {poate sari in celula t1}
163 adun(p1[j],p2[t1],p2[t1])
164 end;
165 end;
166 p1:=p2;
167 fillchar(p1[y],sizeof(p1[y]),0);
168 end;
169 assign(f,fout); rewrite(f);
170 scrie(p2[y]);
171 close(f);
172 end.
72 if(k==n) break;
73
74 // nord_est nc pasi
75 for(np=1;np<=nc&&k<n;np++)
76 {
77 ic=i; jc=j;
78 i=ine(ic,jc); j=jne(ic,jc);
79 s[i][j]=++k; is[k]=i; js[k]=j;
80 }
81 if(k==n) break;
82
83 // sud_est nc pasi
84 for(np=1;np<=nc&&k<n;np++)
85 {
86 ic=i; jc=j;
87 i=ise(ic,jc); j=jse(ic,jc);
88 s[i][j]=++k; is[k]=i; js[k]=j;
89 }
90 if(k==n) break;
91
92 // sud nc pasi
93 for(np=1;np<=nc&&k<n;np++)
94 {
95 ic=i; jc=j;
96 i=is(ic,jc); j=js(ic,jc);
97 s[i][j]=++k; is[k]=i; js[k]=j;
98 }
99 }// while
100 }// stupul()
101
102 static void calcul()
103 {
104 int i,k,v; // v=vecin
105 nd[1][0]=1; // zumzi
106 for(k=1;k<=np;k++) // pasul k
107 {
108 for(i=1;i<=n;i++) // celula i
109 {
110 nd[i][k%2]=0; // este suma vecinilor
111
112 if(a[i]==1) continue; // este ocupata
113 if((i==x)&&(k<np)) continue; // nu mai pleaca !
114
115 v=s[in(is[i],js[i])][jn(is[i],js[i])]; // vecin la nord
116 if(a[v]==0) nd[i][k%2]+=nd[v][(k+1)%2]; // celula libera
117
118 v=s[is(is[i],js[i])][js(is[i],js[i])]; // vecin la sud
119 if(a[v]==0) nd[i][k%2]+=nd[v][(k+1)%2]; // celula libera
120
121 v=s[ine(is[i],js[i])][jne(is[i],js[i])]; // vecin la nord_est
122 if(a[v]==0) nd[i][k%2]+=nd[v][(k+1)%2]; // celula libera
123
124 v=s[ise(is[i],js[i])][jse(is[i],js[i])]; // vecin la sud_est
125 if(a[v]==0) nd[i][k%2]+=nd[v][(k+1)%2]; // celula libera
126
127 v=s[inv(is[i],js[i])][jnv(is[i],js[i])]; // vecin la nord_vest
128 if(a[v]==0) nd[i][k%2]+=nd[v][(k+1)%2]; // celula libera
129
130 v=s[isv(is[i],js[i])][jsv(is[i],js[i])]; // vecin la sud_vest
131 if(a[v]==0) nd[i][k%2]+=nd[v][(k+1)%2]; // celula libera
132 }// for i
133 }// for k
134 }// calcul()
135
136 public static void main(String[] args) throws IOException
137 {
138 int i,j;
139 StreamTokenizer st=new StreamTokenizer(
140 new BufferedReader(new FileReader("zumzi.in")));
141 PrintWriter out=new PrintWriter(
142 new BufferedWriter(new FileWriter("zumzi.out")));
143 st.nextToken(); n=(int)st.nval;
144 st.nextToken(); m=(int)st.nval;
145 st.nextToken(); np=(int)st.nval;
146 st.nextToken(); x=(int)st.nval;
147
CAPITOLUL 32. ONI 2006 696
62 }
63 if(k==n) break;
64
65 // nord nc pasi
66 for(np=1;np<=nc&&k<n;np++)
67 {
68 ic=i; jc=j;
69 i=in(ic,jc); j=jn(ic,jc);
70 s[i][j]=++k; is[k]=i; js[k]=j;
71 }
72 if(k==n) break;
73
74 // nord_est nc pasi
75 for(np=1;np<=nc&&k<n;np++)
76 {
77 ic=i; jc=j;
78 i=ine(ic,jc); j=jne(ic,jc);
79 s[i][j]=++k; is[k]=i; js[k]=j;
80 }
81 if(k==n) break;
82
83 // sud_est nc pasi
84 for(np=1;np<=nc&&k<n;np++)
85 {
86 ic=i; jc=j;
87 i=ise(ic,jc); j=jse(ic,jc);
88 s[i][j]=++k; is[k]=i; js[k]=j;
89 }
90 if(k==n) break;
91
92 // sud nc pasi
93 for(np=1;np<=nc&&k<n;np++)
94 {
95 ic=i; jc=j;
96 i=is(ic,jc); j=js(ic,jc);
97 s[i][j]=++k; is[k]=i; js[k]=j;
98 }
99 }// while
100 }// stupul()
101
102 static int[] nrv(int nr)
103 {
104 int[] x;
105 if(nr==0) { x=new int[1]; x[0]=0; }
106 else
107 {
108 int nc, nrrez=nr;
109 nc=0;
110 while(nr!=0) {nc++; nr=nr/10;}
111
112 x=new int[nc];
113 nr=nrrez;
114 nc=0;
115 while(nr!=0) { x[nc]=nr%10; nc++; nr=nr/10;}
116 }
117 return x;
118 }// nrv(...)
119
120 static int[] suma(int[] x, int[] y)
121 {
122 int[] z=new int[(x.length>y.length) ? (x.length+1) : (y.length+1)];
123 int k,t=0;
124 for(k=0;k<=z.length-2;k++)
125 {
126 z[k]=t;
127 if(k<x.length) z[k]+=x[k];
128 if(k<y.length) z[k]+=y[k];
129 t=z[k]/10;
130 z[k]=z[k]%10;
131 }
132 z[z.length-1]=t;
133 if(z[z.length-1]!=0) return z;
134 else
135 {
136 int[] zz=new int[z.length-1];
137 for(k=0;k<zz.length;k++) zz[k]=z[k];
CAPITOLUL 32. ONI 2006 698
ONI 2005
33.1 Bifo
Autor: Silviu G nceanu
Pentru a-³i vindeca rana provocat de Spânul cel Negru, prinµul Algorel are nevoie de
leacul miraculos aat în posesia vr jitoarei din p durea întunecat .
Aceasta i-a promis leacul dac îi rezolv urm toarea problem , la care ea s-a gândit zadarnic o
mie de ani: pornind de la dou cuvinte iniµiale A1 ³i A2 ³i aplicând "formula bifo" An An2 An1
pentru n ' 3, se obµin cuvintele A3 , A4 , A5 , ³.a.m.d.
Prin An2 An1 înµelegem concatenarea cuvintelor An2 ³i An1 în aceast ordine.
Toate aceste cuvinte (A1 , A2 , A3 , ³.a.m.d), sunt la rândul lor concatenate, în ordine, formând
un ³ir de caractere innit denumit ³ir magic.
Formula leacului miraculos are M caractere, pe care vr jitoarea nu le ³tie. Se ³tiu îns cele M
poziµii din ³irul magic în care apar, în ordine, caracterele din formul .
Cerinµ
Cu toat inteligenµa lui, Algorel nu poate rezolva aceast problem . Ajutaµi-l pe prinµ s ias
din încurc tur aând formula leacului magic.
Date de intrare
Primele dou linii ale ³ierului bifo.in conµin ecare câte un ³ir de cel mult 100 de caractere
reprezentând cuvintele A1 (pe prima linie) ³i respectiv A2 (pe a doua linie).
A treia linie conµine un num r întreg M , reprezentând num rul de caractere din formula
leacului miraculos.
Urmeaz M linii descriind, în ordine, poziµiile din ³irul magic unde se g sesc caracterele din
formul .
Date de ie³ire
699
CAPITOLUL 33. ONI 2005 700
Fi³ierul de ie³ire bifo.out va conµine pe prima linie un ³ir de M caractere reprezentând formula
leacului miraculos.
Restricµii ³i preciz ri
a 1 & M & 100;
a A1 ³i A2 conµin doar litere mici ale alfabetului englez;
a Numerotarea poziµiilor din ³irul innit începe cu 1;
a Cele M poziµii vor numere întregi (nu neap rat distincte) de maxim 100
de cifre;
a Pentru 60% din teste poziµiile vor numere întregi între 1 ³i 1.000.000.000;
a Fiecare linie din ³ierul de intrare ³i din ³ierul de ie³ire se termin cu
marcaj de sfâr³it de linie;
Exemplu
bifo.in bifo.out
ab xdb
cdx
3
10
4
15
Explicaµie: Primele 5 ³iruri obµinute folosind "formula bifo" sunt:
ab, cdx, abcdx, cdxabcdx, abcdxcdxabcdx
Concatenând aceste ³iruri se obµine ³irul magic:
abcdxabcdxcdxabcdxabcdxcdxabcdx...
Timp maxim de execuµie/test: 1 sec sub Windows ³i 1 sec sub Linux
60 }
61
62 static void afisare() throws IOException
63 {
64 int i;
65 out=new PrintWriter(new BufferedWriter(new FileWriter("bifo.out")));
66 for(i=1;i<=m;i++) out.print(f[i]);
67 out.println();
68 out.close();
69 }
70 }
61 x=x-sk1;
62
63 while(k>2) // a[k]=a[k-2]a[k-1]
64 {
65 if(lg[k-2]>=x) // caracterul este in a[k-2] stanga
66 {
67 k=k-2;
68 }
69 else // caracterul este in a[k-1] dreapta
70 {
71 x=x-lg[k-2];
72 k--;
73 }
74 }
75 if(k==1) f[i]=a1[x-1];
76 if(k==2) f[i]=a2[x-1];
77 }
78
79 static void afisare() throws IOException
80 {
81 int i;
82 out=new PrintWriter(new BufferedWriter(new FileWriter("bifo.out")));
83 for(i=1;i<=m;i++) out.print(f[i]);
84 out.println();
85 out.close();
86 }
87 }
45 for(j=0;j<p[i].length;j++)
46 p[i][j]=(char)(p[i][j]-0x30); // coduri cifre --> cifre reale
47 }
48 }
49
50 static void rezolvare(int i)
51 {
52 char[] x,sk1,sk,pk;
53 int k;
54 lg[1]=nr2v(a1.length);
55 lg[2]=nr2v(a2.length);
56
57 x=suma(nr2v(0),p[i]); // improvizatie pentru x=p[i]; !!!
58 if(compar(x,lg[1])<=0){f[i]=a1[v2nr(x)-1];return;}
59 if(compar(x,suma(lg[1],lg[2]))<=0){f[i]=a2[v2nr(x)-v2nr(lg[1])-1];return;}
60
61 sk1=suma(nr2v(0),lg[1]);
62 sk=suma(sk1,lg[2]);
63 k=2; // k=cuvantul unde se gaseste caracterul de pe pozitia x
64 while(compar(sk,x)<0)
65 {
66 k++;
67 lg[k]=suma(lg[k-2],lg[k-1]);
68 sk1=suma(nr2v(0),sk);
69 sk=suma(sk1,lg[k]);
70 }
71 x=scade(x,sk1);
72 while(k>2) // a[k]=a[k-2]a[k-1]
73 {
74 if(compar(lg[k-2],x)>=0) // caracterul este in a[k-2] stanga
75 {
76 k=k-2;
77 }
78 else // caracterul este in a[k-1] dreapta
79 {
80 x=scade(x,lg[k-2]);
81 k--;
82 }
83 }
84 if(k==1) f[i]=a1[v2nr(x)-1];
85 if(k==2) f[i]=a2[v2nr(x)-1];
86 }
87
88 static void afisare() throws IOException
89 {
90 int i;
91 out=new PrintWriter(new BufferedWriter(new FileWriter("bifo.out")));
92 for(i=1;i<=m;i++) out.print(f[i]);
93 out.println();
94 out.close();
95 }
96
97 static int compar(char[] a, char[] b) //-1, 0, 1 ... a < = > b
98 {
99 int na=a.length;
100 int nb=b.length;
101 if(na>nb) return 1; else if(na<nb) return -1;
102
103 int i=na-1;
104 while((i>=0)&&(a[i]==b[i])) i--;
105 if(i==-1) return 0;
106 else if(a[i]>b[i]) return 1; else return -1;
107 }
108
109 static char[] scade(char[] x,char[] y) // z=x-y unde x>=y
110 {
111 int nx=x.length;
112 int ny=y.length;
113 int nz=nx;
114 int i,s;
115 char t;
116 char[] z=new char[nz];
117 char[] yy=new char[nz];
118 for(i=0;i<ny;i++) yy[i]=y[i];
119 t=0;
120 for(i=0;i<nz;i++)
CAPITOLUL 33. ONI 2005 705
121 {
122 s=x[i]-yy[i]-t; // poate fi negativ ==> nu merge tipul char !!!
123 if(s<0) {z[i]=(char)(s+10); t=1;} else {z[i]=(char)s; t=0;}
124 }
125 if(z[nz-1]!=0) return z;
126 else
127 {
128 int poz=nz-1; // de exemplu 123-121=002 ==>
129 while((int)z[poz]==0) poz--;// pot fi mai multe zero-uri la inceput
130 char[] zz=new char[poz+1];
131 for(i=0;i<=poz;i++) zz[i]=z[i];
132 return zz;
133 }
134 }
135
136 static char[] suma(char[] x,char[] y)
137 {
138 int nx=x.length;
139 int ny=y.length;
140 int nz;
141 if(nx>ny) nz=nx+1; else nz=ny+1;
142 int t,i;
143 char[] z=new char[nz];
144 char[] xx=new char[nz];
145 char[] yy=new char[nz];
146 for(i=0;i<nx;i++) xx[i]=x[i];
147 for(i=0;i<ny;i++) yy[i]=y[i];
148 t=0;
149 for(i=0;i<nz;i++)
150 {
151 z[i]=(char)(xx[i]+yy[i]+t);
152 t=z[i]/10;
153 z[i]=(char)(z[i]%10);
154 }
155 if(z[nz-1]!=0) return z;
156 else
157 {
158 char[] zz=new char[nz-1];
159 for(i=0;i<nz-1;i++) zz[i]=z[i];
160 return zz;
161 }
162 }
163
164 static char[] nr2v(int nr)
165 {
166 int nrr=nr,nc=0,i;
167 while(nr!=0) { nc++; nr=nr/10; }
168 char[] nrv=new char[nc];
169 nr=nrr;
170 for(i=0;i<nc;i++) { nrv[i]=(char)(nr%10); nr=nr/10; }
171 return nrv;
172 }
173
174 static int v2nr(char[] x)
175 {
176 int nr=0,i;
177 for(i=x.length-1;i>=0;i--) nr=nr*10+x[i];
178 return nr;
179 }
180 }
33.2 Romeo
Autor: prof. Dan Grigoriu
Ora³ul Julietei este de form p trat ³i are str zi doar pe direcµiile Nord-Sud ³i Est-Vest,
toate la distanµe egale ³i numite ca în desen: strada vertical 0, 1, 2, 3, ..., respectiv strada
orizontal 0, 1, 2, 3... . Julieta locuie³te la intersecµia str zilor: vertical x ³i orizontalu a y
(poziµia x, y ).
Romeo se a în colµul de Sud-Vest al ora³ului (poziµia (0,0)) ³i dore³te s ajung la Julieta,
nu ³tim exact de ce, dar este treaba lui. Peste toate necazurile cunoscute ale bietului b iat, mai
apar ³i altele:
ora³ul urc în pant spre Nord, ceea ce îngreuneaz mersul în acea direcµie;
CAPITOLUL 33. ONI 2005 706
nu poate merge decât spre Nord sau spre Est, pentru c dac "ea" l-ar vedea mergând spre
Vest sau spre Sud, atunci ar crede c el se îndep rteaz denitiv de ea.
Numim segment elementar distanµa dintre dou str zi paralele al turate.
Dac Romeo merge spre Est, atunci el consum 1J (J = joule = o unitate de energie) pentru
ecare segment elementar parcurs.
Din cauza pantei, dac merge spre Nord k segmente elementare consecutive, consum 1 2
3 ... k J .
Romeo vrea s ajung la Julieta (mergând în condiµiile de mai sus) cu un consum minim
de energie.
De exemplu, dac datele sunt:
x 4 ³i y 3,
atunci desenul al turat prezint un drum posibil (dar nu cu consum minim de energie).
În desen, avem
a un prim segment elementar orizontal (consum = 1J ), apoi
a spre Nord dou segmente elementare (consum: 1 2 3J )
a urmeaz 3 segmente spre Est (consum: 1 1 1 3J ) ³i
a ultima porµiune de un segment vertical (consum: 1J ).
Total consum energie: 1 3 3 1 8J .
Cerinµ
Scrieµi un program care cite³te x ³i y ³i care a³eaz num rul minim de J consumaµi pentru
tot drumul de la poziµia 0, 0 la poziµia x, y , mergând doar în direcµiile precizate.
Date de intrare
Fi³ierul de intrare romeo.in conµine numerele x ³i y pe prima linie, separate de un spaµiu.
Date de ie³ire
Fi³ierul de ie³ire romeo.out conµine o singur linie cu num rul de J consumaµi pentru distanµa
total parcurs din poziµia de plecare pân în cea nal .
Restricµii ³i preciz ri
a x ³i y sunt numere naturale;
a 0 & x, y & 40000
a Fiecare linie din ³ierul de intrare ³i din ³ierul de ie³ire se încheie cu marcaj de sfâr³it de
linie.
Exemplu
romeo.in romeo.out
32 5
Explicaµie
Datele de intrare indic un ora³ ca în desen.
Un drum posibil (el nu este unic) este dat de linia îngro³at .
Primul segment vertical consum 1J, porµiunea orizontal consum 3J ³i ultimul segment
vertical (cel din dreapta), înc 1J, deci vom a³a num rul 5, care reprezint 1J+3J+1J=5J.
Timp maxim de execuµie/test: 1 sec sub Windows ³i 1 sec sub Linux
6 int x,y;
7 int z,m,n,e;
8 PrintWriter out = new PrintWriter(
9 new BufferedWriter(new FileWriter("romeo.out")));
10 StreamTokenizer st=new StreamTokenizer(
11 new BufferedReader(new FileReader("romeo.in")));
12 st.nextToken(); x=(int)st.nval;
13 st.nextToken(); y=(int)st.nval;
14 if(x>=y-1) e=x+y;
15 else
16 {
17 z=y/(x+1);
18 n=y-(x+1)*z;
19 m=x+1-y+(x+1)*z;
20 e=m*z*(z+1)/2+n*(z+1)*(z+2)/2+x;
21 }
22 out.println(e);
23 out.close();
24 }
25 }
33.3 Seceta
lect. Ovidiu Dom³a
Gr dinile roditoare ale B r ganului sufer anual pierderi imense din cauza secetei. C u-
t torii de ap au g sit n fântâni din care doresc s alimenteze n gr dini. Fie Gi , Fi , i 1, ..., n
puncte în plan reprezentând puncte de alimentare ale gr dinilor ³i respectiv punctele în care se
a fântânile. Pentru ecare punct se dau coordonatele întregi x, y în plan.
Pentru a economisi materiale, leg tura dintre o gr din ³i o fântân se realizeaz printr-o
conduct în linie dreapt . Fiecare fântân alimenteaz o singur gr din . Consiliul Judeµean
Galaµi pl te³te investiµia cu condiµia ca lungimea total a conductelor s e minim .
Fiecare unitate de conduct cost 100 lei noi (RON).
Cerinµ
S se determine m, costul minim total al conductelor ce leag ecare gr din cu exact o fântân .
Date de intrare
Fi³ierul de intrare seceta.in va conµine:
Pe prima linie se a num rul natural n, reprezentând num rul gr dinilor ³i al fântânilor.
a
a Pe urm toarele n linii se a perechi de numere întregi Gx Gy , separate printr-un spaµiu,
reprezentând coordonatele punctelor de alimentare ale gr dinilor.
a Pe urm toarele n linii se a perechi de numere întregi Fx Fy , separate printr-un spaµiu,
reprezentând coordonatele punctelor fântânilor.
Date de ie³ire
Fi³ierul de ie³ire seceta.out va conµine:
m un num r natural reprezentând partea întreag a costului minim total al conductelor.
Restricµii ³i preciz ri
a 1 $ n $ 13
a 0 & Gx, Gy, F x, F y & 200
a Nu exist trei puncte coliniare, indiferent dac sunt gr dini sau fântâni
a Orice linie din ³ierele de intrare ³i ie³ire se termin prin marcajul de sfâr³it de linie.
Exemplu
seceta.in seceta.out Explicaµie
3 624 Costul minim este [6.24264 * 100]=624
1 4 prin legarea perechilor:
3 3 Gradini Fantani
4 7 14 23
2 3 33 31
2 5 47 25
3 1
Timp maxim de execuµie/test: 1 sec sub Windows ³i 0.5 sec sub Linux.
CAPITOLUL 33. ONI 2005 710
30 xg=new int[n+1];
31 yg=new int[n+1];
32 xf=new int[n+1];
33 yf=new int[n+1];
34 a=new int[n+1];
35 d=new double[n+1][n+1];
36
37 for(k=1;k<=n;k++)
38 {
39 st.nextToken(); xg[k]=(int)st.nval;
40 st.nextToken(); yg[k]=(int)st.nval;
41 }
42 for(k=1;k<=n;k++)
43 {
44 st.nextToken(); xf[k]=(int)st.nval;
45 st.nextToken(); yf[k]=(int)st.nval;
46 }
47 }
48
49 static void rezolvare() throws IOException
50 {
51 int i,j;
52 int s;
53 for(i=1;i<=n;i++) // gradina i
54 for(j=1;j<=n;j++) // fantana j
55 {
56 s=(xg[i]-xf[j])*(xg[i]-xf[j])+(yg[i]-yf[j])*(yg[i]-yf[j]);
57 d[i][j]=Math.sqrt(s);
58 }
59 f(1); // generez permutari
60 }
61
62 static void f(int k)
63 {
64 boolean ok;
65 int i,j;
66 for(i=1;i<=n;i++)
67 {
68 ok=true; // k=1 ==> nu am in stanga ... for nu se executa !
69 for(j=1;j<k;j++) if(i==a[j]) {ok=false; break;}
70 if(!ok) continue;
71 for(j=1;j<k;j++)
72 if(seIntersecteaza(xg[k],yg[k],xf[i], yf[i],
73 xg[j],yg[j],xf[a[j]],yf[a[j]]))
74 {
75 ok=false;
76 break;
77 }
78 if(!ok) continue;
79 a[k]=i;
80 if(k<n) f(k+1); else verificCostul();
81 }
82 }
83
84 static void verificCostul()
85 {
86 int i;
87 double s=0;
88 for(i=1;i<=n;i++) s=s+d[i][a[i]];
89 if(s<costMin) costMin=s;
90 }
91
92 // de ce parte a dreptei [(xa,ya);(xb,yb)] se afla (xp,yp)
93 static int s(int xp,int yp,int xa,int ya,int xb,int yb)
94 {
95 double s=(double)yp*(xb-xa)-xp*(yb-ya)+xa*yb-xb*ya;
96 if(s<-0.001) return -1; // in zona "negativa"
97 else if(s>0.001) return 1; // in zona "pozitiva"
98 else return 0; // pe dreapta suport
99 }
100
101 // testeaza daca segmentul[P1,P1] se intersecteaza cu [P3,P4]
102 static boolean seIntersecteaza(int x1, int y1, int x2, int y2,
103 int x3, int y3, int x4, int y4)
104 {
105 double x,y;
CAPITOLUL 33. ONI 2005 712
23
24 static void citire() throws IOException
25 {
26 int k;
27 st=new StreamTokenizer(new BufferedReader(new FileReader("seceta.in")));
28 st.nextToken(); n=(int)st.nval;
29 xg=new int[n+1];
30 yg=new int[n+1];
31 xf=new int[n+1];
32 yf=new int[n+1];
33 a=new int[n+1];
34 d=new double[n+1][n+1];
35
36 for(k=1;k<=n;k++)
37 {
38 st.nextToken(); xg[k]=(int)st.nval;
39 st.nextToken(); yg[k]=(int)st.nval;
40 }
41 for(k=1;k<=n;k++)
42 {
43 st.nextToken(); xf[k]=(int)st.nval;
44 st.nextToken(); yf[k]=(int)st.nval;
45 }
46 }
47
48 static void rezolvare() throws IOException
49 {
50 int i,j;
51 int s;
52 for(i=1;i<=n;i++) // gradina i
53 for(j=1;j<=n;j++) // fantana j
54 {
55 s=(xg[i]-xf[j])*(xg[i]-xf[j])+(yg[i]-yf[j])*(yg[i]-yf[j]);
56 d[i][j]=Math.sqrt(s);
57 }
58 f(1); // generez permutari
59 }
60
61 static void f(int k)
62 {
63 boolean ok;
64 int i,j;
65 for(i=1;i<=n;i++)
66 {
67 ok=true; // k=1 ==> nu am in stanga ... for nu se executa !
68 for(j=1;j<k;j++) if(i==a[j]) {ok=false; break;}
69 if(!ok) continue;
70
71 for(j=1;j<k;j++)
72 if((s(xg[k],yg[k],xg[j],yg[j],xf[a[j]],yf[a[j]])*
73 s(xf[i],yf[i],xg[j],yg[j],xf[a[j]],yf[a[j]])<0)&&
74 (s(xg[j], yg[j], xg[k],yg[k],xf[i],yf[i])*
75 s(xf[a[j]],yf[a[j]],xg[k],yg[k],xf[i],yf[i])<0))
76 {
77 afisv(k-1);// pe pozitia k(gradina) vreau sa pun i(fantana)
78 System.out.print(i+" ");// pe pozitia j(gradina) e pus a[j](fantana)
79 System.out.print(k+""+i+" "+j+""+a[j]);
80 System.out.print(" ("+xg[k]+","+yg[k]+") "+" ("+xf[i]+","+yf[i]+") ");
81 System.out.println(" ("+xg[j]+","+yg[j]+") "+" ("+xf[a[j]]+","+yf[a[j]]+") "
);
82
83 ok=false;
84 break;
85 }
86 if(!ok) continue;
87
88 a[k]=i;
89 if(k<n) f(k+1); else verificCostul();
90 }
91 }
92
93 static void verificCostul()
94 {
95 int i;
96 double s=0;
97 for(i=1;i<=n;i++) s=s+d[i][a[i]];
CAPITOLUL 33. ONI 2005 714
98 if(s<costMin) costMin=s;
99 afisv(n); System.out.println(" "+s+" "+costMin+" "+(++nv));
100 }
101
102 static void afisv(int nn)
103 {
104 int i;
105 for(i=1;i<=nn;i++) System.out.print(a[i]);
106 }
107
108 // de ce parte a dreptei [(xa,ya);(xb,yb)] se afla (xp,yp)
109 static int s(int xp,int yp,int xa,int ya,int xb,int yb)
110 {
111 double s=(double)yp*(xb-xa)-xp*(yb-ya)+xa*yb-xb*ya;
112 if(s<-0.001) return -1; // in zona "negativa"
113 else if(s>0.001) return 1; // in zona "pozitiva"
114 else return 0; // pe dreapta suport
115 }
116
117 static void afisare() throws IOException
118 {
119 int k;
120 out=new PrintWriter(new BufferedWriter(new FileWriter("seceta.out")));
121 out.println((int)(costMin*100));
122 out.close();
123 }
124 }
45 }
46 }
47
48 static void rezolvare() throws IOException
49 {
50 int i,j;
51 int s;
52 for(i=1;i<=n;i++) // gradina i
53 for(j=1;j<=n;j++) // fantana j
54 {
55 s=(xg[i]-xf[j])*(xg[i]-xf[j])+(yg[i]-yf[j])*(yg[i]-yf[j]);
56 d[i][j]=Math.sqrt(s);
57 }
58 f(1); // generez permutari
59 }
60
61 static void f(int k)
62 {
63 boolean ok;
64 int i,j;
65 for(i=1;i<=n;i++)
66 {
67 ok=true; // k=1 ==> nu am in stanga ... for nu se executa !
68 for(j=1;j<k;j++) if(i==a[j]) {ok=false; break;}
69 if(!ok) continue;
70 for(j=1;j<k;j++)
71 if((s(xg[k], yg[k], xg[j],yg[j],xf[a[j]],yf[a[j]])*
72 s(xf[i], yf[i], xg[j],yg[j],xf[a[j]],yf[a[j]])<0)&&
73 (s(xg[j], yg[j], xg[k],yg[k],xf[i], yf[i])*
74 s(xf[a[j]],yf[a[j]],xg[k],yg[k],xf[i], yf[i])<0))
75 {
76 ok=false;
77 break;
78 }
79 if(!ok) continue;
80 a[k]=i;
81 if(k<n) f(k+1); else verificCostul();
82 }
83 }
84
85 static void verificCostul()
86 {
87 int i;
88 double s=0;
89 for(i=1;i<=n;i++) s=s+d[i][a[i]];
90 if(s<costMin) costMin=s;
91 }
92
93 //de ce parte a dreptei [(xa,ya);(xb,yb)] se afla (xp,yp)
94 static int s(int xp,int yp,int xa,int ya,int xb,int yb)
95 {
96 double s=(double)yp*(xb-xa)-xp*(yb-ya)+xa*yb-xb*ya;
97 if(s<-0.001) return -1; // in zona "negativa"
98 else if(s>0.001) return 1; // in zona "pozitiva"
99 else return 0; // pe dreapta suport
100 }
101
102 static void afisare() throws IOException
103 {
104 int k;
105 out=new PrintWriter(new BufferedWriter(new FileWriter("seceta.out")));
106 out.println((int)(costMin*100));
107 out.close();
108 }
109 }
Varianta 4:
83
84 epus[i]=true;
85 if(k<n) f(k+1); else verificCostul();
86 epus[i]=false;
87 }// for i
88 }// f(...)
89
90 static void verificCostul()
91 {
92 int i;
93 double s=0;
94 for(i=1;i<=n;i++) s=s+d[i][a[i]];
95 if(s<costMin) costMin=s;
96 }// verificCostul(...)
97
98 static void afisare() throws IOException
99 {
100 int k;
101 out=new PrintWriter(new BufferedWriter(new FileWriter("seceta.out")));
102 out.println((int)(costMin*100));
103 out.close();
104 }// afisare(...)
105 }// class
33.4 Biblos
Maria ³i Adrian Niµ
Din dorinµa de a realiza un fond de carte cât mai voluminos, ocialit µile ora³ului Ga-
laµi, au modernizat pentru început, o sal pentru depozitarea c rµilor ³i l-au numit pe Biblos
coordonatorul acestei biblioteci.
Achiziµionarea de carte s-a realizat în mai multe etape.
De ecare dat c rµile achiziµionate au fost depozitate pe câte un stativ construit special de
Biblos.
Pentru a avea spaµiu de depozitare Biblos a construit mai multe stative decât i-ar fost
necesare, unele putând r mâne f r c rµi.
Dup mai multe etape de achiziµionare, Biblos a constatat c spaµiul alocat bibliotecii este
prea mic.
Primind un alt spaµiu mai înc p tor, mut primul stativ cu toate c rµile conµinute de acesta
³i se opre³te deoarece î³i dore³te s mute acele stative care nu sunt a³ezate unul lâng cel lalt ³i
care fac ca fondul de carte din noua sal s e cât mai mare posibil.
Cerinµ
Scrieµi un program care, cunoscând num rul stativelor, precum ³i num rul de volume de carte
de pe ecare stativ, determin care este num rul maxim de volume care pot mutate în noua
sal , ³tiind c primul stativ a fost deja mutat iar celelalte se aleg astfel încât s nu e a³ezate unul
lâng cel lalt. Dac exist stative care nu au c rµi acestea nu vor mutate în a doua sal .
Date de intrare
Fi³ierul de intrare biblos.in conµine
a pe prima linie o valoare n, num r natural cu semnicaµia num rul de stative,
a pe a doua linie n numere naturale, x1 , x2 , ..., xn separate prin câte un spaµiu cu semnicaµia
xi = num rul de volume de carte existente pe ecare stativ.
Date de ie³ire
Fi³ierul de ie³ire biblos.out va conµine o singur linie unde se a un num r natural cu
semnicaµia: num rul maxim de volume ce au fost transferate.
Restricµii ³i preciz ri
a 1 & n & 30000
a 0 & xi & 32767, unde i 1, ..., n iar xi reprezint num rul de c rµi de pe stativul i.
a Pentru 70% dintre teste n & 1000
a Fiecare linie din ³ierul de intrare ³i din ³ierul de ie³ire se termin cu marcaj de sfâr³it de
linie.
Exemple
CAPITOLUL 33. ONI 2005 718
biblos.in biblos.out
7 16
1362584
Explicaµie: Suma maxim se obµine din mutarea stativelor 1 (obligatoriu), 3, 5, 7 (nu pot
stative al turate)
biblos.in biblos.out
15 836
3 1 84 9 89 55 135 49 176 238 69 112 28 175 142
Explicaµie: Suma maxim obµinut din mutarea stativelor 1, 3, 5, 7, 10, 12, 14
biblos.in biblos.out
8 32
7 1 4 12 9 9 12 4
Explicaµie: Suma maxim obµinut din mutarea stativelor 1, 3, 5, 7, sau din mutarea stativelor
1, 4, 6, 8.
Timp maxim de execuµie/test: 0.5 sec sub Windows ³i 0.1 sec sub Linux
Pentru toate celelalte valori cmax i, se observ c se poate folosi formula:
Prin alegerea maximului dintre valorile lui cmax, se obµine rezultatul cerut.
Pentru optimizare, se poate face observaµia c dintre valorile lui cmax, intereseaz doar cele
de pe poziµiile i 3 ³i i 2, deci:
dac cmax i 2 % cmax i 3
atunci cmax i cmax i 2 carti i
altfel cmax i cmax i 3 carti i/
Variant cu vectori.
18 smax=new int[n+1];
19
20 for(i=1;i<=n;i++) { st.nextToken(); x[i]=(int)st.nval;}
21
22 smax[1]=x[1];
23 for(i=2;i<=n;i++)
24 {
25 max=0; jmax=0;
26 if(i==2) ji=0; else ji=i-3;
27 for(j=ji;j<=i-2;j++)
28 if(smax[j]>=max) { max=smax[j]; jmax=j; }
29 if(max!=0) smax[i]=max+x[i]; else smax[i]=0;
30 }
31
32 if(smax[n]>smax[n-1]) max=smax[n]; else max=smax[n-1];
33 out.println(max);
34 out.close();
35 }//main
36 }//class
33.5 Joc
Cristina Luca
Pe o tabl p trat de dimensiune n n se deseneaz o secvenµ de triunghiuri dreptunghic
isoscele.
Fiecare triunghi are vârfurile numerotate cu 1, 2 ³i 3 (2 corespunde unghiului drept iar ordinea
1, 2, 3 a vârfurilor este în sens invers acelor de ceasornic - vezi gura). Triunghiurile au catetele
paralele cu marginile tablei.
Primul triunghi, având lungimea catetei Lg , are vârful 1 pe linia L ³i coloana C ³i este orientat
ca în gur .
CAPITOLUL 33. ONI 2005 721
3
a
a a
a a a
1 a a a a 2
Jocul const în alipirea câte unui nou triunghi la unul din vârfurile 2 sau 3 ale triunghiului
curent. Dac se al tur colµului 2, noul triunghi se a³eaz cu vârful 1 în prelungirea laturii 1, 2 a
triunghiului curent, iar dac se al tur colµului 3 se a³eaz cu vârful 1 în prelungirea laturii 2, 3.
Iniµial noul triunghi este orientat ca ³i cel anterior. El se poate plasa pe tabl dac nu sunt
dep ³ite marginile acesteia sau nu se suprapune peste un alt triunghi. În caz contrar, se face o
o
singur rotaµie cu 90 spre stânga, obµinându-se o nou orientare a triunghiului. Dac nici în acest
caz noul triunghi nu poate plasat, jocul se opre³te.
Zona ocupat de primul triunghi se completez cu litera 'a'; zona celui de-al doilea se comple-
tez cu litera 'b', ³.a.m.d. Când literele mici ale alfabetului englez sunt epuizate, se reîncepe de la
'a'.
Cerinµ
Cunoscându-se dimensiunea tablei, poziµia primului triunghi (linie, coloan ) ³i lungimea catetei
precum ³i o secvenµ de triunghiuri care se doresc a alipite se cere s se genereze matricea
rezultat în nalul jocului.
Jocul se termin dac un triunghi nu mai poate alipit sau au fost plasate toate triunghiurile
descrise în secvenµ .
Date de intrare
În ³ierul de intrare joc.in, pe prima linie se a n (dimensiunea tablei). Pe a doua linie
separate prin câte un spaµiu se a : L (linia), C (coloana) ³i Lg (lungimea catetei) corespunz toare
primului triunghi. Urm toarele linii, pân la sfâr³itul ³ierului, conµin câte dou numere naturale
separate prin câte un singur spaµiu reprezentând colµul triunghiului curent la care va alipit
triunghiul urm tor ³i dimensiunea catetei triunghiului urm or.
Date de ie³ire
În ³ierul de ie³ire joc.out va a³at matricea rezultat . Celulele tablei care nu sunt com-
pletate cu litere ale alfabetului vor completate cu '.'.
Restricµii ³i preciz ri
a 1 & n & 100; 1 & C , L & n; 2 & Lg & n
a Fiecare linie din ³ierul de intrare ³i din c serul de iec sre se termin cu marcaj de sfâr³it
de linie.
Exemplu
joc.in joc.out
20 . . . . . . . . . . . . . . . . . . . .
16 8 4 . . . . . . . . . . . . . . . . . . . .
35 . . . . . . . . . . f f f f f e e e . .
23 . . . . . . . . . . f f f f . . e e . .
34 . . . . . . . . . . f f f . . . . e . .
23 . . . . . . . . . . f f . . d d d d . .
35 . . . . . . . . . . f . . . . d d d . .
33 . . . . . . h h g g g . . . b . d d . .
22 . . . . . . h . g g . . . b b . . d . .
34 j j j i i i i . g . . . b b b . . c . .
23 j j . i i i . . . . . b b b b . c c . .
33 j . . i i . . . . . b b b b b c c c . .
32 k . . i . . . . . . a . . . . . . . . .
33 k k . . . . . . . a a . . . . . . . . .
33 k k k l . . . . a a a . . . . . . . . .
24 . . . l l m . a a a a . . . . . . . . .
. . . . . m m . . . . . . . . . . . . .
. . . . . m m m n . . . . . . . . . . .
. . . . . . . . n n . . . . . . . . . .
. . . . . . . . n n n . . . . . . . . .
Explicaµii
CAPITOLUL 33. ONI 2005 722
Timp maxim de execuµie/test: 0.2 sec în Windows ³i 0.2 sec sub Linux
61 l1=l1-d1; d1=d;
62 dir=(dir+1)%4;
63 umple2(l1,c1,d1);
64 }
65 else ok=false;
66 break;
67 case 2: if(esteGol2(l1,c1-d1,d)) // direct
68 {
69 c1=c1-d1; d1=d; umple2(l1,c1,d1);
70 }
71 else if(esteGol3(l1,c1-d1,d)) // rotit
72 {
73 c1=c1-d1;d1=d;
74 dir=(dir+1)%4;
75 umple3(l1,c1,d1);
76 }
77 else ok=false;
78 break;
79 case 3: if(esteGol3(l1+d1,c1,d)) // direct
80 {
81 l1=l1+d1;d1=d; umple3(l1,c1,d1);
82 }
83 else if(esteGol0(l1+d1,c1,d)) // rotit
84 {
85 l1=l1+d1; d1=d;
86 dir=(dir+1)%4;
87 umple0(l1,c1,d1);
88 }
89 else ok=false;
90 break;
91 default: System.out.println("Ciudat!!!");
92 }
93
94 if(v==3)
95 switch(dir)
96 {
97 case 0: if(esteGol0(l1-d1,c1+d1-1,d)) // direct
98 {
99 c1=c1+d1-1; l1=l1-d1; d1=d; umple0(l1,c1,d1);
100 }
101 else if(esteGol1(l1-d1,c1+d1-1,d)) // rotit
102 {
103 l1=l1-d1; c1=c1+d1-1; d1=d;
104 dir=(dir+1)%4;
105 umple1(l1,c1,d1);
106 }
107 else ok=false;
108 break;
109 case 1: if(esteGol1(l1-d1+1,c1-d1,d)) // direct
110 {
111 l1=l1-d1+1; c1=c1-d1; d1=d; umple1(l1,c1,d1);
112 }
113 else if(esteGol2(l1-d1+1,c1-d1,d)) // rotit
114 {
115 l1=l1-d1+1; c1=c1-d1; d1=d;
116 dir=(dir+1)%4;
117 umple2(l1,c1,d1);
118 }
119 else ok=false;
120 break;
121 case 2: if(esteGol2(l1+d1,c1-d1+1,d)) // direct
122 {
123 c1=c1-d1+1; l1=l1+d1; d1=d; umple2(l1,c1,d1);
124 }
125 else if(esteGol3(l1+d1,c1-d1+1,d)) // rotit
126 {
127 c1=c1-d1+1; l1=l1+d1; d1=d;
128 dir=(dir+1)%4;
129 umple3(l1,c1,d1);
130 }
131 else ok=false;
132 break;
133 case 3: if(esteGol3(l1+d1-1,c1+d1,d)) // direct
134 {
135 l1=l1+d1-1;c1=c1+d1; d1=d; umple3(l1,c1,d1);
136 }
CAPITOLUL 33. ONI 2005 725
213 i=lin+k;
214 for(j=col-d+1;j<=col-k;j++) a[i][j]=val;
215 }
216 }
217
218 static boolean esteGol2(int lin, int col, int d)
219 {
220 int i,j,k;
221 if((lin<1)||(lin+d-1>n)||(col-d+1<1)||(col>n)) return false;
222 boolean gol=true;
223 for(k=0;k<d;k++)
224 {
225 i=lin+k;
226 for(j=col-d+1;j<=col-k;j++) if(a[i][j]!=-1){ gol=false;break;}
227 }
228 return gol;
229 }
230
231 static void umple3(int lin, int col, int d) // 12=sj==>dir=3
232 {
233 int i,j,k;
234 for(k=0;k<d;k++)
235 {
236 i=lin+k;
237 for(j=col;j<=col+k;j++) a[i][j]=val;
238 }
239 }
240
241 static boolean esteGol3(int lin, int col, int d)
242 {
243 int i,j,k;
244 if((lin<1)||(lin+d-1>n)||(col<1)||(col+d-1>n)) return false;
245 boolean gol=true;
246 for(k=0;k<d;k++)
247 {
248 i=lin+k;
249 for(j=col;j<=col+k;j++) if(a[i][j]!=-1) {gol=false; break;}
250 }
251 return gol;
252 }
253 }
33.6 Pal
Autor: Silviu G nceanu
Prinµul Algorel este în încurc tur din nou: a fost prins de Spânul cel Negru în încercarea
sa de a o salva pe prinµes ³i acum este închis în Turnul cel Mare.
Algorel poate evada dac g se³te combinaµia magic cu care poate deschide poarta turnului.
Prinµul ³tie cum se formeaz aceast combinaµie magic : trebuie s utilizeze toate cifrele scrise
pe u³a turnului pentru a obµine dou numere palindroame, astfel încât suma lor s e minim , iar
aceast sum este combinaµia magic ce va deschide u³a.
Primul num r palindrom trebuie s aib cel puµin L cifre, iar cel de-al doilea poate avea orice
lungime diferit de 0. Numerele palindroame formate nu pot începe cu cifra 0. Acum interveniµi
dumneavoastr în poveste, ind prietenul s u cel mai priceput în algoritmi.
Prin noul super-telefon al s u, prinµul transmite num rul de apariµii a ec rei cifre de pe u³a
turnului precum ³i lungimea minim L a primului num r, iar dumneavoastr trebuie s -i trimiteµi
cât mai repede numerele cu care poate obµine combinaµia magic .
Cerinµ
Având datele necesare, aaµi dou numere palindroame cu care se poate obµine combinaµia
magic .
Date de intrare
Prima linie a ³ierului pal.in conµine un num r întreg L reprezentând lungimea minim a
primului num r. Urmeaz 10 linii: pe linia i 2 se va aa un num r întreg reprezentând num rul
de apariµii ale cifrei i, pentru i cu valori de la 0 la 9.
Date de ie³ire
CAPITOLUL 33. ONI 2005 727
Prima linie a ³ierului de ie³ire pal.out conµine primul num r palidrom, iar cea de-a doua
linie conµine cel de-al doilea num r palindrom. Dac exist mai multe soluµii se va scrie doar una
dintre ele.
Restricµii ³i preciz ri
a În total vor cel mult 100 de cifre
a 1 & L $ 100 ³i L va mai mic decât num rul total de cifre
a Pentru datele de test va exista întotdeauna soluµie: se vor putea forma din cifrele scrise pe
u³a turnului dou numere care încep cu o cifr diferit de 0, iar primul num r s aib cel puµin L
cifre
a Un num r este palindrom dac el coincide cu r sturnatul s u. De exemplu 12321 ³i 7007
sunt numere palindroame, în timp ce 109 ³i 35672 nu sunt.
a Pentru 30% dintre teste, num rul total de cifre va cel mult 7; pentru alte 40% din teste
num rul total de cifre va cel mult 18, iar pentru restul de 30% din teste num rul total de cifre
va mai mare sau egal cu 30.
a Fiecare linie din ³ierul de intrare ³i din ³ierul de ie³ire se termin cu marcaj de sfâr³it de
linie.
Exemplu
pal.in pal.out Explicaµie
5 10001 Pentru acest exemplu avem L 5,
3 222 3 cifre de 0, 2 cifre de 1³i 3 cifre de 2.
2 Cifrele de la 3 la 9 lipsesc
3 de pe u³a turnului.
0
0 Cele dou palindroame cu care
0 se genereaz combinaµia magic
0 sunt 10001 ³i 222.
0 Combinaµia magic va suma acestora
0 ³i anume 10223 (care este suma minim
0 pe care o putem obµine).
Timp maxim de execuµie/test: 1 sec sub Windows ³i 1 sec sub Linux
147 {
148 z[k]=t;
149 if(k<x.length) z[k]+=x[k];
150 if(k<y.length) z[k]+=y[k];
151 t=z[k]/10;
152 z[k]=z[k]%10;
153 }
154 z[z.length-1]=t;
155 if(z[z.length-1]!=0) return z;
156 else
157 {
158 int[] zz=new int[z.length-1];
159 for(k=0;k<zz.length;k++) zz[k]=z[k];
160 return zz;
161 }
162 }
163 }//class
Capitolul 34
ONI 2004
34.1 Coduri
Un detectiv particular are de rezolvat un caz special.
Este vorba de o deturnare de fonduri. Pentru a putea rezolva cazul trebuie s g seasc un ³ir
cu n coduri distincte. Fiecare cod este un num r natural scris în baza 10.
Din p cate lucrurile nu sunt simple, pentru c din cercet rile efectuate a obµinut dou infor-
maµii. Prima informaµie este legat de faptul c suma p tratelor codurilor este un cub perfect,
iar a doua spune c suma cuburilor codurilor este un p trat perfect.
Cerinµ
Ajutaµi detectivul s g sesc un ³ir de coduri x1 , x2 , ..., xn , care veric condiµiile din enunµ ³i
xi & n14 , pentru orice i cu 1 & i & n.
Date de intrare
Fi³ierul de intrare coduri.in conµine pe prima linie num rul natural n.
Date de ie³ire
Fi³ierul de ie³ire coduri.out va conµine n linii, câte una pentru ecare cod din ³ir, în ordine
cresc toare.
Restricµii
a 1 & n & 20
Exemplu
coduri.in coduri.out
2 625
1250
Timp maxim de execuµie: 1 sec/test
k s ,1&k & n.
4
Fie s n n 1 2n 1©6. Se pot considera codurile xk
731
CAPITOLUL 34. ONI 2004 732
2 2 2 n n 1 2n 1 3 3 3 n n 1 2
1 2 ... n ³i 1 2 ... n
6 2
3 3 3 3 n n 1 2
x1 x2 ... xn α
2
2
³i pentru a obµine un p trat perfect vom considera α β , deci codurile vor considerate sub
2
forma xk β k .
Acum suma cuburilor
3 3 3 6 n n 1 2
x1 x2 ... xn β
2
este un p trat perfect.
Suma p tratelor codurilor este
2 2 2 4n n 1 2n 1 3 n n 1 2n 1
x1 x2 ... xn β β β
6 6
³i pentru a obµine un cub perfect putem considera
n n 1 2n 1 2
β .
6
n n 1 2n 1 4
xk k .
6
24 for i:=1 to dt do
25 y[i]:=t[i];
26 dy:=dx;
27 end
28 else
29 if dy>dx then
30 begin
31 for i:=1 to dy-dx do
32 t[i]:=0;
33 dt:=dy-dx;
34 for i:=1 to dx do
35 begin
36 inc(dt);
37 t[dt]:=x[i];
38 end;
39 for i:=1 to dt do
40 x[i]:=t[i];
41 dx:=dy;
42 end;
43 dt:=0;
44 mi:=0;
45 for i:=dx downto 1 do
46 begin
47 inc(dt);
48 tr:=x[i]+y[i]+mi;
49 t[dt]:=tr mod 10;
50 mi:=tr div 10;
51 end;
52 if mi>0 then
53 begin
54 inc(dt);
55 t[dt]:=mi;
56 end;
57 for i:=1 to dt do
58 z[i]:=t[dt+1-i];
59 dz:=dt;
60 end;{suma}
61
62 procedure produs(x:ve;dx:byte;y:ve;dy:byte;var z:ve;var dz:byte);
63 var i,j,k,dt,du:byte;t,u:ve;
64 begin
65 dz:=1;z[1]:=0;
66 for i:=1 to dy do
67 begin
68 t[1]:=0;dt:=1;
69 for j:=1 to y[dy-i+1] do
70 begin
71 suma(x,dx,t,dt,u,du);
72 dt:=du;
73 for k:=1 to du do t[k]:=u[k];
74 end;
75 for j:=1 to i-1 do
76 begin
77 inc(dt);
78 t[dt]:=0;
79 end;
80 suma(z,dz,t,dt,u,du);
81 dz:=du;
82 for j:=1 to du do z[j]:=u[j];
83 end;
84 end;{produs}
85
86 begin
87 assign(f,’coduri.in’);
88 reset(f);
89 readln(f,n);
90 close(f);
91 m:=n*(n+1)*(2*n+1) div 6;
92 str(m,sm);
93 ds:=length(sm);
94 for i:=1 to ds do
95 val(sm[i],s[i],er);
96 produs(s,ds,s,ds,x,dx);
97 s:=x;ds:=dx;
98 produs(s,ds,s,ds,x,dx);
99 s:=x;ds:=dx;
CAPITOLUL 34. ONI 2004 734
100
101 assign(f,’coduri.out’);
102 rewrite(f);
103 for i:=1 to n do
104 begin
105 str(i,si);
106 di:=length(si);
107 for j:=1 to di do
108 val(si[j],ii[j],er);
109 produs(ii,di,s,ds,x,dx);
110 for j:=1 to dx do
111 write(f,x[j]);
112 writeln(f);
113 end;
114 close(f);
115 end.
34.2 Logic
CAPITOLUL 34. ONI 2004 735
Exemplu:
logic.in logic.out
p¶q $ % p& q 4
A 1
Timp execuµie: 1 sec/test.
Informaµia "în formul nu apar mai mult de 10 litere mici ale alfabetului latin" ne conduce
10
la ideea de a genera toate conguraµiile (sunt cel mult 2 1024) ³i a calcula valoarea de
adev r a formulei pentru ecare conguraµie. Se folose³te recursivitatea µinând cont de priorit µile
operatorilor.
48
49 int sau(void)
50 {
51 int value = si(), v;
52
53 while (e[pos] == ’|’)
54 {
55 pos++;
56 v = sau();
57 value = value || v;
58 }
59 return value;
60 }
61
62 int implicatie(void)
63 {
64 int value = sau(), v;
65
66 while (e[pos] == ’=’)
67 {
68 pos += 2;
69 v = implicatie();
70 value = (!value) || v;
71 }
72 return value;
73 }
74
75 int echivalenta(void)
76 {
77 int value = implicatie(), v;
78
79 while (e[pos] == ’<’)
80 {
81 pos += 3;
82 v = echivalenta();
83 value = value == v;
84 }
85 return value;
86 }
87
88 int main(void)
89 {
90 FILE *fi, *fo;
91 int len, result;
92 int i, j;
93 int a[256];
94
95 memset(e, 0, sizeof(e));
96 fi = fopen("logic.in", "r");
97 fscanf(fi, "%s", e);
98 len = strlen(e);
99 fclose(fi);
100
101 memset(a, 0, sizeof(a));
102 for (i = 0; i < len; i++) a[(int)e[i]]++;
103 nv = 0;
104 for (i = ’a’; i <= ’z’; i++)
105 if (a[i]) c[nv++] = i;
106
107 result = 0;
108 for (i = 0; i < (1 << nv); i++)
109 {
110 for (j = 0; j < nv; j++)
111 t[(int)c[j]] = i & (1 << j) ? 1 : 0;
112 pos = 0;
113 result += echivalenta();
114 }
115
116 fo = fopen("logic.out", "w");
117 fprintf(fo, "%d\n", result);
118 fclose(fo);
119
120 return 0;
121 }
CAPITOLUL 34. ONI 2004 738
37 boolean val;
38 val=echivalenta();
39 if(poz<n) System.out.println("<-- formula "+poz+" "+e[poz]);
40 else System.out.println("<-- formula "+poz);
41 return val;
42 }
43
44 static boolean echivalenta()
45 {
46 System.out.println(" --> echivalenta "+poz+" "+e[poz]);
47 boolean a,b,val;
48 a=implicatie();
49 val=a;
50 if((poz<n)&&(e[poz]==’<’)) {poz+=3; b=formula(); val=(a==b);}
51 if(poz<n) System.out.println("<-- echivalenta "+poz+" "+e[poz]);
52 else System.out.println("<-- echivalenta "+poz);
53 return val;
54 }
55
56 static boolean implicatie()
57 {
58 System.out.println(" --> implicatie "+poz+" "+e[poz]);
59 boolean a, b, val;
60 a=sau();
61 val=a;
62 if((poz<n)&&(e[poz]==’=’)) {poz+=2; b=implicatie(); val=(!a)||b;}
63 if(poz<n) System.out.println("<-- implicatie "+poz+" "+e[poz]);
64 else System.out.println("<-- implicatie "+poz);
65 return val;
66 }
67
68 static boolean sau()
69 {
70 System.out.println(" --> sau "+poz+" "+e[poz]);
71 boolean a, b, val;
72 a=si();
73 val=a;
74 if((poz<n)&&(e[poz]==’|’)) {poz++; b=sau(); val=(a||b);}
75 if(poz<n) System.out.println("<-- sau "+poz+" "+e[poz]);
76 else System.out.println("<-- sau "+poz);
77 return val;
78 }
79
80 static boolean si()
81 {
82 System.out.println(" --> si "+poz+" "+e[poz]);
83 boolean a, b, val;
84 a=not();
85 val=a;
86 if((poz<n)&&(e[poz]==’&’)) {poz++; b=si(); val=(a&&b);}
87 if(poz<n) System.out.println("<-- si "+poz+" "+e[poz]);
88 else System.out.println("<-- si "+poz);
89 return val;
90 }
91
92 static boolean not()
93 {
94 boolean val;
95 System.out.println(" --> not "+poz+" "+e[poz]);
96 if(e[poz]==’~’) {poz++; val=!not();}
97 else val=paranteza();
98 if(poz<n) System.out.println("<-- not "+poz+" "+e[poz]);
99 else System.out.println("<-- not "+poz);
100 return val;
101 }
102
103 static boolean paranteza()
104 {
105 System.out.println(" --> paranteza "+poz+" "+e[poz]);
106 boolean val;
107 if(e[poz]==’(’) {poz++;val=formula(); poz++;}
108 else if(e[poz] == ’)’) val=false;
109 else val=variabila();
110 if(poz<n) System.out.println("<-- paranteza "+poz+" "+e[poz]);
111 else System.out.println("<-- paranteza "+poz);
112 return val;
CAPITOLUL 34. ONI 2004 740
113 }
114
115 static boolean variabila()
116 {
117 System.out.println(" --> variabila "+poz+" "+e[poz]);
118 boolean val;
119 if((poz<n)&&(e[poz]>=’a’)&&(e[poz]<=’z’)) val=v[(int)e[poz++]];
120 else val=formula();
121 if(poz<n) System.out.println("<-- variabila "+poz+" "+e[poz]);
122 else System.out.println("<-- variabila "+poz);
123 return val;
124 }
125 }//class
60 boolean a, b, val;
61 a=si();
62 val=a;
63 if((poz<n)&&(e[poz]==’|’)) {poz++; b=sau(); val=(a||b);}
64 return val;
65 }
66
67 static boolean si()
68 {
69 boolean a, b, val;
70 a=not();
71 val=a;
72 if((poz<n)&&(e[poz]==’&’)) {poz++; b=si(); val=(a&&b);}
73 return val;
74 }
75
76 static boolean not()
77 {
78 boolean val;
79 if(e[poz]==’~’) {poz++; val=!not();}
80 else val=paranteza();
81 return val;
82 }
83
84 static boolean paranteza()
85 {
86 boolean val;
87 if(e[poz]==’(’) {poz++;val=formula(); poz++;}
88 else if(e[poz] == ’)’) val=false;
89 else val=variabila();
90 return val;
91 }
92
93 static boolean variabila()
94 {
95 boolean val;
96 if((poz<n)&&(e[poz]>=’a’)&&(e[poz]<=’z’)) val=v[(int)e[poz++]];
97 else val=formula();
98 return val;
99 }
100 }//class
34.3 Poligon
Se d un caroiaj de M N în care sunt plasate K puncte. Fiecare punct poate legat de
vecinul s u direct pe maxim opt direcµii (N , N E , E , SE , S , SV , V , N V ).
Cerinµ
Determinaµi patrulaterele având vârfurile în punctele date iar laturile formate din leg turi între
dou sau mai multe puncte coliniare.
Date de intrare
Fi³ierul de intrare poligon.in conµine
a pe prima linie trei numere naturale nenule, separate prin câte un spaµiu,
M N K
reprezentând dimensiunile M , N ale caroiajului ³i K num rul de puncte, iar
a pe urm toarele K linii câte trei numere naturale separate printr-un spaµiu,
Ii Ji Vi
reprezentând coordonatele punctului i, 1 & i & K respectiv direcµiile
spre care este legat de vecini direcµi.
Codicarea direcµiilor se face printr-un num r cuprins între 0 ³i 255.
Reprezentarea binar a acestuia pe 8 cifre reprezint , începând de la stânga
spre dreapta, leg tur pe direcµiile (1 - legatur , 0 - nu ):
N N E E SE S SV V N V .
De exemplu: 1 0 0 0 0 1 1 0 = 134 deci leg turi spre N , SV , V
CAPITOLUL 34. ONI 2004 742
Date de ie³ire
Fi³ierul de ie³ire poligon.out conµine numai num rul natural
npol
reprezentând num rul patrulaterelor.
Restricµii
1 $ M, N & 100
4 & K & 50
Exemplu
POLIGON.IN POLIGON.OUT
449 6
1 1 24
2 1 184
2 2 43
2 3 22
3 1 136
3 2 213
345
4 1 192
4 3 65
Se genereaz toate combin rile de câte 4 puncte ³i se veric dac acestea pot porma un
patrulater (tinând cont de direcµii).
12 x,e:sir;
13 a:mat;
14 f:text;
15 time:longint absolute $000:$046C;
16 timeinit:longint;
17
18 Procedure citire(var a:mat;var m,n,l:integer);
19 var i,j,k,v:byte;
20 f:text;
21 begin
22 assign(f,’poligon.in’);
23 reset(f);
24 readln(f,m,n,l);
25 for k:=1 to l do
26 begin
27 readln(f,i,j,v);
28 a[i,j]:=v;
29 e[k]:=(i-1)*m+j;
30 end;
31 close(f);
32 end;
33
34 Function traseu(vi,vf,i1,c1,i2:byte;c2:integer;c:byte):boolean;
35 var aux,i:byte;
36 begin
37 if vi>vf then begin aux:=vi;vi:=vf;vf:=aux end;
38 traseu:=true;
39 for i:=vi to vf-1 do
40 if a[i1+c1*i,i2+c2*i] and d[c] <> d[c] then
41 traseu:=false
42 end;
43
44 Function verif(var x:sir; p:integer):boolean;
45 var i,j,l1,c1,l2,c2,t,nc,nl,ndp,nds:byte;
46 begin
47 if p=1 then verif:=true
48 else
49 begin
50
51 verif:=true;
52 nc:=0;nl:=0;ndp:=0;nds:=0;
53 l1:=(e[x[p]]-1) div n +1;
54 c1:=(e[x[p]]-1) mod n +1;
55 for i:=1 to p-1 do
56 begin
57 l2:=(e[x[i]]-1) div n +1;
58 c2:=(e[x[i]]-1) mod n +1;
59 if (c1=c2) then inc(nc);
60 if (l1=l2) then inc(nl);
61 if l1-l2=c1-c2 then inc(ndp);
62 if l1-l2=c2-c1 then inc(nds);
63 end;
64 if (nc>1) or (nl>1) or (ndp>1) or (nds>1) then verif:=false;
65 end;
66 end;
67
68 Function este(y:vecini):boolean;
69 var i,l1,c1,l2,c2,min,max:byte;
70 cod:boolean;
71 begin
72 este:=true;
73 for i:=1 to k do
74 begin
75 cod:=false;
76 l1:=(e[x[y[i+1]]]-1) div n +1;
77 c1:=(e[x[y[i+1]]]-1) mod n +1;
78 l2:=(e[x[y[i]]]-1) div n +1;
79 c2:=(e[x[y[i]]]-1) mod n +1;
80 min:=trunc(((l1+l2)-abs(l1-l2))/2);
81 if (c1=c2) and traseu(l1,l2,0,1,c1,0,5) then cod:=true;
82 if (l1=l2) and traseu(c1,c2,l1,0,0,1,3) then cod:=true;
83 if (l1-l2=c1-c2) and
84 traseu(0,abs(c1-c2),min,1,trunc(((c1+c2)-abs(c1-c2))/2),1,4)
85 then cod:=true;
86 if (l1-l2=c2-c1)
87 and traseu(0,abs(c1-c2),min,1,trunc(((c1+c2)+abs(c1-c2))/2),-1,6)
CAPITOLUL 34. ONI 2004 744
88 then cod:=true;
89 if not cod then este:=false;
90 end;
91 end;
92
93 Procedure Poligon(x:sir;n:integer);
94 var i:byte;
95 begin
96 if este(x1) or este(x2) or este(x3) then
97 begin
98 inc(nr);
99 {for i:=1 to n do
100 write(f,e[x[i]],’,’);
101 writeln(f);}
102 end;
103 end;
104
105 procedure comb (p:integer);
106 var i:integer;
107 begin
108 for i:=x[p-1]+1 to l do
109 begin
110 x[p]:=i;
111 if verif(x,p) then
112 if p=k then
113 Poligon(x,k)
114 else
115 comb(p+1);
116 end;
117 end;
118
119 begin
120 {writeln(’Incepem’);
121 timeinit:=time;
122 writeln(time);}
123 nr:=0;
124 assign(f,’poligon.out’);
125 rewrite(f);
126 k:=4;
127 citire(a,m,n,l);
128 comb(1);
129 writeln(f,nr);
130 close(f);
131 {writeln(time,’/’,(timeinit-time)/18:4:2); }
132 end.
23 y=new int[k+1];
24 d=new int[k+1];
25
26 for(i=1;i<=k;i++)
27 {
28 st.nextToken(); y[i]=(int)st.nval; // linia
29 st.nextToken(); x[i]=(int)st.nval; // coloana
30 st.nextToken(); d[i]=(int)st.nval; // directia
31 }
32
33 ymax=y[1];
34 for(i=2;i<=k;i++) if(y[i]>ymax) ymax=y[i];
35 for(i=1;i<=k;i++) y[i]=ymax-y[i]+1; // sa fie "normal"!
36
37 for(i=1;i<=k;i++) ePunctIn[y[i]][x[i]]=i;
38
39 generezCombinariPePozitia(1);
40
41 out.println(nsol);
42 out.close();
43 t2=System.nanoTime();
44 System.out.println("Timp = "+((double)(t2-t1))/1000000000);
45 }
46
47 static void generezCombinariPePozitia(int j)
48 {
49 int i;
50 for(i=a[j-1]+1;i<=k-4+j;i++)
51 {
52 a[j]=i;
53 if(j<4) generezCombinariPePozitia(j+1);
54 else if(ePoligonOK()) nsol++;
55 }
56 }
57
58 static boolean ePoligonOK()
59 {
60 if(coliniare3Puncte()) return false;
61 if(ePoligon(a[1],a[2],a[3],a[4])) return true;
62 if(ePoligon(a[1],a[2],a[4],a[3])) return true;
63 if(ePoligon(a[1],a[3],a[2],a[4])) return true;
64 if(ePoligon(a[1],a[3],a[4],a[2])) return true;
65 if(ePoligon(a[1],a[4],a[2],a[3])) return true;
66 if(ePoligon(a[1],a[4],a[3],a[2])) return true;
67 return false;
68 }
69
70 static boolean coliniare3Puncte()
71 {
72 if(coliniare(a[1],a[2],a[3])) return true;
73 if(coliniare(a[1],a[2],a[4])) return true;
74 if(coliniare(a[1],a[3],a[4])) return true;
75 if(coliniare(a[2],a[3],a[4])) return true;
76 return false;
77 }
78
79 static boolean coliniare(int p1, int p2, int p3)
80 {
81 int s;
82 s=x[p1]*y[p2]+x[p2]*y[p3]+x[p3]*y[p1];
83 s=s-y[p1]*x[p2]-y[p2]*x[p3]-y[p3]*x[p1];
84 if(s==0) return true; else return false;
85 }
86
87 static boolean ePoligon(int p1, int p2, int p3, int p4)
88 {
89 if(!eLinie(p1,p2)) return false;
90 if(!eLinie(p2,p3)) return false;
91 if(!eLinie(p3,p4)) return false;
92 if(!eLinie(p4,p1)) return false;
93 if(eNedegenerat(p1,p2,p3,p4)) return true; else return false;
94 }
95
96 static boolean eLinie(int p1, int p2) // trece prin coordonate intregi!
97 {
98 if(Math.abs(x[p1]-x[p2])==Math.abs(y[p1]-y[p2])) return eLinieOkOblica(p1,p2);
CAPITOLUL 34. ONI 2004 746
34.4 ablon
Gigel ³i Vasilic imagineaz un mod de a transmite mesaje pe care nimeni s nu le poat
descifra. Mesajul este ascuns într-un text care are N linii ³i pe ecare linie sunt exact N caractere
- litere mari ale alfabetului englez, cifre, semne de punctuaµie ³i caracterul spaµiu.
Decodicarea se face cu ajutorul unui ³ablon, de acelea³i dimensiuni ca ³i textul, care are
câteva g uri.
Suprapunând ³ablonul peste text r mân vizibile câteva caractere.
Acestea se citesc în ordinea liniilor, de sus în jos, iar pe aceea³i linie de la stânga la dreapta.
o
Apoi hârtia cu textul se rote³te spre stânga, în sens trigonometric, cu 90 , ³ablonul r mânând
x. Alte caractere devin vizibile ³i acestea se citesc în acela³i mod.
o o
Operaµia se repet de înc dou ori (rotire cu 180 , respectiv cu 270 ), pân când textul
o
ajunge, printr-o nou rotaµie cu 90 , din nou în poziµia iniµial .
Din p cate, ³ablonul pentru codicare/decodicare s-a pierdut. În schimb a r mas la Gigel
mesajul iniµial iar la Vasilic a ajuns textul care conµine mesajul.
Cerinµ
S se reconstituie ³ablonul care a fost folosit la codicare.
Date de intrare
Fi³ierul de intrare sablon.in conµine
a pe prima linie, mesajul iniµial
a pe linia a doua a ³ierului de intrare se g se³te valoarea N
a urm toarele N linii conµin textul care ascunde mesajul.
Date de ie³ire
Fi³ierul de ie³ire sablon.out conµine N linii a câte N caractere. Caracterele sunt 'O' (pentru
reprezentarea unei g uri) ³i 'X'.
Restricµii ³i
a prin rotirea textului nici una din g uri nu se va suprapune peste nici una
din poziµiile ocupate de o gaur în poziµiile precedente ale textului
a 1 & N & 50
a mesajul are maxim 1000 caractere ³i se încheie cu un caracter diferit de
spaµiu
a în cazul în care exist mai multe soluµii, a³aµi una dintre ele
Exemplu
sablon.in sablon.out
CODIFICARE CU SABLON XXXXOXXXXX
10 XXOXXXXXXX
ABCDCEFAGH OXXXXXXXXX
IJOKLEMNOP XXXOXXXXXX
DQRSTUVWCX XOXXXXXXXX
YZAIBCRDEF XXXXXXXXXX
GFHIJKLMNI XXXXXXXXXX
AJKLMNOPSQ XXXXXXXXXX
RSTOUV WXY XXXXXXXXXX
ZBABCDEFGU XXXXXXXXXX
HIJKNLMCNO
PQLRS TUVW
Timp de execuµie: 1 sec/test
Soluµia ocial
Problema se rezolv relativ simplu µinând cont de urm toarele observaµii:
1. Deoarece întregul mesaj a fost codicat prin 4 rotiri ale textului, este clar c la o poziµionare a
textului sub ³ablon pot citite Lung M esaj ©4 caractere, deci întregul mesaj are 4N umarGauri
caractere
CAPITOLUL 34. ONI 2004 748
10 {
11 int i,j;
12 out=new PrintWriter(new BufferedWriter(new FileWriter("sablon.out")));
13 BufferedReader br=new BufferedReader(new FileReader("sablon.in"));
14 StreamTokenizer st=new StreamTokenizer(br);
15
16 mesaj=br.readLine(); System.out.println(mesaj);
17 st.nextToken(); n=(int)st.nval; System.out.println(n);
18 text=new char[n][n];
19 br.readLine(); // citeste CR LF adica 0D 0A adica 13 10
20 for(i=0;i<n;i++) text[i]=br.readLine().toCharArray();
21 for(i=0;i<n;i++)
22 {
23 for(j=0;j<n;j++) System.out.print(text[i][j]);
24 System.out.println();
25 }
26 out.close();
27 }
28 }
54 gaura[i][j]=true;
55 k++;
56 if(k>=nrGauri) return;
57 }
58 }
59
60 static void afisare() throws IOException
61 {
62 int i,j;
63 out=new PrintWriter(new BufferedWriter(new FileWriter("sablon.out")));
64 for(i=0;i<n;i++)
65 {
66 for(j=0;j<n;j++)
67 if(gaura[i][j]) out.print(’O’); else out.print(’X’);
68 out.println();
69 }
70 out.close();
71 }
72 }
34.5 ir
Gigel se distreaz construind ³iruri cresc toare de numere din mulµimea r1, 2, ..., nx. La un
moment dat observ c unele ³iruri, de cel puµin k termeni (k ' 3), au o proprietate mai aparte:
diferenµa dintre doi termeni consecutivi este constant . Iat câteva exemple de astfel de ³iruri
pentru n ' 21:
2,3,4
1,5,9,13
7,10,13,16,19,21
Cerinµ
Dându-se num rul natural n ajutaµi-l pe Gigel s numere câte astfel de ³iruri poate s con-
struiasc .
Date de intrare
În ³ierul de intrare sir.in se g se³te, pe prima linie, num rul n.
Date de ie³ire
În ³ierul de ie³ire sir.out se va a³a, pe prima linie, num rul cerut urmat de caracterul sfâr³it
de linie.
Restricµii:
a 3 & n & 20000
a 3&k&n
Exemple:
sir.in sir.out
3 1
4 3
5 7
Timp execuµie: 1 sec/test
Soluµia ocial
Notând cu r diferenta dintre doi tereni consecutivi constat m c pentru r 1 se pot construi
urmatoarele submulµimi, ³iruri cu proprietea cerut , de lungime 3:
Cele de lungime superioar se construiesc ad ugând elemente pe cele deja obµinute. Num rul
n2
lor va i 1 i. <
CAPITOLUL 34. ONI 2004 752
Cele de lungime superioar se construiesc ad ugând elemente pe acestea. Numarul lor este o
sum te tipul precedent.
Se continu astfel pân la r n©2, valoarea maxim a lui r.
34.6 Snipers
Se spune c în timpul r zboiului cu gnomii, trolii au trimis n tr g ori de elit s lichideze cele
n c petenii inamice.
Din fericire c peteniile inamice erau plasate în câmp deschis, iar tr g torii au reu³it s se
plaseze în zon f r s e observaµi.
Când s e dat comanda de tragere s-a constatat c nu se transmisese ec rui tr g tor ce
c petenie s împu³te, iar dac doi tr g tori ar tras în aceea³i c petenie sau traiectoriile razelor
uciga³e s-ar intersectat, atunci ar sc pat cel puµin o c petenie care ar putut duce r zboiul
pân la cap t, iar trolii ar fost învin³i.
Deoarece c peteniile aveau capacitatea de a deveni invizibile oricând doreau (pe o perioad
nelimitat ), trebuiau lichidate simultan, altfel ...
Istoria ne spune c trolii au învins deoarece comandantul lor a reu³i ca în mai puµin de o
secund s transmit ec rui tr g tor în ce c petenie s trag .
Voi puteµi face asta?
Cerinµ
Scrieµi un program care, citind poziµiile tr g torilor ³i a c peteniilor, determin c petenia în
care trebuie s trag ecare tr g tor.
Date de intrare
Fi³ierul de intrare snipers.in conµine
a pe prima sa linie num rul n
a pe urm toarele n linii se a perechi de numere întregi, separate prin spaµiu, ce reprezint
coordonatele tr g torilor urmate de
a alte n perechi de numere întregi ce reprezint coordonatele c peteniilor (abscis ³i ordonat ).
Date de ie³ire
Fi³ierul de ie³ire snipers.out conµine n linii.
Pe linia i a ³ierului se a num rul c peteniei µintite de tr g torul i
(i 1...n).
Restricµii ³i preciz ri
a 0 $ n $ 200
a Coordonatele sunt numere întregi din intervalul [0, 50000]
a Raza uciga³ a oric rei arme se opre³te în µinta sa.
a În datele de intrare nu vor exista trei persoane aate în puncte coliniare.
Exemple
snipers.in snipers.out snipers.in snipers.out
2 1 5 2
1 3 2 6 6 5
1 1 4 12 1
3 4 2 8 3
3 1 9 4 4
5 2
6 11
9 7
3 9
1 4
7 3
Timp de execuµie: 1 sec/test
Soluµia ocial
La început ec rui tragator i îi asociem capetenia i, dup care vom lua în considerare toate
perechile tr g tor-c petenie ³i vom elimina încruci³ rile razelor, la câte dou perechi prin in-
terschimbarea µintelor tr g torilor.
CAPITOLUL 34. ONI 2004 754
Se vor face interschimb ri între câte dou perechi tr g tor-µint pâna când nu vor mai exista
intersecµii.
Se observ c la eliminarea unei intersecµii suma distanµelor dintre tr g tori ³i µinte scade, ceea
ce asigur nitudinea algoritmului.
47
48 procedure rezolva;
49 var i,j,aux:word; e_int,ok:boolean;
50 begin
51 for i:=1 to n do t[i].k:=i;
52
53 {tragatorul i trage in capetenia i, pentru inceput}
54 if n>1 then
55 repeat
56 ok:=true;{am gasit o combinatie valida tragator-capetenie}
57 i:=1;
58
59 repeat
60 j:=i;
61
62 repeat
63 j:=j+1;
64 {verifica daca traiectoria de la sniper i la tinta
65 sa nu se intersecteaza
66 cu traiectoria de la sniper j la tinta sa }
67 e_int:=inter(t[i],c[t[i].k],t[j],c[t[j].k]);
68 {daca da le interschimbam tintele,
69 si notam ca nu avem o combinatie buna}
70 if e_int then
71 begin
72 aux:=t[i].k;
73 t[i].k:=t[j].k;
74 t[j].k:=aux;
75 ok:=false;
76 end;
77 until (j=n)or e_int;
78
79 if not e_int then inc(i);
80 {daca nu jeneaza pe numeni trecem al urmatorul sniper}
81
82 until i=n;{pana terminam lista de tragatori}
83
84 until ok;
85 end;
86
87 BEGIN
88 citire;
89 rezolva;
90 scrie;
91 END.
23 yt=new int[n+1];
24 xc=new int[n+1];
25 yc=new int[n+1];
26 t=new int[n+1]; // tragator --> capetenie
27
28 for(k=1;k<=n;k++)
29 {
30 st.nextToken(); xt[k]=(int)st.nval;
31 st.nextToken(); yt[k]=(int)st.nval;
32 }
33 for(k=1;k<=n;k++)
34 {
35 st.nextToken(); xc[k]=(int)st.nval;
36 st.nextToken(); yc[k]=(int)st.nval;
37 }
38 }
39
40 static void rezolvare() throws IOException
41 {
42 int i,j,aux;
43 boolean seIntersecteaza_ij,ok;
44 for(i=1;i<=n;i++) t[i]=i; // tragatorul i trage in capetenia i
45 if(n==1) return;
46 do
47 {
48 ok=true; // am gasit o combinatie valida tragator-capetenie
49 i=1;
50 do
51 {
52 j=i;
53 do
54 {
55 j=j+1;
56 seIntersecteaza_ij=seIntersecteaza(xt[i],yt[i],xc[t[i]],yc[t[i]],
57 xt[j],yt[j],xc[t[j]],yc[t[j]]);
58 if(seIntersecteaza_ij)
59 {
60 aux=t[i];t[i]=t[j];t[j]=aux; // interschimbam tintele
61 ok=false; // nu avem combinatie buna
62 }
63 } while ((j!=n) && !seIntersecteaza_ij);
64 if(!seIntersecteaza_ij) i++; // trecem la urmatorul sniper
65 } while(i!=n); // pana terminam lista de tragatori
66 } while(!ok);
67 }
68
69 //de ce parte a dreptei [(xa,ya);(xb,yb)] se afla (xp,yp)
70 static int s(int xp,int yp,int xa,int ya,int xb,int yb)
71 {
72 double s=(double)yp*(xb-xa)-xp*(yb-ya)+xa*yb-xb*ya;
73 if(s<-0.001) return -1;
74 else if(s>0.001) return 1;
75 else return 0;
76 }
77
78 // testeaza daca segmentul[a1,b1] se intersecteaza cu [a2,b2]
79 static boolean seIntersecteaza(int xa1,int ya1,int xb1,int yb1,
80 int xa2,int ya2,int xb2,int yb2)
81 {
82 // a2 si b2 se afla de o parte si de alta a lui [a1,b1] si
83 // a1 si b1 se afla de o parte si de alta a lui [a2,b2]
84 return (s(xa2,ya2,xa1,ya1,xb1,yb1)*s(xb2,yb2,xa1,ya1,xb1,yb1)<0) &&
85 (s(xa1,ya1,xa2,ya2,xb2,yb2)*s(xb1,yb1,xa2,ya2,xb2,yb2)<0);
86 }
87
88 static void afisare() throws IOException
89 {
90 int k;
91 out=new PrintWriter(new BufferedWriter(new FileWriter("snipers.out")));
92 for(k=1;k<=n;k++) out.println(t[k]);
93 out.close();
94 }
95 }
Capitolul 35
ONI 2003
35.1 Seti
Cercet torii ce lucreaz la programul SETI au recepµionat dou transmisii de date foarte
ciudate, date care ar putea veni din partea unor civilizaµii extraterestre. Primul set de date
este format din 10 caractere distincte, date în ordinea lor lexicograc , ce formeaz alfabetul
extraterestru. A doua transmisie conµine cuvinte din exact 4 caractere.
Cerinµ
Cercet torii trebuie s ordoneze lexicograc cuvintele primite în a doua transmisie (conform
alfabetului extraterestru).
Date de intrare
Fi³ierul de intrare seti.in conµine pe prima linie cele 10 caractere ale alfabetului, iar pe ecare
din urm toarele linii câte un cuvânt.
Date de ie³ire
Fi³ierul de ie³ire seti.out va conµine cuvintele ordonate, câte unul pe linie.
Restricµii ³i preciz ri
a În ³ier nu sunt mai mult de 200.000 de cuvinte, iar caracterele sunt literele mici ale alfabe-
tului englez.
a Datele de intrare se presupun ca ind corecte.
Exemplu
seti.in seti.out
abcdefghij aaaa
aaaa aabc
fgaa fgaa
aabc iihf
iihf
Timp de execuµie: 1 sec/test
757
CAPITOLUL 35. ONI 2003 758
75 }
76 }//class
Versiune nala!
35.2 Scaune
Se consider ns scaune numerotate de la 1 la ns, aranjate în cerc.
Exemplu pentru ns 20 a³ezarea scaunelor este dat în gur .
20 19 18 17 16 15 14 13 12 11
1 2 3 4 5 6 7 8 9 10
Pe ecare din aceste scaune este a³ezat un copil. Primul copil st pe scaunul 1, iar ultimul
pe scaunul ns. Pe lâng cele ns scaune deja ocupate, alµi nc copii (1 & nc & ns) a³teapt s se
elibereze un loc.
La un moment dat un singur copil se ridic de pe scaun ³i pleac . Atunci, cât timp în dreptul
scaunului liber nu exist un copil, toµi copiii aaµi în a³teptare se mi³c în sens invers mi³c rii
acelor ceasornicului, câte o poziµie, pân când unul din ei ocup locul liber.
Condiµii:
la început toate scaunele sunt ocupate;
ecare copil aat în a³teptare se a iniµial în dreptul unui scaun ocupat;
când un copil avanseaz cu n poziµii spre un loc pe scaun, toµi cei care a³teapt avanseaz
tot cu n poziµii. Deoarece mi³carea este circular , avansarea cu 4 poziµii de la poziµia 18, semnic
o deplasare în dreptul poziµiei 2;
Cerinµ
Dac se d o secvenµ a numerelor de ordine a copiilor care pleac la ecare moment, s se
scrie un program care s a³eze num rul scaunului pe care s-a a³ezat ecare copil care a³teapt ,
dac acest lucru este posibil.
Date de intrare
a Pe prima linie a ³ierului text de intrare scaune.in se a dou numere, separate prin spaµiu,
reprezentând num rul de scaune, ns ³i respectiv num rul copiilor care stau în a³teptare nc.
a Pe urm toarele nc linii vor date poziµiile copiilor aaµi în a³teptare.
a În continuare pân la sfâr³itul ³ierului sunt linii ce descriu numerele de ordine ale copiilor
care se ridic unul câte unul de pe scaune ³i p r sesc jocul.
Date de ie³ire
Fi³ierul de ie³ire scaune.out conµine nc linii, ecare linie conµinând poziµia iniµial de a³tep-
tare a copilului ³i poziia ocupat , separate printr-un spaµiu.
Liniile de ie³ire trebuie s e în aceea³i ordine ca cele din ³ierul de intrare.
În cazul în care un copil nu are nici o posibilitate s se a³eze, în dreptul s u se va scrie 0 în
³ierul de ie³ire.
Restricµii
a 1 & ns & 200
a nc & ns
Exemplu
scaune.in scaune.out
20 5 6 16
6 19 3
19 17 0
17 13 20
13 11
1
1
3
20
16
Timp maxim de execuµie: 1 secund /test
CAPITOLUL 35. ONI 2003 762
27 void init()
28 { int i;
29 for(i=0;i<MaxPoz;i++)
30 PozIn[i]=PozLoc[i]=Loc[i]=0;
31 }
32
33 void prelucrare()
34 { int n, poza, locp, liber, nrmut, ns;
35 int gasitloc, faraloc;
36 int i, ok;
37 fin = fopen(InputFile,"r");
38 fout= fopen(OutputFile, "w");
39 fscanf(fin,"%d %d",&ns, &n);
40 for(i=1;i<=n;i++)
41 { fscanf(fin,"%d",&poza);
42 PozLoc[poza]=i;
43 PozIn[i]=poza;
44 }
45 faraloc=0;
46 while(!feof(fin)&&!faraloc)
47 { fscanf(fin,"%d",&liber);
48 if(!feof(fin))
49 {
50 gasitloc=0;
51 i=liber;
52 while(i>=1&&!gasitloc)
53 { if(PozLoc[i]) { locp=PozLoc[i];
54 nrmut=liber-i;
55 gasitloc=1;
56 }
57 else i--;
58 }
59 if(!gasitloc) { i=ns;
60 while((i>=liber+1)&&!gasitloc)
61 { if(PozLoc[i]) { locp=PozLoc[i];
62 nrmut=ns-i+liber;
63 gasitloc=1;
64 }
65 else i--;
66 }
67 }
68 if(!gasitloc) faraloc=1;
69 else { Loc[locp]=liber;
70 PozLoc[i]=0;
71 for(i=1;i<=ns;i++)
72 if(i+nrmut<=ns) Muta[i+nrmut]=PozLoc[i];
73 else Muta[i+nrmut-ns]=PozLoc[i];
74 for(i=1;i<=ns;i++)
75 PozLoc[i]=Muta[i];
76 }
77 }
78 }
79
80 ok=1;
81 for(i=1;i<=n;i++)
82 if(Loc[i]) { fprintf(fout,"%d %d \n",PozIn[i],Loc[i]); ok=0; }
83 else { fprintf(fout,"%d %d\n",PozIn[i],0); ok=0; }
84 if(ok&&faraloc) fprintf(fout,"%d",0);
85 fclose(fin);
86 fclose(fout);
87 }
88
89 int main()
90 { init();
91 prelucrare();
92 return 0;
93 }
1 import java.io.*;
2 class Scaune1
3 {
4 static int ns, nc;
5 static int[] pozInitiala;
6 static int[] pozFinala;
7 static boolean[] asezat;
8
9 public static void main(String[]args) throws IOException
10 {
11 int i,j,k,nca=0; // nca=nr copii asezati
12 long t1,t2;
13 t1=System.currentTimeMillis();
14 PrintWriter out = new PrintWriter(
15 new BufferedWriter(new FileWriter("scaune.out")));
16 StreamTokenizer st=new StreamTokenizer(
17 new BufferedReader(new FileReader("scaune.in")));
18 st.nextToken(); ns=(int)st.nval;
19 st.nextToken(); nc=(int)st.nval;
20 asezat=new boolean[nc+1];
21 pozInitiala=new int[nc+1];
22 pozFinala=new int[nc+1];
23
24 for(k=1;k<=nc;k++)
25 {
26 st.nextToken();
27 pozInitiala[k]=pozFinala[k]=(int)st.nval;
28 }
29 while(st.nextToken()!=st.TT_EOF)
30 {
31 k=(int)st.nval; // scaunul k este liber
32 i=esteLaPozitia(k);
33 while((nca<nc)&&(i==0)) { misca(); i=esteLaPozitia(k); }
34 pozFinala[i]=k;
35 asezat[i]=true;
36 nca++;
37 }
38
39 for(j=1;j<=nc;j++)
40 if(asezat[j]) out.println(pozInitiala[j]+" "+pozFinala[j]);
41 else out.println(pozInitiala[j]+" "+0);
42 out.close();
43 t2=System.currentTimeMillis();
44 System.out.println("Timp = "+(t2-t1));
45 }//main
46
47 static void misca()
48 {
49 int i;
50 for(i=1;i<=nc;i++)
51 if(!asezat[i])
52 {
53 pozFinala[i]++;
54 if(pozFinala[i]==ns+1) pozFinala[i]=1;
55 }
56 }
57
58 static int esteLaPozitia(int k)
59 {
60 int i,copil=0;
61 for(i=1;i<=nc;i++)
62 if(!asezat[i]&&(pozFinala[i]==k)) { copil=i; break; }
63 return copil;
64 }
65 }//class
Pentru a doua varianta se calculeaz distanµele pân la scaunul liber pentru ecare copil r mas
nea³ezat.
Listing 35.2.3: scaune2.java
1 import java.io.*;
2 class Scaune2
3 {
4 static int ns, nc;
CAPITOLUL 35. ONI 2003 765
35.3 Circular
Unele numere naturale sunt formate doar din cifre distincte nenule.
Dintre acestea, unele, numite numere circulare, au urm toarea proprietate: pornind de la
prima cifr ³i num rând spre dreapta, dup cifr , atâtea cifre cât indic aceasta, se determin o
nou cifr . Procedând la fel ³i pentru aceasta ³i pentru toate cele care urmeaz se va ajunge din
CAPITOLUL 35. ONI 2003 766
De exemplu num rul
1894256
este num r circular deoarece:
a are numai cifre distincte
a nu conµine cifra 0
a pornind de la 1 obµinem, pe rând: 8, 9, 2, 6, 5, 4, 1
Cerinµ
Scrieµi un program care, pentru un N dat, determin câte numere circulare sunt mai mici sau
egale cu N, precum ³i cel mai mare num r circular mai mic sau egal cu N.
Date de intrare
Pe prima linie a ³ierului de intrare circular.in se a num rul natural N.
Date de ie³ire
Fi³ierul de ie³ire circular.out conµine o singur linie, pe care se a num rul de numere
circulare mai mici ca N precum ³i num rul circular maxim cerut, separate printr-un spaµiu.
Dac nu exist nici un num r circular mai mic ca N, în ³ierul de ie³ire se vor a³a dou valori
0 separate printr-un spaµiu.
Restricµii
10 & N $ 10.000.000
Exemplu
circular.in circular.out Semnicaµie
1894250 347 1849625 Exist 347 numere circulare mai mici dacât
1894250 cel mai mare dintre acestea ind
num rul 1849625
Timp de execuµie: 1 sec/test
La ecare pas din backtracking se folosesc cifrele cuprinse între 1 ³i 9, care nu au fost folosite
anterior; dac avansarea spre dreapta duce într-o poziµie deja completat ³i mai sunt poziµii libere,
num rul în construcµie nu poate circular ³i se revine la cifra precedent .
Analiza complexit µii
Pentru aceast problem , complexitatea rezolv rii este dat de num rul M de numere circulare,
deci soluµia ruleaz instantaneu, deci ordinul de complexitate al acesteia ar O log2 M , în cazul
în care se folose³te o c utare binar .
Deoarece M este o constant , ordinul de complexitate al soluµiei este O 1.
Complexitatea metodei de generare a numerelor circulare depinde de metoda folosit .
53 {
54 nn=N;
55 nc=0;
56 while (nn) //determin numarul de cifre
57 {
58 nc++;
59 nn/=10;
60 }
61 nn=N;
62 for (i=nc; i>=1; i--) //pun cifrele in vector corect
63 { //Obs. daca un numar este circular
64 c[i]=nn%10; // nu rezulta ca inversul este
65 nn/=10; // si el circular
66 }
67 if (CIRC())
68 {
69 // circular=1;
70 fprintf(g, "%ld\n", N);
71 }
72 // N++;
73 }
74 }
75 fclose(g);
76 return 0;
77 }
48 if (!gata) //
49 {
50 contor++;
51 NCircM=y;
52 }
53 else
54 if (y<=N)
55 {
56 contor++;
57 NCircM=y;
58 }
59
60 }
61 }
62
63 void back(int k)
64 {
65 int i;
66 if (k==n+1)
67 prelucreaza();
68 else
69 for (i=1; i<=9; i++)
70 if (!uz[i])
71 {
72 uz[i]=1;
73 x[k]=i;
74 back(k+1);
75 uz[i]=0;
76 }
77 }
78
79 int main(void)
80 {
81 f=fopen("circular.in", "rt");
82 g=fopen("circular.out", "wt");
83 fscanf(f, "%U", &N); fclose(f);
84 nn=N;
85 nc=0;
86 while (nn) //determin numarul de cifre
87 {
88 nc++;
89 nn/=10;
90 }
91
92 nn=N;
93 for (i=nc; i>=1; i--) //pun cifrele in vector corect
94 { //Obs. daca un numar este circular
95 c[i]=nn%10; // nu rezulta ca inversul este
96 nn/=10; // si el circular
97 }
98 nc1=nc;
99 c1=c[1]; gata=0;
100 contor=0;
101 for (n=2; n<nc1; n++) back(1);
102 gata=1;
103 for (cifra=1; cifra<=c1; cifra++)
104 {
105 x[1]=cifra;
106 uz[cifra]=1;
107 back(2);
108 uz[cifra]=0;
109 }
110
111 fprintf(g, "%ld %ld\n", contor, NCircM);
112 fclose(g);
113
114 return 0;
115 }
23
24 for(nc=2;nc<=ncn;nc++) f(0);
25
26 out.println(nnc+" "+ncmax);
27 out.close();
28 t2=System.currentTimeMillis();
29 System.out.println("Timp = "+(t2-t1));
30 }
31
32 static void f(int k)
33 {
34 boolean ok;
35 int i,j;
36 for(i=1;i<=9;i++) // pun valoarea i pe pozitia k in vectorul a
37 {
38 ok=true;
39 if(k>0)
40 for(j=0;j<k;j++) if(i==x[j]) {ok=false; break;}
41
42 if(!ok) continue;
43 x[k]=i;
44 if(k<nc-1) f(k+1); else afisv();
45 }
46 }
47
48 static void afisv()
49 {
50 if(!esteCircular(x)) return;
51 if(numar(x)>n) return;
52 nnc++;
53 ncmax=numar(x);
54 //System.out.print(nnc+" : ");
55 //for(int i=0; i<=nc-1; i++) System.out.print(x[i]);
56 //System.out.println();
57 }
58
59 static int numar(int[] x)
60 {
61 int nx=x[0];
62 for(int i=1;i<=nc-1;i++) nx=nx*10+x[i];
63 return nx;
64 }
65
66 static boolean esteCircular(int[] x)
67 {
68 int i,j;
69 for(i=0;i<nc;i++) a[i]=aa[i]=x[i];
70
71 j=0;
72 for(i=1;i<=nc;i++)
73 if(aa[j]==0) return false; else { aa[j]=0; j=(j+a[j])%nc; }
74 if(j==0) return true; else return false;
75 }
76 }
35.4 Criptare
Mircea ³i Vasilic vor s -³i trimit mesaje pe care alµii s nu le înµeleag . Au citit ei despre
spioni ³i modalit µi de a scrie mesaje ³i, în nal, au imaginat un mod de criptare a unui mesaj
care folose³te "cuvânt cheie" (le-a pl cut lor denumirea asta :-) ).
Alegându-³i un cuvânt cheie format numai din litere distincte, ei num r literele acestuia ³i
împart mesajul în grupe de lungime egal cu num rul de litere ale cuvântului cheie, ³i le a³eaz
una sub alta. Desigur, se poate întâmpla ca ultima grup s e incomplet , a³a c o completeaz
cu spaµii.
Apoi numeroteaz literele cuvântului cheie în ordinea apariµiei lor în alfabetul englez.
În nal, rescriu mesajul astfel: coloana de sub litera numerotat cu 1, urmat de coloana de
sub litera numerotat cu 2, etc. înlocuind totodat ³i spaµiile cu caracterul '*' (asterisc).
Exemplu:
CAPITOLUL 35. ONI 2003 773
codicare:
2 6 3 5 7 1 4
I n c e r c a
m * s a * l u
c r a m * c u
* c o d u r i
* s i * c r i
p t a r i . *
mesaj criptat: clcrr.Imc**pcsaoiaauuii*eamd*rn*rcstr**uci
clcrr. Imc**p csaoia auuii* eamd*r n*rcst r**uci
col1 col2 col3 col4 col5 col6 col7
Cerinµ
Fiind date un cuvânt cheie ³i un mesaj criptat, decodicaµi mesajul trimis de Mircea pentru
Vasilic .
Date de intrare
Fi³ierul de intrare criptare.in conµine pe prima linie mesajul criptat iar pe linia a doua
cuvântul cheie.
Date de ie³ire
Fi³ierul de intrare criptare.out conµine pe prima linie mesajul decriptat.
Restricµii
a lungimea mesajului este de minim 20 ³i maxim 1000 caractere
a cuvântul cheie are minim 5 ³i maxim 20 de caractere
a cuvântul cheie conµine numai litere mici ale alfabetului
Exemplu
criptare.in
clcrr.Imc**pcsaoiaauuii*eamd*rn*rcstr**uci
criptam
criptare.out
Incercam sa lucram cu coduri si criptari.
Timp maxim de execuµie: 1 secund /test
Deoarece lungimea L a cuvântului cheie este mic , operaµiile cu acesta (determinarea ordinii
literelor) pot neglijate la calculul complexit µii.
Scrierea cuvântului în matrice are ordinul de complexitate O N .
În nal, ordinul de complexitate al algoritmului de rezolvare a acestei probleme este O N
O N O N .
58
59 int main()
60 {
61 citire();
62 decriptare();
63 return 0;
64 }
35.5 Ma³ina
O µar are 3 & N & 30000 ora³e, numerotate de la 1 la N , dispuse pe un cerc.
PAM tocmai ³i-a luat carnet de conducere ³i vrea s viziteze toate ora³ele µ rii. Lui PAM îi
este fric s conduc prin locuri aglomerate a³a c ea ³i-a propus s mearg numai pe ³oselele
unde tracul este mai redus.
Exist ³osele de leg tur între oricare dou ora³e al turate: între ora³ul 1 ³i ora³ul 2, ... , între
ora³ul i ³i ora³ul i 1, iar ora³ul N este legat de ora³ulul 1.
Ca s nu se r t ceasc , PAM ³i-a propus s -³i aleag un ora³ de început ³i s mearg pe ³oselele
respective în sens trigonometric pân ajunge înapoi în ora³ul de unde a plecat. Dac PAM pleac
din ora³ul K , atunci traseul ei va : K, K 1, ..., N, 1, 2, ..., K .
Ma³ina lui PAM are un rezervor foarte mare (în care poate pune oricât de mult benzin ). În
ecare ora³, PAM ia toat cantitatea de benzin existent în ora³, iar parcurgerea ec rei ³osele
necesit o anumit cantitate de benzin .
Cerinµ
tiind c PAM are, la începutul c l toriei, doar benzina existent în ora³ul de plecare, ³i c ,
atunci când ajunge într-un ora³, ea va lua toat cantitatea de benzin disponibil în acel ora³, s
se g seasc un ora³ din care PAM î³i poate începe excursia astfel încât s nu r mân f r benzin .
Se consider c PAM a r mas f r benzin dac în momentul plec rii dintr-un ora³, nu are
sucient benzin pentru a parcurge ³oseaua care duce la ora³ul urm tor. Dac benzina îi ajunge
la x (adic la plecare are tot atâta benzin cât îi trebuie) se consider c PAM poate ajunge
pân în ora³ul urm tor.
CAPITOLUL 35. ONI 2003 777
Date de intrare
Fi³ierul de intrare masina.in conµine
a pe prima linie num rul N ,
a pe cea de-a doua linie se g sesc N numere naturale a1, a2, ..., aN , separate prin câte
un spaµiu, unde ai reprezint cantitatea de benzin disponibil în ora³ul i.
a linia a treia conµine un ³ir de N numere naturale b1, b2, ..., bN , separate prin câte un
spaµiu, unde bi reprezint cantitatea de benzin necesar str baterii ³oselei dintre ora³ele i ³i
i 1 (sau N ³i 1, dac i N ).
Date de ie³ire
Fi³ierul de ie³ire masina.out va conµine un singur num r s care reprezint un ora³ din care,
dac PAM î³i începe c l toria, poate completa turul µ rii f r a face pana prostului.
Restricµii ³i preciz ri
a Dac exist mai multe soluµii, se cere una singur .
a 0 & ai & 30000
a 1 & bi & 30000
Exemplu
masina.in masina.out
6 4
0 3 2 5 10 5
783214
Timp maxim de execuµie: 0.3 sec/test
35.6 Operaµii
k
Not m cu c ³i r câtul ³i respectiv restul împ rµirii unui numar nr la 2 , unde k este un num r
natural nenul.
Asupra num rului putem efectua succesiv urm toarele operaµii:
k
a O1 nr, k reprezint transformarea num rului nr în num rul 2 2c 1 r pentru orice rest
r, sau
c r doar dac r $ 2k 1.
k1
a O2 nr, k reprezint transformarea num rului nr în num rul 2
Cerinµ
Se dau m ³i n dou numere naturale nenule.
Efectuaµi asupra numerelor m ³i n operaµii succesive, O1 sau O2, pentru valori alese ale lui k ,
astfel încât dup un num r nit de operaµii cele dou numere s devin egale, iar valoarea astfel
obµinut s e minim .
Date de intrare
Fi³ierul de intrare operatii.out conµine pe o linie m n dou numere naturale nenule, separate
printr-un spaµiu, reprezentând cele dou numere date.
Date de ie³ire
CAPITOLUL 35. ONI 2003 779
Restricµii
1 $ m, n & 2.000.000.000
Exemplu
OPERATII.IN OPERATII.OUT
11 45 15
2
23
12
2
22
24
Timp maxim de execuµie: 1 sec/test
ONI 2002
36.1 Pentagon
lect. univ. Ovidiu Dom³a, Alba Iulia
În urma bombardamentelor din 11 septembrie 2001, cl direa Pentagonului a suferit daune
la unul din pereµii cl dirii. Imaginea codicat a peretelui avariat se reprezint sub forma unei
matrice cu m linii ³i n coloane, ca în gura de mai jos:
1110000111 unde 1 reprezint zid intact
1100001111 0 zid avariat
1000000011
1111101111
1110000111
Sumele alocate de Bin Laden pentru refacerea Pentagonului vor donate celor care vor ajuta
americanii s refac aceast cl dire prin plasarea, pe vertical , a unor blocuri de în lµimi k ,
k 1, ..., m, ³i l µime 1, în locurile avariate.
Cerinµ :
Pentru o structur dat a unui perete din cl direa Pentagonului, determinaµi num rul minim
al blocurilor, de în lµimi k 1, k 2, ..., k m, necesare refacerii cl dirii.
Date de intrare:
Fi³ierul de intrare PENTAGON.IN conµine pe prima linie dimensiunile m ³i n ale peretelui
cl dirii, iar pe urm toarele m linii câte o secvenµ de caractere 1 sau 0 de lungime n.
Date de ie³ire:
Fi³ierul PENTAGON.OUT va conµine pe câte o linie, ordonate cresc tor dup k , secvenµe:
k nr
unde k este înalµimea blocului,
iar nr este num rul de blocuri de în lµime k , separate prin câte un spaµiu.
Restricµii ³i preciz ri
a 1 & m, n & 200
a nu se vor a³a blocurile de în lµime k , a c ror num r este zero (0).
781
CAPITOLUL 36. ONI 2002 782
Exemplu
PENTAGON.IN PENTAGON.OUT
5 10 17
1110000111 21
1100001111 32
1000000011 51
1111101111
1110000111
Timp maxim de execuµie: 1 secund /test
3 f:text;
4 s:array[1..200] of byte;
5 m,n,i:byte;
6
7 Procedure numara;
8 var i,j:byte;
9 cod:boolean;
10 nr:byte;
11 begin
12 for j:=1 to n do
13 begin
14 nr:=0;
15 cod:=c[1,j]=’1’;
16 for i:=1 to m do
17 if c[i,j]=’1’ then
18 begin
19 if not cod then
20 begin
21 cod:=true;
22 inc(s[nr]);
23 nr:=0;
24 end
25 end
26 else
27 begin
28 if cod then
29 begin
30 nr:=1;
31 cod:=false;
32 end
33 else
34 inc(nr);
35 end;
36 if not cod then
37 begin
38 cod:=true;
39 inc(s[nr]);
40 end
41 end;
42 end;
43
44 begin
45 assign(f,’pentagon.in’);
46 reset(f);
47 readln(f,m,n);
48 for i:=1 to m do
49 readln(f,c[i]);
50 close(f);
51 numara;
52 assign(f,’pentagon.out’);
53 rewrite(f);
54 for i:=1 to m do
55 if s[i]<>0 then
56 writeln(f,i,’ ’,s[i]);
57 close(f);
58 end.
36.2 Pod
prof. Marinel erban, Ia³i
Între dou maluri ale unei v i adânci s-a construit un pod suspendat format din N buc µi
de scândur , legate cu liane.
Vom considera c scândurile sunt numerotate de la 1 la N , începând de pe malul pe care ne
a m.
În timp unele buc µi de scândur s-au deteriorat, iar altele chiar au disp rut.
Pentru traversarea podului se ³tie c :
se pot face pa³i doar de lungime 1, 2 sau 3;
scândurile deteriorate sunt nesigure, deci pe ele ³i de pe ele se pot face doar pa³i de lungime
1.
evident, nu se poate p ³i pe o scândur care lipse³te.
Cerinµ :
Scrieµi un program care s determine num rul de modalit µi de traversare a podului (mai exact,
de a ajunge pe cel lalt mal), precum ³i o soluµie de traversare, dac o astfel de soluµie exist .
Date de intrare:
Fi³ierul de intrare POD.IN are structura:
POD.IN Semnicaµie
N Num rul total de scânduri
k s1 s2 ... sk Num rul de scânduri lips ³i numerele lor de ordine
h d1 d2 ... dh Num rul de scânduri deteriorate ³i numerele lor de ordine
Date de ie³ire:
Fi³ierul de ie³ire POD.OUT va conµine pe prima linie valoarea -1 dac nu este posibil s
travers m podul, respectiv num rul de posibilit µi de a traversa podul, dac aceasta este posibil.
În cazul în care exist soluµii, pe cea de a doua linie va a³at o astfel de soluµie, prin
indicarea, în ordine, a scândurilor pe care se p ³e³te, sub forma:
POD.OUT Semnicaµie
Nr Num rul total de posibilit µi
p1 p2 ... pm Soluµia determinat , prin indicarea în ordine a scândurilor
pe care se p ³e³te
CAPITOLUL 36. ONI 2002 785
Restricµii ³i preciz ri:
a 3 & N & 300
a 0 & k, h & N
a rs1 , s2 , ..., sk x N r2, ...N x,
a rd1 , d2 , ..., dh x N r1, 2, ...N x;
a rs1 , s2 , ..., sk x = rd1 , d2 , ..., dh x o
a N r are cel mult 80 de cifre.
Exemple:
pod.in pod.out pod.in pod.out pod.in pod.out
5 24 10 48 6 -1
0 3 227 368 224
0 15 13
Timp maxim de execuµie: 1 secund /test
se realizeaz pe baza unor indici p straµi pentru ecare scândur în parte, ordinul de complexitate
al acestei operaµii este O 1. Datorit faptului c vor cel mult N astfel de determin ri, ordinul
de complexitate al operaµiei de determinare a modalit µii de traversare este O N . Scrierea
num rului posibilit µilor de traversare poate considerat a o operaµie elementar , deci are
ordinul de complexitate O 1. A³adar, ordinul de complexitate al operaµiei de scriere a datelor de
ie³ire este O(N) + O(1) = O(N).
În concluzie, algoritmul de rezolvare al acestei probleme are ordinul de complexitate O N
O N O N O N O N .
54 {
55 NrSol++;
56 if (NrSol==1)
57 {lgsol=k;
58 for (int i=0; i<lgsol; i++) sol[i]=p[i];}
59 }
60
61 void Gen(int k)
62 {
63 if (p[k-1]==n) GasitSol(k);
64 else
65 if (p[k-1]==n-1)
66 {if (!uz[n-1]) GasitSol(k);
67 if (!s[n]) {p[k]=n; Gen(k+1);}
68 }
69 else
70 if (p[k-1]==n-2)
71 {
72 if (!uz[n-2]) GasitSol(k); //sar direct
73 if (!s[n-1]) {p[k]=n-1; Gen(k+1);}
74 if (!s[n] && !uz[n] && !uz[n-2]) {p[k]=n; Gen(k+1);}
75 }
76 else
77 {//mai sar
78 if (!s[p[k-1]+1])
79 {
80 p[k]=p[k-1]+1;
81 Gen(k+1);
82 }
83 if (!s[p[k-1]+2] && !uz[p[k-1]+2] &&!uz[p[k-1]])
84 {
85 p[k]=p[k-1]+2;
86 Gen(k+1);
87 }
88 if (!s[p[k-1]+3] && !uz[p[k-1]+3] &&!uz[p[k-1]])
89 {
90 p[k]=p[k-1]+3;
91 Gen(k+1);
92 }
93 }
94 }
32
33 if (!s[n]) {Sum(Total,Nr[n]); final=n;}
34 if (strcmp(Nr[n-1],"-1") && !uz[n-1]) {Sum(Total,Nr[n-1]); final=n-1;}
35 if (strcmp(Nr[n-2],"-1") && !uz[n-2]) {Sum(Total,Nr[n-2]); final=n-2;}
36
37 ofstream fout(nfout);
38
39 if (strcmp(Total,"0"))
40 fout<<-1<<endl;
41 else
42 {fout<<strrev(Total)<<endl;
43 d[0]=final; lg=1;
44 while (poz[final]!=0) {d[lg++]=poz[final]; final=poz[final];}
45 for (final=lg-1; final>=0; final--)
46 fout<<d[final]<<’ ’;
47 fout<<endl;
48 }
49
50 fout.close();
51 }
52
53 void Citire()
54 {
55 ifstream f(nfin);
56 int x, k, h;
57 f>>n>>k;
58 for(int i=0;i<k;i++) {f>>x; s[x]=1;}
59 //s[x]=1 daca scandura x lipseste si 0 altfel
60 f>>h;
61 for(int i=0;i<h;i++) {f>>x; uz[x]=1;}
62 //uz[x]=1 daca scandura x este deteriorata si 0 altfel
63 f.close();
64 }
65
66 void Rezolva()
67 {
68 strcpy(Nr[1],"1"); poz[1]=0;
69 if (s[2]) strcpy(Nr[2],"-1");
70 else {strcpy(Nr[2],"2"); poz[2]=0;}
71 if (s[3]) strcpy(Nr[3],"-1");
72 else
73 if (s[2]) {strcpy(Nr[3],"2"); poz[3]=0;}
74 else {strcpy(Nr[3],"4"); poz[3]=0;}
75 for (int i=4; i<=n; i++)
76 if (s[i]) strcpy(Nr[i],"-1");
77 else
78 if (uz[i]) { strcpy(Nr[i],Nr[i-1]); poz[i]=i-1;}
79 else
80 {strcpy(Nr[i],"0");
81 if (strcmp(Nr[i-1],"-1"))
82 {strcpy(Nr[i],Nr[i-1]);poz[i]=i-1;}
83 if (strcmp(Nr[i-2],"-1") && !uz[i-2])
84 {Sum(Nr[i],Nr[i-2]);poz[i]=i-2;}
85 if (strcmp(Nr[i-3],"-1") && !uz[i-3])
86 {Sum(Nr[i],Nr[i-3]);poz[i]=i-3;}
87 if (!strcmp(Nr[i],"0"))
88 strcpy(Nr[i],"-1");}
89 }
90
91 void Sum (Big & A, Big & B)
92 {
93 //adun pe B la A
94 int t=0, cifra, i;
95 for (i=0; A[i] && B[i]; i++)
96 {cifra = (A[i]-’0’+B[i]-’0’+t);
97 A[i]=cifra%10+’0’;
98 t=cifra/10;}
99 for (; A[i]; i++)
100 {cifra = (A[i]-’0’+t);
101 A[i]=cifra%10+’0’;
102 t=cifra/10;}
103 for (; B[i]; i++)
104 {cifra = (B[i]-’0’+t);
105 A[i]=cifra%10+’0’;
106 t=cifra/10;}
107 A[i]=NULL;
CAPITOLUL 36. ONI 2002 789
71 {Nr[i]=0;
72 if (Nr[i-1]!=-1) {Nr[i]=Nr[i-1];poz[i]=i-1;}
73 if (Nr[i-2]!=-1 && !uz[i-2]) {Nr[i]+=Nr[i-2];poz[i]=i-2;}
74 if (Nr[i-3]!=-1 && !uz[i-3]) {Nr[i]+=Nr[i-3];poz[i]=i-3;}
75 if (!Nr[i]) Nr[i]=-1;}
76 }
62 afisv(y); System.out.println();
63
64 for(i=4;i<=ns+1;i++)
65 {
66 switch(x[i])
67 {
68 case lipsa:
69 y[i]=0; break;
70 case deteriorata:
71 if(x[i-1]!=lipsa) y[i]=y[i-1]; // 1 pas din i-1
72 break;
73 case buna:
74 y[i]=0; // pentru suma
75 if(x[i-3]==buna) y[i]+=y[i-3]; // 3 pasi din i-3
76 if(x[i-2]==buna) y[i]+=y[i-2]; // 2 pasi din i-2
77 if(x[i-1]!=lipsa) y[i]+=y[i-1]; // 1 pas din i-1
78 }
79 afisv(y);
80 }
81 }// main
82
83 static void afisv(int[] a)
84 {
85 int i;
86 for(i=1;i<=ns+1;i++) System.out.print(a[i]+" ");
87 System.out.println();
88 }
89 }// class
87 }// main
88
89 static boolean ok(int[] z)
90 {
91 int i;
92 for(i=0;i<z.length;i++) if(z[i]!=0) return true;
93 return false;
94 }
95
96 static void drum(int j)
97 {
98 if(p[j]!=0) drum(p[j]);
99 out.print(j+" ");
100 }
101
102 static void afisv(int[] x)
103 {
104 int nx=x.length;
105 int i;
106 for(i=nx-1;i>=0;i--) out.print(x[i]);
107 out.println();
108 }
109
110 static int[] nrv(int nr)
111 {
112 int nc;
113 int nrrez=nr;
114 nc=0;
115 while(nr!=0) {nc++; nr=nr/10;}
116 int[] x=new int[nc];
117 nr=nrrez;
118 nc=0;
119 while(nr!=0) { x[nc]=nr%10; nc++; nr=nr/10; }
120 return x;
121 }
122
123 static int[] suma(int[] x,int[] y)
124 {
125 int k,s,t;
126 int nx=x.length;
127 int ny=y.length;
128 int nz;
129 if(nx>ny)nz=nx+1; else nz=ny+1;
130 int[] z=new int[nz];
131 t=0;
132 for(k=0;k<nz;k++)
133 {
134 s=t;
135 if(k<nx) s=s+x[k];
136 if(k<ny) s=s+y[k];
137 z[k]=s%10;
138 t=s/10;
139 }
140 if(z[nz-1]!=0)return z;
141 else
142 {
143 int[] zz=new int[nz-1];
144 for(k=0;k<nz-1;k++) zz[k]=z[k];
145 return zz;
146 }
147 }
148 }// class
36.3 Suma
Florin Gheµu, Bucure³ti
Fie ³irul tuturor numerelor naturale de la 1 la un num r oarecare N .
Considerând asociate câte un semn (+ sau -) ec rui num r ³i adunând toate aceste numere
cu semn se obµine o sum S .
Problema const în a determina pentru o sum dat S , num rul minim N pentru care, printr-o
asociere de semne tuturor numerelor de la 1 la N , se poate obµine S .
Cerinµ :
CAPITOLUL 36. ONI 2002 795
Date de ie³ire
În ³ierul SUMA.OUT se va scrie, pe prima linie num rul minim N pentru care se poate obµine
suma S iar pe urm toarele linii, pân la sfâr³itul ³ierului, numerele care au semn negativ, câte
unul pe linie.
Ordinea de a³are a numerelor nu are importanµ .
Celelalte numere care nu apar în ³ier se consider pozitive.
Dac exist mai multe soluµii se cere doar una.
Exemplu:
SUMA.IN SUMA.OUT
12 7
1
7
Deci suma 12 se poate obµine din minimum 7 termeni astfel:
12 1 2 3 4 5 6 7.
Nu este singura posibilitate de asociere de semne termenilor de la 1 la 7.
Timpul de execuµie: 1 secund /test
Analiza complexit µii
CAPITOLUL 36. ONI 2002 796
Valoarea N poate obµinut folosind o simpl formul matematic , deci ordinul de complexi-
tate al acestei operaµii este O 1.
Valorile SN , SN 1 , SN 2 , DN , DN 1 , DN 2 sunt calculate tot cu ajutorul unor formule ma-
tematice simple, a³adar ordinul de complexitate al operaµiei de determinare a acestora este tot
O 1.
¬
Identicarea valorii N se face pe baza veric rii parit µii a cel mult trei numere, deci ³i aceast
operaµie are ordinul de complexitate O 1.
Determinarea valorii x ³i a celor cel mult dou numere c rora li se va modica semnul este
realizat tot pe baza unor calcule simple al c ror ordin de complexitate este O 1.
În concluzie, ordinul de complexitate al unui algoritm ecient de rezolvare a acestei probleme
este O 1 O 1 O 1 O 1 O 1.
este $O(N)$.
128
129 \^In concluzie, algoritmul de rezolvare al acestei probleme are ordinul de complexitate
$O(N^2) + O(N^2) + O(N) = O(N^2)$.
130
131
132 \subsection{*Rezolvare detaliat\u a}
133 \hspace{0.66cm}
134
135
136 %-----------------------------------------------
137
138 \subsection{Cod surs\u a}
139 \hspace{0.66cm}
140
141 \begin{lstlisting}[language=C++,commentstyle=\color{purple}, caption={\hspace{5mm}
becbun.cpp}]
142 #include <iostream>
143 #include <conio.h>
144 #include <stdio.h>
145
146 using namespace std;
147
148 int a[101][101],m,n,k,l0,l1,c0,c1,x,y;
149 int s[4];
150 FILE *g;
151
152 int generare(int lin, int col)
153 {
154 int ax[101][101],i,j,ok;
155 for(i=1;i<=m;i++)
156 for(j=1;j<=n;j++)
157 ax[i][j]=0;
158 for(j=1;j<=n;j++)//pun coloanele care trebuie pe 1
159 if(a[1][j]==lin)
160 for(i=1;i<=m;i++)
161 ax[i][j]=1;
162 for(i=1;i<=m;i++)//comut liniile care trebuie
163 if(a[i][1]==col)
164 for(j=1;j<=n;j++){
165 if(ax[i][j]==0) ax[i][j]=1;
166 else ax[i][j]=0;
167 }
168 //verificare
169 ok=1;
170 for(i=1;i<=m;i++)
171 for(j=1;j<=n;j++){
172 if(ax[i][j]!=a[i][j])
173 ok=0;
174 }
175 return ok;
176 }
177
178 void comutare(int lin,int col)
179 { int i,j;
180 //cout<<"\nmodific coloanele "<<endl;
181 int sw=1;
182 for(j=1;j<=n;j++) if (a[1][j]==lin)
183 { fprintf(g,"%d ",j);sw=0;
184 //solc[jj++]=j;
185 }
186 if (sw) fprintf(g,"0");
187 //cout<<"\nmodific liniile "<<endl;
188 fprintf(g,"\n");
189 sw=1;
190 for(i=1;i<=m;i++)
191 if (a[i][1]==col)
192 {fprintf(g,"%d ",i);
193 sw=0;}
194 if (sw) fprintf(g,"0");
195 fprintf(g,"\n");
196 }
197
198 int date_valide()
199 {
200 int sir[101],i,j,egale,opuse;
CAPITOLUL 36. ONI 2002 800
70 }
71 }
72
73 static boolean okLinia(int i)
74 {
75 int j;
76 for(j=2;j<=n;j++) if(b[i][j]!=b[i][1]) return false;
77 return true;
78 }
79
80 static void comutaColoana(int j)
81 {
82 int i;
83 for(i=1;i<=m;i++) b[i][j]=(byte)((1+b[i][j])%2); // 0<-->1
84 }
85
86 static void comutaLinia(int i)
87 {
88 int j;
89 for(j=1;j<=n;j++) b[i][j]=(byte)((1+b[i][j])%2); // 0<-->1
90 }
91
92 static void afisb()
93 {
94 int i,j;
95 for(i=1;i<=m;i++)
96 {
97 for(j=1;j<=n;j++) System.out.print(b[i][j]+" ");
98 System.out.println();
99 }
100 }
101 }
A doua faz : pun 1 pe prima linie ³i veric. Constat m c se poate folosi aceea³i metot dar
cu un parametru pentru a transmite valoarea 0 sau 1.
39 out.close();
40 }
41
42 static void facLinia1(byte val)
43 {
44 int i,j;
45 int nlc=0, ncc=0; // nr linii/coloane comutate
46 boolean ok=true;
47
48 for(j=1;j<=n;j++) colc[j]=0; // coloane necomutate inca
49 for(i=1;i<=m;i++) linc[i]=0; // linii necomutate inca
50 for(i=1;i<=m;i++) for(j=1;j<=n;j++) b[i][j]=a[i][j]; // copie
51
52 for(j=1;j<=n;j++)
53 if(b[1][j]!=val)
54 {
55 comutaColoana(j);
56 colc[j]=1; // coloana j este comutata;
57 ncc++;
58 }
59 afisb();
60 for(i=1;i<=m;i++) if(!okLinia(i)) { ok=false; break; }
61 else if(b[i][1]==1) { linc[i]=1; nlc++; }
62 if(ok&&(nlc+ncc<nlincsol+ncolcsol))
63 {
64 nlincsol=nlc;
65 ncolcsol=ncc;
66 for(i=1;i<=m;i++) lincsol[i]=linc[i];
67 for(j=1;j<=n;j++) colcsol[j]=colc[j];
68 }
69 }
70
71 static boolean okLinia(int i)
72 {
73 int j;
74 for(j=2;j<=n;j++) if(b[i][j]!=b[i][1]) return false;
75 return true;
76 }
77
78 static void comutaColoana(int j)
79 {
80 int i;
81 for(i=1;i<=m;i++) b[i][j]=(byte)((1+b[i][j])%2); // 0<-->1
82 }
83
84 static void comutaLinia(int i)
85 {
86 int j;
87 for(j=1;j<=n;j++) b[i][j]=(byte)((1+b[i][j])%2); // 0<-->1
88 }
89
90 static void afisb()
91 {
92 int i,j;
93 for(i=1;i<=m;i++)
94 {
95 for(j=1;j<=n;j++) System.out.print(b[i][j]+" ");
96 System.out.println();
97 }
98 System.out.println();
99 }
100 }
86 boolean ok=true;
87
88 for(j=1;j<=n;j++) colc[j]=0; // coloane necomutate inca
89 for(i=1;i<=m;i++) linc[i]=0; // linii necomutate inca
90 for(i=1;i<=m;i++) for(j=1;j<=n;j++) b[i][j]=a[i][j]; // copie
91
92 for(i=1;i<=m;i++)
93 if(b[i][1]!=val)
94 {
95 comutaLinia(i);
96 linc[i]=1; // linia i este comutata;
97 nlc++;
98 }
99 for(j=1;j<=n;j++)
100 if(!okColoana(j)) { ok=false; break;}
101 else if(b[1][j]==1) { colc[j]=1; ncc++; }
102 if(ok&&(nlc+ncc<nlincsol+ncolcsol))
103 {
104 nlincsol=nlc;
105 ncolcsol=ncc;
106 for(i=1;i<=m;i++) lincsol[i]=linc[i];
107 for(j=1;j<=n;j++) colcsol[j]=colc[j];
108 }
109 }
110
111 static boolean okLinia(int i)
112 {
113 int j;
114 for(j=2;j<=n;j++) if(b[i][j]!=b[i][1]) return false;
115 return true;
116 }
117
118 static boolean okColoana(int j)
119 {
120 int i;
121 for(i=2;i<=m;i++) if(b[i][j]!=b[1][j]) return false;
122 return true;
123 }
124
125 static void comutaColoana(int j)
126 {
127 int i;
128 for(i=1;i<=m;i++) b[i][j]=(byte)((1+b[i][j])%2); // 0<-->1
129 }
130
131 static void comutaLinia(int i)
132 {
133 int j;
134 for(j=1;j<=n;j++) b[i][j]=(byte)((1+b[i][j])%2); // 0<-->1
135 }
136 }
36.4 Discuri
Florin Gheµu, Bucure³ti
Se dau N numere reale considerate ca ind razele a N discuri.
Consider m c a³ez m un disc în sistemul xOy dac îl plas m la o coordonat x pozitiv
sucient de mare, tangent cu axa Ox ³i deasupra ei, apoi îl împingem spre Oy pân când devine
tangent cu Oy sau cu primul disc întâlnit, a³ezat anterior.
Dup a³ezarea tuturor discurilor în ordinea dat unele dintre ele pot considerate dispensabile,
pentru c prin eliminarea lor nu se modic l µimea total a gurii rezultate, adic nici un disc
nu se mai poate deplasa spre stânga.
Cerinµ :
Identicaµi toate discurile dispensabile dintr-o conguraµie dat .
Date de intrare:
Din ³ierul de intrare DISCURI.IN veµi citi de pe prima linie num rul N de discuri, iar de
pe urm toarele N linii, N numere reale reprezentând razele discurilor în ordinea de a³ezare, câte
unul pe linie.
CAPITOLUL 36. ONI 2002 806
Date de iesire:
În ³ierul DISCURI.OUT veµi scrie pe prima linie num rul K de discuri dispensabile, iar pe
urm toarele K linii, K întregi reprezentând numerele de ordine ale discurilor considerate dispen-
sabile, câte unul pe linie.
Restricµii:
a N & 1000.
Analiza complexit µii
CAPITOLUL 36. ONI 2002 807
Pentru ecare disc i care este introdus, se determin posibila coordonat xi datorat atingerii
cu toate cele i 1 discuri inserate anterior. Pentru cele N discuri se vor determina, în total,
0 1 2 ... N 1 N N 1©2 coordonate, deci ordinul de complexitate al acestei operaµii
2
este O N .
La ecare pas, pot marcate ca dispensabile cel mult toate discurile inserate anterior, a³adar
2
ordinul de complexitate al acestei operaµii este tot O N .
Determinarea l µimii gurii ³i a cercurilor dispensabile de la sfâr³itul secvenµei necesit a
singur parcurgere a ³irului care p streaz coordonatele centrelor discurilor, ceea ce implic ordinul
de complexitate O N .
A³area cercurilor dispensabile precum ³i citirea razelor cercurilor sunt operaµii care se efec-
tueaz în timp liniar (O N ), necesitând o simpl parcurgere a unor ³iruri.
În concluzie, ordinul de complexitate al algoritmului de rezolvare a acestei probleme este
2 2 2
O N O N O N O N O N O N .
36.5 Cod
lect. univ. Ovidiu Dom³a, Alba Iulia
Transmiterea ³i memorarea informaµiilor necesit diverse sisteme de codicare în vederea
utiliz rii optime a spaµiilor disponibile. Un sistem foarte des întâlnit este acela prin care unei
secvenµe de caractere i se asociaz un num r.
Se consider cuvintele formate numai cu literele mici ale alfabetului englez a, b, c, ..., z (26 de
caractere). Din toate aceste cuvinte le consider m doar pe cele ale c ror caractere sunt în ordine
strict lexicograc (caracterul de pe orice poziµie este strict mai mic decât orice caracter urm tor).
Sistemul de codicare se obµine astfel:
a Se ordoneaz cuvintele în ordinea cresc toare a lungimilor lor.
a Cuvintele de aceea³i lungime se ordoneaz lexicograc (în ordinea alfabetic a cuvintelor
dintr-un dicµionar).
a Codic m aceste cuvinte prin numerotarea lor începând cu a, dup cum urmeaz :
a 1
b 2
...
z 26
ab 27
...
az 51
bc 52
...
vwxzy 83681
...
Cerinµ :
Dac se d un cuvânt s se precizeze dac poate codicat conform sistemului de codicare.
În caz armativ s se precizeze codul s u.
Date de intrare
Fi³ierul de intrare COD.IN conµine pe o linie un cuvânt.
Date de ie³ire
Fi³ierul COD.OUT va conµine codul cuvântului ce trebuie codicat, sau 0 în cazul în care
cuvântul nu poate codicat.
Restricµii ³i preciz ri
a Num rul maxim de litere ale unui cuvânt este 10
a Num rul de caractere din alfabetului englez este 26
Exemple
COD.IN COD.OUT COD.IN COD.OUT COD.IN COD.OUT
bf 55 aab 0 vwxyz 83681
Timp maxim de execuµie: 2 secunde/test
În continuare, pentru prima liter a cuvântului, va trebui s g sim num rul cuvintelor care
încep cu o liter mai mic (din punct de vedere lexicograc).
CAPITOLUL 36. ONI 2002 810
k1 k1
În cazul în care cuvântul are k litere, vor exista C25 cuvinte valide care k încep cu 'a', C25
cuvinte valide care încep cu 'b' etc.
k 1
În general, vor exista C26i cuvinte valide care încep cu a i-a liter a alfabetului.
<
Dac prima liter a cuvântului este cea de-a n-a liter a alfabetului, vom avea i 1 C26i
n k1
Adunând toate valorile obµinute pe parcurs vom obµine num rul cuvintelor care se a înaintea
cuvântului dat. Adunând 1 la aceast valoare, vom obµine num rul de ordine al cuvântului.
Analiza complexit µii
Pentru a analiza complexitatea acestui algoritm va trebui s preciz m faptul c num rul lite-
relor din alfabet este constant, deci nu poate interveni în exprimarea ordinului de complexitate.
Acesta va stabilit doar în funcµie de lungimea k a cuvântului.
< k i
Iniµial se calculeaz suma i 1 C26 , operaµie realizabil în timp liniar, avân în vedere observaµia
anterioar . A³adar, primul pas al algoritmului are ordinul de complexitate O k .
<m1 k2
Pentru ecare liter a cuvântului se calculeaz suma i n1 C26i , unde variabilele au sem-
nicaµia prezentat anterior. Num rul de litere este implicat în determinarea valorii combin rii.
A³adar, calculul combin rii se realizeaz în timp liniar. Num rul de combin ri calculate nu de-
pinde de lungimea cuvântului, deci ordinul de complexitate al calcul rii acestei sume este O k .
În total vor calculate k astfel de sume, deci ordinul de complexitate al celui de-al doilea pas
2
al algoritmului este O k O k O k .
Citirea datelor de intrare ³i scrierea celor de ie³ire se realizeaz cu ajutorul unor operaµii
elementare, deci putem considera c au ordinul de complexitate O 1.
În concluzie, ordinul de complexitate al algoritmului de rezolvare a acestei probleme este
2 2
O k O k O k O k având în vedere c num rul literelor din alfabetul englez este
constant.
21 begin
22 if x=cuv then
23 begin
24 WriteLn(f,nr);
25 close(f);
26 Halt(0);
27 end;
28 end;
29
30 Procedure Back(i:byte);
31 var j,aa:char;
32 begin
33 if i=1 then aa:=’a’ else aa:=succ(x[i-1]);
34 for j:=aa to ’z’ do
35 begin
36 x:=X+j;
37 if i<l then Back(i+1)
38 else begin
39 nr:=nr+1;
40 sol(x);
41 end;
42 delete(x,i,1);
43 end;
44 end;
45
46 begin
47 assign(f,’cod.in’);
48 reset(f);
49 ReadLn(f,cuv);
50 close(f);
51 assign(f,’cod.out’);
52 rewrite(f);
53 nr:=0;
54 if verifcuv(cuv) then
55 for l:=1 to length(cuv) do
56 Back(1)
57 else
58 writeln(f,0);
59 close(f);
60 end.
33 ss:=ss+trunc(n);
34 end;
35 end;
36 assign(f,fou);
37 rewrite(f);
38 writeln(f,ss+1);
39 close(f);
40 end.
60 d=cmmdc(x[i],y[j]);
61 x[i]=x[i]/d;
62 y[j]=y[j]/d;
63 if(y[j]==1) break;
64 }
65 long p=1;
66 for(i=1;i<=k;i++) p=p*x[i];
67 return p;
68 }
69
70 static int cmmdc(int a, int b)
71 {
72 int d,i,c,r;
73 if (a>b) {d=a; i=b;} else {d=b; i=a;}
74 while (i != 0){ c=d/i; r=d%i; d=i; i=r; }
75 return d;
76 }
77 }
Capitolul 37
ONI 2001
37.1 Ferma
prof. Maria Niµ ³i prof. Adrian Niµ , Oradea
Un fermier are un teren care are forma unui tablou dreptunghiular lung de M unit µi ³i
lat de N unit µi. Pe teren sunt plantaµi din loc în loc copaci, pe care fermierul nu dore³te s -i
taie. Dorind s -³i supravegheze cultura, fermierul realizeaz un mic robot de form p trat având
latura de 3 unit µi pe care îl poate teleghida prin ferm , parcurgând unitate cu unitate o anumit
suprafaµ .
Robotul se poate mi³ca pe vertical ³i pe orizontal dar, nu poate trece peste copaci, nu îi poate
distruge, nu se poate roti ³i are nevoie pentru mi³care de o suprafaµ corespunz toare dimensiunii
lui.
Cerinµ
Ajutaµi-l pe fermier s determine suprafaµa maxim pe care o poate urm ri, folosind acest
sistem.
Date de intrare
Fi³ier de intrare: FERMA.IN
a Linia 1: N M - dou numere naturale nenule, separate pritr-un spaµiu, reprezentând num rul
de linii (N ), respectiv num rul de coloane (M );
a Liniile 2..N+1: C1 C2 ...CM - aceste N linii codic ferma; ecare linie conµine câte M
caractere (f r s e separate prin spaµii) având semnicaµia:
'.' - teren liber;
'+' - locul în care este plantat un copac;
'R' - centrul robotului.
Date de ie³ire
Fi³ier de ie³ire: FERMA.OUT
a Liniile 1..N: C1 C2 ...CM - aceste N linii codic modul în care fermierul poate s -³i utilizeze
robotul pe terenul s u; ecare linie conµine câte M caractere (f r s e separate prin spaµii)
având semnicaµia:
814
CAPITOLUL 37. ONI 2001 815
40 if(ir-2>=1) // sus
41 if((a[ir-2][jr-1]!=copac)&&(a[ir-2][jr]!=copac)&&(a[ir-2][jr+1]!=copac))
42 if((a[ir-2][jr-1]==liber)||(a[ir-2][jr]==liber)||(a[ir-2][jr+1]==liber))
43 {
44 a[ir-2][jr-1]=a[ir-2][jr]=a[ir-2][jr+1]=robot;
45 deplasareDin(ir-1,jr);
46 }
47
48 if(ir+2<=n) // jos
49 if((a[ir+2][jr-1]!=copac)&&(a[ir+2][jr]!=copac)&&(a[ir+2][jr+1]!=copac))
50 if((a[ir+2][jr-1]==liber)||(a[ir+2][jr]==liber)||(a[ir+2][jr+1]==liber))
51 {
52 a[ir+2][jr-1]=a[ir+2][jr]=a[ir+2][jr+1]=robot;
53 deplasareDin(ir+1,jr);
54 }
55
56 if(jr-2>=1) // stanga
57 if((a[ir-1][jr-2]!=copac)&&(a[ir][jr-2]!=copac)&&(a[ir+1][jr-2]!=copac))
58 if((a[ir-1][jr-2]==liber)||(a[ir][jr-2]==liber)||(a[ir+1][jr-2]==liber))
59 {
60 a[ir-1][jr-2]=a[ir][jr-2]=a[ir+1][jr-2]=robot;
61 deplasareDin(ir,jr-1);
62 }
63
64 if(jr+2<=m) // dreapta
65 if((a[ir-1][jr+2]!=copac)&&(a[ir][jr+2]!=copac)&&(a[ir+1][jr+2]!=copac))
66 if((a[ir-1][jr+2]==liber)||(a[ir][jr+2]==liber)||(a[ir+1][jr+2]==liber))
67 {
68 a[ir-1][jr+2]=a[ir][jr+2]=a[ir+1][jr+2]=robot;
69 deplasareDin(ir,jr+1);
70 }
71 }
72
73 static void afism()
74 {
75 int i,j;
76 for(i=1;i<=n;i++)
77 {
78 for(j=1;j<=m;j++) out.print((char) a[i][j]);
79 out.println();
80 }
81 out.println();
82 }
83 }
37.2 Fracµii
prof. Ovidiu Dom³a, Alba Iulia
O proprietate interesant a fracµiilor ireductibile este c orice fracµie se poate obµine dup
urm toarele reguli:
a pe primul nivel se a fracµia 1©1;
a pe al doilea nivel, în stânga fracµiei 1©1 de pe primul nivel, plas m fracµia 1©2 iar în dreapta
ei fracµia 2©1;
nivelul 1: 1©1
nivelul 2: 1 ©2 2©1
a pe ecare nivel k se plaseaz sub ecare fracµie i©j de pe nivelul de deasupra, fracµia i© i j
în stânga, iar fracµia i j ©j în dreapta.
nivelul 1: 1©1
nivelul 2: 1©2 2©1
nivelul 3: 1©3 3©2 2©3 3©1
Cerinµ
Dându-se o fracµie oarecare prin num r torul ³i numitorul s u, determinaµi num rul nivelului
pe care se a fracµia sau o fracµie echivalent (având aceea³i valoare) cu aceasta.
Date de intrare
Fi³ier de intrare: FRACTII.IN
CAPITOLUL 37. ONI 2001 818
Restricµii
1 $ N, M & 2.000.000.000
Exemple
FRACTII.IN FRACTII.OUT FRACTII.IN FRACTII.OUT
13 8 6 12 8 3
Timp maxim de execuµie: 1 secund /test
37.3 Tablou
prof. Rodica Pintea, Bucure³ti
Generaµi un tablou bidimensional cu propriet µile:
a conµine N linii ³i N coloane;
a elementele sale sunt numere naturale nenule;
a suma elementelor este egal cu num rul natural nenul S;
a pe nici o linie ³i pe nici o coloan nu exist dou elemente identice;
a diferenµa dintre cel mai mare ³i cel mai mic element ale tabloului este minim .
Date de intrare
Fi³ier de intrare: TABLOU.IN
a Linia 1: N S - dou numere naturale nenule, separate printr-un spaµiu, reprezentând num rul
de linii ³i de coloane ale tabloului, respectiv valoarea sumei tuturor elementelor din tablou;
Date de ie³ire
Fi³ier de ie³ire: TABLOU.OUT
a Linia 1..N: nr11 nr12 ... nr1N
nr21 nr22 ... nr2N
.........................
nrN 1 nrN 2 ... nrN N
pe aceste N linii se vor scrie elementele tabloului, câte o linie din tablou pe o linie din ³ier;
elementele se vor separa prin câte un spaµiu.
Restricµii ³i preciz ri
a 1 $ N & 100
0$S&2
31
a
a Dac problema nu are soluµie, în ³ierul de ie³ire se va scrie cifra 0.
a Dac problema are mai multe soluµii, în ³ier se va scrie una singur .
Exemplu
TABLOU.IN TABLOU.OUT
3 51 4 6 7
7 4 5
5 7 6
Timp maxim de execuµie: 1 sec/test
6
7 public static void main(String[] args) throws IOException
8 {
9 int i,j,k;
10 StreamTokenizer st=new StreamTokenizer(new BufferedReader(
11 new FileReader("tablou.in")));
12 PrintWriter out=new PrintWriter(new BufferedWriter(
13 new FileWriter("tablou.out")));
14 st.nextToken();n=(int)st.nval;
15 st.nextToken();s=(int)st.nval;
16 a=new int[n][n];
17
18 x=(2*s-n*n*n+n*n)/(2*n*n);
19 System.out.println("x="+x);
20 sp=0;
21 for(i=0;i<n;i++)
22 for(j=0;j<n;j++)
23 {
24 a[i][j]=x+(i+j)%n;
25 sp+=a[i][j];
26 }
27 p=s-sp;
28 System.out.println("sp="+sp+" s="+s+" p="+p);
29
30 System.out.println(); afism();
31 k=x+n-1;
32 while(p>0)
33 {
34 i=0;
35 while((p>0)&&(i<n)) // k=valoarea pe care o maresc cu 1
36 {
37 j=(n-i+k-1)%n;
38 System.out.println("k="+k+" i="+i+" j="+j+" p="+p);
39 a[i][j]++;
40 i++; p--;
41 }
42 System.out.println(); afism();
43 k--;
44 }
45 System.out.println(); afism();
46 out.close();
47 }
48
49 static void afism()
50 {
51 int i,j;
52 for(i=0;i<n;i++)
53 {
54 for(j=0;j<n;j++) System.out.print(a[i][j]+" ");
55 System.out.println();
56 }
57 }
58 }
20 for(i=0;i<n;i++)
21 for(j=0;j<n;j++)
22 {
23 a[i][j]=x+(i+j)%n;
24 sp+=a[i][j];
25 }
26 p=s-sp;
27 k=x+n-1;
28 while(p>0)
29 {
30 i=0;
31 while((p>0)&&(i<n)) // k=valoarea pe care o maresc cu 1
32 {
33 j=(n-i+k-1)%n;
34 a[i][j]++;
35 i++; p--;
36 }
37 k--;
38 }
39 for(i=0;i<n;i++)
40 {
41 for(j=0;j<n;j++) out.print(a[i][j]+" ");
42 out.println();
43 }
44 out.close();
45 }
46 }
37.5 Cuvinte
prof. Maria Niµ ³i prof. Adrian Niµ , Oradea
Se consider o list având un num r cunoscut de cuvinte. Din acest list s-au ales
dou cuvinte oarecare. Se dore³te transformarea primului cuvânt în cel de-al doilea, trecând
prin cuvinte intermediare, existente în lista dat . Trecerea dintr-un cuvânt în altul se poate face
folosind urm toarele operaµii: schimbarea, ad ugarea sau ³tergerea unui singur caracter.
Cerinµ
Dându-se o list de cuvinte ³i dou cuvinte din aceasta, g siµi cea mai scurt secvenµ de
operaµii care transform primul cuvânt în cel de-al doilea folosind operaµiile permise.
Date de intrare
Fi³ierul de intrare: CUVINTE.IN
a Linia 1: N P Q - trei numere naturale nenule, reprezentând num rul cuvintelor din list
(N ), poziµia primului cuvânt în list (P ), respectiv poziµia celui de-al doilea cuvânt în list (Q);
a Liniile 2..N+1: cuvânt - aceste N linii conµin ecare câte un cuvânt, aparµinând listei.
Date de ie³ire
Fi³ier de ie³ire: CUVINTE.OUT
a Linia 1: M - num r natural, reprezentând num rul minim de pa³i necesari pentru a ajunge
de la primul cuvânt la al doilea;
a Liniile 2..M+2: cuvânti - pe aceste linii apar în ordine cuvintele dintr-o secvenµ ce respect
cerinµa problemei (câte un cuvânt pe linie), inclusiv primul cuvânt al secvenµei.
Restricµii ³i preciz ri
a 2 & N & 100
a 1 & M, P, Q & 100
a num rul maxim de caractere dintr-un cuvânt este 100;
a dac nu exist soluµie, în ³ierul de ie³ire se va scrie num rul 0 (zero);
a dac sunt mai multe secvenµe de lungime minim , în ³ier se va scrie una singur .
Exemple
CUVINTE.IN CUVINTE.OUT CUVINTE.IN CUVINTE.OUT
715 2 716 0
car car car
cer mar cer
cerc mare cerc
mar mar
mare mare
rosu rosu
inrosit inrosit
Timp maxim de execuµie: 2 secunde/test
71 }
72 else // nx>ny
73 {
74 k=0;
75 while((k<ny)&&(x.charAt(k)==y.charAt(k))) k++;
76 if(k==ny) return 1;
77 else
78 {
79 k++;
80 while((k<ny)&&(x.charAt(k)==y.charAt(k-1))) k++;
81 if(k==ny) return 1; else return 0;
82 }
83 }
84 }
85 }
37.6 Grup
prof. Emanuela Cerchez ³i prof. Marinel erban, Ia³i
Administratorul reµelei cu N calculatoare de la SRI împarte, din motive strategice, aceste
calculatoare în mai multe grupuri. De fapt, important este doar num rul de grupuri ³i num rul de
calculatoare din ecare grup, a³a c împ rµirea este descris prin ³irul numerelor de calculatoare
din ecare grup, ordonat cresc tor.
Periodic, el procedeaz la o nou împ rµire pe grupe a calculatoarelor.
Dintre toate împ rµirile posibile ale calculatoarelor în grupuri putem alege ca urm toare îm-
p rµire doar aceea a c rei descriere precede sau succede lexicograc imediat împ rµirii curente.
Not :
Spunem c ³irul x1 x2 ... xp precede lexicograc ³irul y1 y2 ... yk dac :
a) exist un indice j , astfel încât xi yi pentru toµi indicii i $ j ³i xj $ yj
sau
b) p $ k ³i xi yi pentru toµi indicii i & p
Exemple
a) 3 7 2 5 precede lexicograc 3 7 4 1 6 2
b) 1 2 3 precede lexicograc 2
Cerinµ
Dându-se o împ rµire în grupe a celor N calculatoare, determinaµi cele dou variante candidate
pentru împ rµirea urm toare.
Date de intrare
Fi³ier de intrare: GRUP.IN
a Linia 1: N k - numere naturale nenule, reprezentând num rul total (N ) al calculatoarelor
din reµea ³i num rul (k ) de grupe.
a Linia 2: g1 g2 . . . gk - num rul calculatoarelor din ecare grup .
Date de ie³ire
Fi³ier de ie³ire: GRUP.OUT
a p - num rul de grupe din împ rµirea care precede lexicograc imediat împ rµirea dat ;
a h1 h2 ... hp - num rul de calculatoare din cele p grupe ale împ rµirii precedente;
a u - num rul de grupe din împ rµirea care succede lexicograc imediat împ rµirea dat ;
a t1 t2 ... tu - num rul de calculatoare din cele u grupe ale împ rµirii urm toare;
Restricµii ³i preciz ri
a 2 & N & 1000
a g1 g2 ... gk h1 h2 ... hp t1 t2 ... tu N
a 1 & g1 & g2 & ... & gk ; 1 & h1 & h2 & ... & hp ; 1 & t1 & t2 & ... & tu ;
a 1$k$N
a 1 & p, u & N
Exemplu
CAPITOLUL 37. ONI 2001 826
GRUP.IN GRUP.OUT
14 3 3
266 257
2
2 12
Timp maxim de execuµie: 1 secund /test
26 {
27 s=g[k];
28 i=k-1;
29 while(g[i]-1<g[i-1]) {s+=g[i]; i--;}
30 out.println(i+1); // nr grupe din precedenta
31 for(j=1;j<i;j++) out.print(g[j]+" ");
32 out.println((g[i]-1)+" "+(s+1));
33 }
34
35 if(g[k-1]+1<=g[k]-1)
36 {
37 nge=(g[k]-1)/(g[k-1]+1);// nr grupe egale la sfarsit
38 out.println(k+nge-1); // nr grupe din urmatoarea
39 for(j=1;j<=k-2;j++) out.print(g[j]+" ");
40 for(j=1;j<=nge;j++) out.print((g[k-1]+1)+" ");
41 out.println(g[k-1]+1+(g[k]-1)%(g[k-1]+1));
42 }
43 else
44 {
45 out.println(k-1); // nr grupe din urmatoarea
46 for(j=1;j<=k-2;j++) out.print(g[j]+" ");
47 out.println((g[k-1]+g[k]));
48 }
49 out.close();
50 }
51 }
Capitolul 38
ONI 2000
38.1 Algoritm
prof. Roxana Tâmplaru, Liceul "tefan Odobleja", Craiova
Georgel scrie un algoritm care conµine structuri de atribuire, alternative, de selecµie,
repetitive ³i compuse. Dup scrierea algoritmului vrea s -l testeze pentru toate cazurile posibile.
Pentru aceasta trebuie s cunoasc num rul minim de date de test necesare.
Pentru descrirea structurilor se utilizeaz urm toarele cuvinte cheie:
- pentru atribuire ATRIB
- pentru alternativ DACA
ATUNCI
ALTFEL unde ALTFEL poate lipsi
- pentru selecµie ALEGE
CAZ
CAZ_IMPLICIT unde CAZ_IMPLICIT poate lipsi
- pentru repetitive 1) CAT_TIMP
2) REPETA
PANA_CAND
3) PENTRU
- pentru compus INCEPUT
SFARSIT
Nu se face diferenµ între literele mari ³i literele mici. Un algoritm începe cu cuvântul cheie
INCEPUT, se termin cu SFARSIT ³i nu conµine structuri vide. De asemenea o structur compus
începe cu cuvântul cheie INCEPUT ³i se termin cu SFARSIT.
Cerinµ
S se calculeze num rul minim de date de test necesare pentru vericarea algoritmului.
Date de intrare:
Din ³ierul text ALGOR.IN se cite³te algoritmul.
Fi³ierul conµine pe ecare linie câte un singur cuvânt cheie.
Nu exist linii vide.
Algoritmul respect principiile program rii structurate ³i este scris corect.
Date de ie³ire:
În ³ierul ALGOR.OUT se va scrie pe prima linie num rul minim de date de test necesare
pentru vericarea algoritmului. Vericarea se bazeaz pe principiul "cutiei transparente", ceea ce
828
CAPITOLUL 38. ONI 2000 829
înseamn c testele se compun astfel încât s e posibil executarea algoritmului pe toate ramurile
posibile.
De exemplu, în cazul unei structuri repetitive CAT_TIMP care conµine în corpul s u un singur
ATRIB, un test vizeaz o execuµie f r s se intre în corpul structurii, altul pentru a trece cel
puµin o dat ³i prin corpul acestuia.
În mod similar se trateaz ³i structura PENTRU.
Restricµii ³i preciz ri
a Dup cuvintele cheie
ATUNCI, ALTFEL,
CAZ, CAZ_IMPLICIT,
CAT_TIMP, REPETA, PENTRU
trebuie s existe obligatoriu o structur de atribuire, alternativ , de decizie, repetitiv sau
compus .
Exemplul 1:
ALGOR.IN ALGOR.OUT
INCEPUT 2
atrib
DACA
atunci
ATRIB
SFARSIT
Exemplul 2:
ALGOR.IN ALGOR.OUT OBS.
INCEPUT 1 REPETA se execut cel puµin o dat
ATRIB
REPETA
inceput
atrib
atrib
SFARSIT
pana_cand
SFARSIT
Exemplul 3:
ALGOR.IN ALGOR.OUT OBS.
INCEPUT 3 - se execut ATRIB de la primul CAZ
ATRIB - se execut ATRIB de la al doilea CAZ
ALEGE - nu se execut nici primul CAZ,
CAZ nici al doilea
ATRIB
CAZ
INCEPUT
ATRIB
ATRIB
SFARSIT
SFARSIT
Exemplul 4:
ALGOR.IN ALGOR.OUT OBS.
INCEPUT 3 - se execut ATRIB
ATRIB de la primul CAZ
ALEGE - se execut ATRIB
CAZ de la al doilea CAZ
ATRIB - se execut ATRIB
CAZ de la CAZ_IMPLICIT
ATRIB
CAZ_IMPLICIT
ATRIB
SFARSIT
Exemplul 5:
CAPITOLUL 38. ONI 2000 830
43 { Altfel }
44 nrAltfel := 1;
45 if atom = ’altfel’ then begin
46 AnaLex;
47 nrAltfel := Instr;
48 end;
49 nr := nrAtunci + nrAltfel;
50 end
51
52 else if atom = ’alege’ then begin
53 AnaLex;
54 implicit := false;
55 nr := 0;
56 while (atom = ’caz’) or (atom = ’caz_implicit’) do begin
57 if (atom = ’caz_implicit’) then implicit := true;
58 AnaLex;
59 nrCaz := Instr;
60 nr := nr + nrCaz;
61 end;
62 if not implicit then inc(nr);
63 end
64
65 else if atom = ’cat_timp’ then begin
66 AnaLex;
67 nr := Instr+1;
68 end
69
70 else if atom = ’repeta’ then begin
71 AnaLex;
72 nr := Instr;
73 AnaLex;
74 end
75
76 else if atom = ’pentru’ then begin
77 AnaLex;
78 nr := Instr+1;
79 end
80
81 else if atom = ’inceput’ then begin
82 contor := 0;
83 repeat
84 if atom = ’inceput’ then begin
85 AnaLex;
86 inc(contor)
87 end
88 else if atom = ’sfarsit’ then begin
89 AnaLex;
90 dec(contor);
91 end
92 else begin
93 nrTemp := Instr;
94 nr := nr * nrTemp;
95 end
96 until contor = 0;
97 end
98
99 else nr := 1;
100
101 Instr := nr;
102 end;
103
104 begin
105 { Deschidere fisiere }
106 assign(fin, ’Algor.in’);
107 reset(fin);
108 assign(fout, ’Algor.out’);
109 rewrite(fout);
110
111 { Calcul }
112 AnaLex;
113 writeln(fout,Instr);
114 close(fout);
115 close(fin);
116 end.
CAPITOLUL 38. ONI 2000 832
71 readAtom(); nr=nrTeste();
72 readAtom(); // citeste ce urmeaza dupa "pana_cand"
73 }
74 else if(atom.equals("pentru")) {readAtom(); nr=nrTeste()+1;}
75 else nr=1; // la eof
76
77 System.out.println(" <*** "+atomr);
78 return nr;
79 }
80
81 static void readAtom() throws IOException
82 {
83 if(st.nextToken()==StreamTokenizer.TT_EOF) atom="eof";
84 else atom=st.sval.toString().toLowerCase();
85
86 System.out.println("readAtom() "+atom);
87 pauza=br.readLine();
88 }
89 }// class
54 readAtom();
55 while(atom.equals("caz")||atom.equals("caz_implicit"))
56 {
57 if(atom.equals("caz_implicit")) implicit = true;
58 readAtom(); nrTesteCaz=nrTeste();
59 nr=nr+nrTesteCaz;
60 }
61 if(!implicit) nr++;
62 }
63 else if(atom.equals("cat_timp")) {readAtom(); nr=nrTeste()+1;}
64 else if(atom.equals("repeta"))
65 {
66 readAtom(); nr=nrTeste();
67 readAtom(); // citeste ce urmeaza dupa "pana_cand"
68 }
69 else if(atom.equals("pentru")) {readAtom(); nr=nrTeste()+1;}
70 else nr=1; // pentru "eof"
71
72 return nr;
73 }
74
75 static void readAtom() throws IOException
76 {
77 if(st.nextToken()==StreamTokenizer.TT_EOF) atom="eof";
78 else atom=st.sval.toString().toLowerCase();
79 }
80 }// class
Date de ie³ire
Fi³ierul de ie³ire COD.OUT va conµine o singur linie pe care se va aa codul urm tor; dac
nu exist un astfel de cod, atunci în ³ier se va scrie "Este ultimul cod."
Restricµii ³i preciz ri
a Codurile sunt formate din cel mult 100 de litere mici ale alfabetului latin.
Exemple:
COD.IN COD.OUT COD.IN COD.OUT
amaaxm amamax xmmaaa Este ultimul cod.
Timp de execuµie: 1 secund /test.
Se determin cel mai mare indice i pentru care cod[i]<cod[i+1]. Caracterele de pe ultimile
poziµii din cod, incepând cu poziµia i inclusiv, se scriu în noul cod în ordine cresc toare.
CAPITOLUL 38. ONI 2000 835
66 rewrite(t);
67 if nedes(cod)=true then
68 begin
69 for i:=length(cod)-1 downto 1 do
70 begin
71 for j:=i to length(cod) do cod_temp:=cod_temp+cod[j];
72 if nedes(cod_temp) then
73 begin
74 next(i);
75 writeln(t,cod);
76 goto e;
77 end;
78 end;
79 if i=1 then
80 begin
81 writeln(t,’Este ultimul cod’);
82 goto e;
83 end;
84 end
85 else writeln(t,’Este ultimul cod’);
86 e:close(t);
87 end.
51 Writeln(fo,urm);
52 Close(fi);
53 Close(fo)
54 End.
28 nrl2[j]--;
29 i--;
30 }
31 j=(byte)cod[i+1]-’a’;
32 nrl2[j]--;
33
34 for(k=0;k<i;k++) System.out.print(cod[k]);
35 System.out.println();
36
37 if(i<0) out.println("Este ultimul cod.");
38 else
39 {
40 j=(byte)cod[i]-’a’; // j = "codul" caracterului cod[i]
41 nrl2[j]--; // caractere de pus la sfarsit!
42
43 for(k=0;k<26;k++)
44 if(nrl2[k]!=nrl1[k])
45 System.out.println((char)(k+’a’)+" "+nrl2[k]+" "+nrl1[k]);
46
47 for(k=j+1;k<26;k++) // caut primul caracter > cod[i]
48 if(nrl2[k]<nrl1[k]) // si il pun pe pozitia i
49 {
50 cod[i]=(char)(k+’a’);
51 nrl2[k]++;
52 break;
53 }
54
55 for(k=0;k<=i;k++) System.out.print(cod[k]);
56 System.out.println();
57
58 for(k=0;k<26;k++)
59 if(nrl2[k]!=nrl1[k])
60 System.out.println((char)(k+’a’)+" "+nrl2[k]+" "+nrl1[k]);
61
62 i++;
63 for(k=0;k<26;k++)
64 if(nrl2[k]<nrl1[k]) // poate lipsi !
65 for(j=nrl2[k];j<nrl1[k];j++)
66 {
67 cod[i]=(char)(k+’a’);
68 for(kk=0;kk<=i;kk++) System.out.print(cod[kk]);
69 System.out.println();
70 i++;
71 }
72 for(k=0;k<n;k++) out.print(cod[k]);
73 out.println();
74 }
75 out.close();
76 }
77 }
22 while((i>=0)&&(cod[i]>=cod[i+1]))
23 {
24 j=(byte)cod[i+1]-’a’;
25 nrl2[j]--;
26 i--;
27 }
28 j=(byte)cod[i+1]-’a’; // trebuie si el!
29 nrl2[j]--;
30
31 if(i<0) out.println("Este ultimul cod.");
32 else
33 {
34 j=(byte)cod[i]-’a’; // j = "codul" caracterului cod[i]
35 nrl2[j]--; // caractere de pus la sfarsit!
36
37 for(k=j+1;k<26;k++) // caut primul caracter > cod[i]
38 if(nrl2[k]<nrl1[k]) // si il pun pe pozitia i
39 {
40 cod[i]=(char)(k+’a’);
41 nrl2[k]++;
42 break;
43 }
44
45 i++;
46 for(k=0;k<26;k++)
47 if(nrl2[k]<nrl1[k]) // poate lipsi !
48 for(j=nrl2[k];j<nrl1[k];j++)
49 {
50 cod[i]=(char)(k+’a’);
51 i++;
52 }
53 for(k=0;k<n;k++) out.print(cod[k]);
54 out.println();
55 }
56 out.close();
57 }
58 }
38.3 Comoara
Mihai Stroe, student, Universitatea Politehnica, Bucure³ti
Cei K membri ai unui grup de c ut tori de comori se a într-un complex dreptunghiular
format din camere p trate de latur 1.
În mod normal toate camerele ar trebui s e deschise, dar o parte dintre ele sunt închise ³i
pot deschise doar cu ajutorul unor cartele speciale. Astfel, ecare camer ³i ecare cartel are
asociat un num r între 0 ³i 20; o camer cu num rul asociat 0 este deschis de la început, în
timp ce una cu num rul asociat diferit de 0 este iniµial închis , poate deschis din interior sau
din exterior dintr-o camer vecin cu o cartel cu num rul corespunz tor ³i va r mâne deschis
ulterior.
Cartelele cu num rul asociat 0 nu au nici o întrebuinµare practic . Un num r poate asociat
mai multor cartele, respectiv camere. Dintr-o camer se poate trece în alta numai dac ele sunt
vecine ³i ambele sunt deschise. Dou camere se consider vecine dac au un perete (deci o latur )
în comun.
În ecare camer se a comori cu o valoare între 0 ³i 10000. De asemenea, în ecare camer
se a exact o cartel de acces (cu num rul asociat între 0 ³i 20); un c ut tor de comori poate
ridica ³i folosi cartelele din camerele prin care trece, dar nu le poate da unui alt c ut tor decât
dac respectivul se a în aceea³i camer cu el.
Cerinµ
Cunoscându-se conguraµia complexului ³i poziµiile iniµiale ale c ut torilor de comori, s se
determine valoarea maxim a comorilor adunate de ace³tia.
Datele de intrare
se citesc din ³ierul COMOARA.IN care are urm torul format:
pe prima linie dimensiunile complexului, m ³i n
pe urm toarele m linii numerele asociate ec rei camere
pe urm toarele m linii valorile comorilor din ecare camer
pe urm toarele m linii numerele asociate cartelelor din ecare camer
CAPITOLUL 38. ONI 2000 840
Se folose³te un algoritm de tip ll (umplere) pentru ecare c ut tor de comori, în mod repetat,
pân când nu mai apar îmbun t µiri ale soluµiei. Pe parcurs, unele camere devin ³i r mân deschise.
Pentru ecare c ut tor de comori se p streaz informaµii referitoare la cheile pe care le are la un
moment dat (în momentul în care poate p trunde într-o camer , el ia cheia existent în acea
camer ).
95 for j:=1 to n do
96 begin
97 l:=0;
98 for ii:=1 to k do
99 if ok[ii,i,j]=1 then
100 l:=1;
101 if l=1 then
102 d[i,j]:=1;
103 end;
104 for i:=1 to m do
105 begin
106 for j:=1 to n do
107 write(fo,d[i,j],’ ’);
108 writeln(fo);
109 end;
110
111 end;
112
113 procedure solve;
114 begin
115 init;
116 gata:=false;
117 while not gata do
118 expand;
119 rewrite(fo);
120 writeln(fo,s);
121 { dump;}
122 close(fo);
123 end;
124
125 begin
126 readdata;
127 solve;
128 end.
34 st.nextToken(); n=(int)st.nval;
35 codCamera=new int[m+1][n+1];
36 valc=new int[m+1][n+1];
37 cheiaDinCamera=new int[m+1][n+1];
38 traseu=new boolean[m+1][n+1];
39
40 for(i=1;i<=m;i++)
41 for(j=1;j<=n;j++) {st.nextToken(); codCamera[i][j]=(int)st.nval;}
42 for(i=1;i<=m;i++)
43 for(j=1;j<=n;j++) {st.nextToken(); valc[i][j]=(int)st.nval;}
44 for(i=1;i<=m;i++)
45 for(j=1;j<=n;j++) {st.nextToken(); cheiaDinCamera[i][j]=(int)st.nval;}
46
47 st.nextToken(); k=(int)st.nval;
48 arecheia=new boolean[k+1][21];
49 lin=new int[k+1];
50 col=new int[k+1];
51 amaifost=new boolean[k+1][m+1][n+1];
52
53 for(i=1;i<=k;i++)
54 {
55 st.nextToken(); lin[i]=(int)st.nval;
56 st.nextToken(); col[i]=(int)st.nval;
57 }
58 }
59
60 static void rezolvare()
61 {
62 int i;
63 s=0;
64 for(i=1;i<=k;i++) arecheia[i][0]=true;
65 for(i=1;i<=k;i++) amaifost[i][lin[i]][col[i]]=true;
66
67 gata=false;
68 while(!gata) alteCautari();
69 }
70
71 static void alteCautari()
72 {
73 int i;
74 gata=true;
75 for(i=1;i<=k;i++)
76 {
77 curatTraseu();
78 cauta(i,lin[i],col[i]);
79 }
80 }
81
82 static void curatTraseu()
83 {
84 int i,j;
85 for(i=1;i<=m;i++) for(j=1;j<=n;j++) traseu[i][j]=false;
86 }
87
88 static void cauta(int x, int i, int j) // alg "fill" (de umplere)
89 {
90 if((i<1)||(i>m)||(j<1)||(j>n)) return;
91 if(traseu[i][j]) return; // a mai trecut pe aici
92 if((!amaifost[x][i][j])&& // nu a mai fost aici
93 (!arecheia[x][codCamera[i][j]])) return; // nu are cheia de intrare aici
94
95 traseu[i][j]=true;
96 if(!amaifost[x][i][j]) gata=false; // face o imbunatatire
97 amaifost[x][i][j]=true;
98
99 arecheia[x][cheiaDinCamera[i][j]]=true; // ia cheia din camera
100 s=s+valc[i][j]; // ia valorile
101 valc[i][j]=0; // raman valori zero
102
103 if(arecheia[x][codCamera[i][j]]) // daca are cheia camerei
104 {
105 codCamera[i][j]=0; // camera ramane deschisa
106 cauta(x,i-1,j);
107 cauta(x,i+1,j);
108 cauta(x,i,j-1);
109 cauta(x,i,j+1);
CAPITOLUL 38. ONI 2000 844
110 }
111 }
112
113 static void afisare() throws IOException
114 {
115 out=new PrintWriter(
116 new BufferedWriter(new FileWriter("comoara.out")));
117 out.println(s);
118 out.close();
119 }
120 }
38.4 Cuburi
prof. Ovidiu Dom³a, Colegiul "Horea, Clo³ca ³i Cri³an", Alba Iulia
Un joc nou este format din n cuburi identice, numerotate de la 1 la n. Fiecare cub are
toate cele ³ase feµe adezive (cu "scai").
Jocul const în realizarea unui obiect din toate cele n cuburi.
Obiectul iniµial este cubul 1. Un obiect se obµine din obiectul anterior prin alipirea unui nou
cub la un cub aat în obiect, pe una din feµele acestuia.
Pentru alipirea unui cub nou, se extrage un bileµel cu num rul cubului la care se va alipi acesta
³i se arunc un zar care va indica unde va lipit cubul nou (sus, jos, la stânga, la dreapta, în faµ
sau în spate, poziµii codicate respectiv cu 1, 2, 3, 4, 5, 6, ale cubului din obiect).
Cerinµ
a Dându-se o succesiune de alipire a cuburilor, vericaµi dac aceasta este valid
b Dac succesiunea este valid , precizaµi dac obiectul obµinut are forma unui paralelipiped
plin, specicând dimesiunile acestuia.
Date de intrare
Fisierul CUBURI.IN conµine pe prima linie valoarea lui n.
Pe urm toarele n 1 linii, se a o succesiune de a³ezare a cuburilor, pentru ecare cub
specicând:
num r_cub biletel zar
valori separate prin câte un spatiu.
Date de ie³ire
Fi³ierul de iesire CUBURI.OUT va conµine pe dou linii rezultatele de la punctul a ³i respectiv
b dup cum urmeaz :
a Dac succesiunea este valid , prima linie va contine valoarea 0. În caz contrar, prima linie
va contine num rul cubului ce nu poate alipit, num rul cubului ³i num rul feµei la care nu se
poate alipi, precum si codul de eroare:
1 pentru alipire la cub inexistent;
2 pentru alipire pe o faµ ocupat .
b Dac obiectul nu este paralelipiped plin, sau dac succesiunea nu este valid , a doua linie a
³ierului va conµine valoarea 0.
Dac obiectul este paralelipiped plin, a doua linie a ³ierului va conµine dimensiunile acestuia,
m surate în num r de cuburi, în ordinea:
num r de cuburi pe directiile sus-jos, stânga-dreapta, faµ -spate
separate prin câte un spatiu.
Restricµii ³i precizri
a 2 & n & 1000;
a pe o dimensiune se alipesc cel mult 10 cuburi.
Exemple
CUBURI.IN CUBURI.OUT CUBURI.IN CUBURI.OUT
6 0 4 0
211 321 211 0
324 421
514 324
631
463
CAPITOLUL 38. ONI 2000 845
Identic m poziµia cubului în obiect prin coordonatele sale din (stanga, jos, faµ ). De aseme-
nea, pentru c pe o dimensiune se alipesc cel mult 10 cuburi, folosim un tablou tridimensional
pentru a reµine num rul de ordine al cubului care este plasat în oricare punct al spaµiului în care
poate s e construit corpul respectiv.
117 end.
67 ok=false;
68 break; // iese din for ==> nu mai pun "else" !
69 }
70 ecubul[x[cubnou]][y[cubnou]][z[cubnou]]=cubnou;
71 eplasat[cubnou]=true;
72 }
73 if(ok)
74 if((maxx-minx+1)*(maxy-miny+1)*(maxz-minz+1)==n)
75 {
76 out.println("0");
77 out.println((maxz-minz+1)+" "+(maxx-minx+1)+" "+(maxy-miny+1));
78 }
79 else
80 {
81 out.println("0");
82 out.println("0");
83 }
84 out.close();
85 }
86 }
38.5 Fibo
prof. Marinel erban, Liceul de Informatic , Ia³i
Consider m ³irul lui Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
Dat ind un num r natural (n " N), scrieµi acest num r sub form de sum de elemente
neconsecutive din ³irul Fibonacci, ecare element putând s apar cel mult o dat , astfel încât
num rul de termeni ai sumei s e minim.
Date de intrare
Din ³ierul FIB.IN se cite³te de pe prima linie num rul natural n.
Datele de ie³ire
În ³ierul de ie³ire FIB.OUT se vor a³a termeni ai ³irului Fibonacci, câte unul pe linie, a
c ror sum este n.
Restricµii ³i preciz ri
a n poate avea maxim 80 de cifre
Exemple:
FIB.IN FIB.OUT FIB.IN FIB.OUT
20 2 8 8
5
13
Timp maxim de execuµie pe test: 1 secund
Se determin cel mai mare num r din ³irul Fibonacci care este mai mic sau egal cu num rul
dat. Acesta este primul num r din soluµie. Se determin cel mai mare num r din ³irul Fibonacci
care este mai mic sau egal cu diferenµa dintre num rul dat ³i primul num r din soluµie. Acesta
este al doilea num r din soluµie. Se repet acest algoritm pân când num rul r mas devine zero.
Se folosesc operaµiile de adunare, sc dere ³i comparare cu numere mari.
99 WriteLn(Fout, F[i]);
100 n := Scadere(n, F[i]);
101 Until n=’0’;
102 Close(Fout);
103 End;
104
105 Begin
106 Citire;
107 Fibonacci;
108 Determina;
109 End.
57 int ny=y.length;
58 int nz=nx;
59 int t,i;
60 int[] z=new int[nz];
61 int[] yy=new int[nz];
62 for(i=0;i<ny;i++) yy[i]=y[i];
63 t=0;
64 for(i=0;i<nz;i++)
65 {
66 z[i]=x[i]-yy[i]-t;
67 if(z[i]<0) {z[i]+=10; t=1;} else t=0;
68 }
69 if(z[nz-1]!=0) return z;
70 else
71 {
72 int[] zz=new int[nz-1];
73 for(i=0;i<nz-1;i++) zz[i]=z[i];
74 return zz;
75 }
76 }
77
78 static int[] suma(int[] x,int[] y)
79 {
80 int nx=x.length;
81 int ny=y.length;
82 int nz;
83 if(nx>ny) nz=nx+1; else nz=ny+1;
84 int t,i;
85 int[] z=new int[nz];
86 int[] xx=new int[nz];
87 int[] yy=new int[nz];
88 for(i=0;i<nx;i++) xx[i]=x[i];
89 for(i=0;i<ny;i++) yy[i]=y[i];
90 t=0;
91 for(i=0;i<nz;i++)
92 {
93 z[i]=xx[i]+yy[i]+t;
94 t=z[i]/10;
95 z[i]=z[i]%10;
96 }
97 if(z[nz-1]!=0) return z;
98 else
99 {
100 int[] zz=new int[nz-1];
101 for(i=0;i<nz-1;i++) zz[i]=z[i];
102 return zz;
103 }
104 }
105
106 static int[] nr2v(int nr)
107 {
108 int nrr=nr,nc=0,i;
109 while(nr!=0) { nc++; nr=nr/10; }
110 int[] nrv=new int[nc];
111 nr=nrr;
112 for(i=0;i<nc;i++) { nrv[i]=nr%10; nr=nr/10; }
113 return nrv;
114 }
115
116 static void afisv(int[] x)
117 {
118 int i;
119 for(i=x.length-1;i>=0;i--) out.print(x[i]);
120 out.println();
121 }
122 }
38.6 Kommando
prof. Marinel erban, Liceul de Informatic , Ia³i
Într-o cl dire cu h etaje sunt deµinuµi, la parter, câµiva prizonieri de c tre T terori³ti.
Fiecare etaj al cl dirii are m n camere identice. Fiecare camer are un cod numeric (nu neap rat
unic) exprimat printr-un num r din intervalul 0 255.
CAPITOLUL 38. ONI 2000 853
O trup de komando, format din K speciali³ti în luptele antitero, trebuie s elibereze prizo-
nierii. Trupa de komando este para³utat pe cl dire ³i încearc s ajung la parter. Se cunoa³te
locul x, y unde ecare membru al trupei a aterizat pe acoperi³.
Greutatea ec rui membru al trupei este exprimat în unit µi din intervalul 1 255. Un
membru al trupei poate trece "în jos" printr-o camer a cl dirii doar dac "greutatea lui trece
prin camera respectiv ", conform urm toarei deniµii.
Deniµie: Spunem c "a trece prin b" (a %% b) dac , în reprezentare binar , num rul de cifre
1 a lui a este mai mic sau egal cu num rul de cifre 1 a lui b ³i cifrele 1 ale lui a sunt comune cu
unele cifre 1 ale lui b.
Exemplu: "44 trece prin 174" (44 %% 174) deoarece
44 = 00101100
174 = 10101110
Pentru detectarea unei camere prin care s poat trece, un membru al trupei de komando se
poate, eventual, deplasa cu un "pas" în cele 8 direcµii al turate poziµiei curente în care a ajuns prin
aterizare sau trecerea "în jos". Prin "pas"-ul respectiv se ajunge la una din cele 8 camere vecine.
Prizonierii pot eliberaµi doar dac la parter ajung minim T membri ai trupei de komando.
Cerinµ :
S se determine dac prizonierii pot eliberaµi sau nu, precum ³i num rul de membri ai trupei
de komando care pot s ajung la parter.
Date de intrare
Fi³ierul text KOMMANDO.IN are structura urm toare:
a pe prima linie valorile m, n, h, K , T desp rµite prin câte un spaµiu, cu semnicaµiile descrise
mai sus;
a urm toarele h linii reprezint codurile celor m n camere ale unui etaj, desp rµite prin câte
un spaµiu;
a ultimele K linii ale ³ierului conµin greutatea ³i coordonatele x ³i y a poziµiei de aterizare pe
acoperi³ ale celor K membri ai trupei de komando, pentru ecare pe câte o linie, desp rµite prin
câte un spaµiu:
m n h K T
c111 c112 ... c11n c121 c122 ... c12n ... c1m1 ... c1mn
...
ch11 ch12 ... ch1n ch21 ch22 ... ch2n ... chm1 ... chmn
G1 x1 y1
...
GK xK yK
Datele de ie³ire:
Fi³ierul text KOMMANDO.OUT cu structura:
a DA sau NU - pe prima linie;
a num rul de membri ai trupei de komando ajun³i la parter - pe linia a doua.
Restricµii ³i preciz ri
a 2 & m, n, h & 35 1 & xi & m 1 & yi &n
a 1 & T, K, Gi & 255
a 0 & cijk & 255
a Toate valorile sunt întregi.
Exemplu:
KOMMANDO.IN KOMMANDO.OUT
55532 DA
0 0 0 0 0 0 0 33 0 0 0 02 0000030 00000 2
00000 01 0000 44 2 0 0 0 0 0 3 0 0 0 0 0 0
0 0 0 0 0 11 0 0 0 0 0 0 2 22 0 0 0 0 0 3 0 0 0 0 0
00000 00 0000 66 2 0 0 0 0 0 7 0 15 0 0 0 0
00000 00 0000 00 0000000 00000
122
233
344
Timp maxim de execuµie pe test: 5 secunde
CAPITOLUL 38. ONI 2000 854
În ³ierul de intrare etajele sunt de sus în jos (primul etaj este lâng acoperi³)!
Pentru ecare soldat se face o parcurgere în adâncime (folosind recursivitatea) sau o parcurgere
în l µime (eventual folosind o structur de tip coad ) pentru un algoritm de tip ll (umplere).
58 Exit
59 End
60 Else
61 For i := 1 To 9 Do {incearca in cele 9 posibile directii}
62 If c[xx+Dx[i], yy+Dy[i], Nivel] and Com[Kapa].greu= Com[Kapa].greu
63 { then
64 if not(yy+dy[i] in p[nivel+1,xx+dx[i]])
65 } Then {daca trece prin aceasta camera}
66 Trece(Kapa, xx+Dx[i], yy+Dy[i], Nivel+1)
67 {incearca la nivelul urmator}
68 End;
69
70 Begin
71 Citeste_Date;
72 Assign(g, ’KOMMANDO.OUT’); ReWrite(g);
73 For Kapa := 1 To K Do {pentru fiecare din cei K Komandisti}
74 begin
75 if kapa mod 10=0 then
76 writeln(kapa);
77 fillchar(p,sizeof(p),0);
78 Trece(Kapa, Com[Kapa].x, Com[Kapa].y, 1); {plec de pe nivelul 1}
79 end;
80 For Kapa := 1 To K Do {contorizez cei ajunsi}
81 If Com[Kapa].Ajuns Then Inc(ContorAjunsi);
82 If ContorAjunsi >= T Then WriteLn(g, ’DA’)
83 Else WriteLn(g, ’NU’);
84 WriteLn(g, ContorAjunsi);
85 Close(g);
86 End.
44
45 Procedure Trece(Kapa: Byte; xx, yy, Nivel: Dim);
46 Var i: 1..9;
47 Begin
48 If Not Com[Kapa].Ajuns Then
49 If Nivel = h Then
50 Begin
51 Com[Kapa].Ajuns := True; {Kapa a ajuns !!! la parter}
52 Exit
53 End
54 Else
55 For i := 1 To 9 Do {incearca in cele 9 posibile directii}
56 If c[xx+Dx[i], yy+Dy[i], Nivel] and Com[Kapa].greu= Com[Kapa].greu
57 Then {daca trece prin aceasta camera}
58 Trece(Kapa, xx+Dx[i], yy+Dy[i], Nivel+1)
59 {incearca la nivelul urmator}
60 End;
61
62 Begin
63 Citeste_Date;
64 Assign(g, ’KOMMANDO.OUT’); ReWrite(g);
65 For Kapa := 1 To K Do {pentru fiecare din cei K Komandisti}
66 Trece(Kapa, Com[Kapa].x, Com[Kapa].y, 1); {plec de pe nivelul 1}
67 For Kapa := 1 To K Do {contorizez cei ajunsi}
68 If Com[Kapa].Ajuns Then Inc(ContorAjunsi);
69 If ContorAjunsi >= T Then WriteLn(g, ’DA’)
70 Else WriteLn(g, ’NU’);
71 WriteLn(g, ContorAjunsi);
72 Close(g);
73 End.
43 Ajuns := False
44 End;
45 Close(f)
46 End;
47
48 Procedure Trece;
49 Var Niv, i, j, xx: Byte;
50 Begin
51 FillChar(a, SizeOf(a), 0);
52 a[Com[Kapa].x, Com[Kapa].y] := 1;
53 For Niv := 2 To h Do
54 Begin
55 FillChar(b, SizeOf(b), 0);
56 For i := 1 To m Do
57 For j := 1 To n Do
58 If a[i, j] = 1 Then
59 For xx := 1 To 9 Do
60 If c[i+Dx[xx], j+Dy[xx], Niv-1] and
61 Com[Kapa].greu = Com[Kapa].greu
62 Then
63 b[i+Dx[xx], j+Dy[xx]] := 1;
64 a := b;
65 End;
66 For i := 1 To m Do
67 For j := 1 To n Do
68 If a[i, j] = 1 Then
69 Com[Kapa].Ajuns := true;
70 End;
71
72 Begin
73 Citeste_Date;
74 Assign(g, ’KOMMANDO.OUT’); ReWrite(g);
75 For Kapa := 1 To K Do {pentru fiecare din cei K Komandisti}
76 Trece; {plec de pe nivelul 1}
77 For Kapa := 1 To K Do {contorizez cei ajunsi}
78 If Com[Kapa].Ajuns Then Inc(ContorAjunsi);
79 If ContorAjunsi >= T Then WriteLn(g, ’DA’)
80 Else WriteLn(g, ’NU’);
81 WriteLn(g, ContorAjunsi);
82 Close(g);
83 End.
32 reset(fe);
33 {$I+}
34 if ioresult<>0 then eroare(’Fisier de iesire inexistent!’, 0);
35 {$I-}
36 readln(fe, s1);
37 {$I+}
38 if ioresult<>0 then eroare(’Fisier de iesire cu format incorect!’, 0);
39 end;
40
41 procedure citire_comisie;
42 var x,y,z:integer;
43 begin
44 assign(fc, paramstr(1)); reset(fc);
45 readln(fc, s2);
46 end;
47
48 begin
49 citire_comisie;
50 citire_concurent;
51 for i:=1 to 2 do s2[i]:=upcase(s2[i]);
52 if s1<>s2 then eroare(’Gresit!!!’, 0)
53 else
54 begin
55 ReadLn(fc, s3);
56 if seekeof(fe) then Eroare(’Fisier incomplet!!! ’,0)
57 else
58 begin
59 ReadLn(fe, s4);
60 if s3=s4 then Eroare(’Numar corect!!!’, 10)
61 else eroare(’Numar gresit!!!’, 0);
62 close(fe);
63 end;
64 close(fc)
65 end;
66 end.
33 codCamera=new int[h+1][m+1][n+1];
34 xk=new int[K+1];
35 yk=new int[K+1];
36 G=new int[K+1];
37
38 for(etaj=1;etaj<=h;etaj++)
39 for(x=1;x<=m;x++)
40 for(y=1;y<=n;y++)
41 {
42 st.nextToken();
43 codCamera[etaj][x][y]=(int)st.nval;
44 }
45
46 for(k=1;k<=K;k++)
47 {
48 st.nextToken(); G[k]=(int)st.nval;
49 st.nextToken(); xk[k]=(int)st.nval;
50 st.nextToken(); yk[k]=(int)st.nval;
51 }
52 }
53
54 static void rezolvare() throws IOException
55 {
56 int soldat;
57 for(soldat=1;soldat<=K;soldat++)
58 {
59 System.out.println(soldat);
60 aajunslaparter=false;
61 coboara(soldat,1,xk[soldat],yk[soldat]);
62 if(aajunslaparter) ns++;
63 }
64 }
65
66 static void coboara(int soldat, int etaj, int x, int y)
67 {
68 System.out.println(soldat+" "+etaj+" "+x+" "+y);
69 if((x<1)||(x>m)||(y<1)||(y>n)) return;
70 if(aajunslaparter) return;
71 if(etaj==h) {aajunslaparter=true; return;}
72 int i,j;
73 for(i=-1;i<=1;i++)
74 for(j=-1;j<=1;j++)
75 if((x+i>=1)&&(x+i<=m)&&(y+j>=1)&&(y+j<=n))
76 if(trece(G[soldat],codCamera[etaj][x+i][y+j]))
77 coboara(soldat, etaj+1, x+i, y+j);
78 }
79
80 static boolean trece(int a, int b) // a trece prin b ?
81 {
82 int k;
83 for(k=0;k<=7;k++)
84 if(((1<<k)&a)!=0) // pozitia k in a este 1
85 if(((1<<k)&b)==0) // pozitia k in b este 0
86 return false;
87 return true;
88 }
89
90 static void afisare() throws IOException
91 {
92 out=new PrintWriter(
93 new BufferedWriter(new FileWriter("kommando.out")));
94 if(ns>=T) out.println("DA"); else out.println("NU");
95 out.println(ns);
96 out.close();
97 }
98 }
83
84 static void coboara(int soldat, int etaj, int x, int y)
85 {
86 if((x<1)||(x>m)||(y<1)||(y>n)) return;
87 if(aajunslaparter) return;
88 if(etaj==h) {aajunslaparter=true; return;}
89 if(traseu[etaj][x][y]) return; // a mai trecut pe aici
90 traseu[etaj][x][y]=true;
91
92 int i,j;
93 for(i=-1;i<=1;i++)
94 for(j=-1;j<=1;j++)
95 if((x+i>=1)&&(x+i<=m)&&(y+j>=1)&&(y+j<=n))
96 if(trece(G[soldat],codCamera[etaj][x+i][y+j]))
97 coboara(soldat, etaj+1, x+i, y+j);
98 }
99
100 static boolean trece(int a, int b) // a trece prin b ?
101 {
102 int k;
103 for(k=0;k<=7;k++)
104 if(((1<<k)&a)!=0) // pozitia k in a este 1
105 if(((1<<k)&b)==0) // pozitia k in b este 0
106 return false;
107 return true;
108 }
109
110 static void afisare() throws IOException
111 {
112 out=new PrintWriter(
113 new BufferedWriter(new FileWriter("kommando.out")));
114 if(ns>=T) out.println("DA"); else out.println("NU");
115 out.println(ns);
116 out.close();
117 }
118 }
37 st.nextToken(); K=(int)st.nval;
38 st.nextToken(); T=(int)st.nval;
39
40 codCamera=new int[h+1][m+1][n+1];
41 ok=new boolean[h+1][m+1][n+1];
42
43 xk=new int[K+1];
44 yk=new int[K+1];
45 G=new int[K+1];
46
47 for(etaj=1;etaj<=h;etaj++)
48 for(x=1;x<=m;x++)
49 for(y=1;y<=n;y++)
50 {
51 st.nextToken();
52 codCamera[etaj][x][y]=(int)st.nval;
53 }
54
55 for(k=1;k<=K;k++)
56 {
57 st.nextToken(); G[k]=(int)st.nval;
58 st.nextToken(); xk[k]=(int)st.nval;
59 st.nextToken(); yk[k]=(int)st.nval;
60 }
61 }
62
63 static void rezolvare() throws IOException
64 {
65 int soldat,etaj,x,y;
66 for(soldat=1;soldat<=K;soldat++)
67 {
68 System.out.println(soldat);
69 curatTraseu();
70 aajunslaparter=false;
71 etaj=1;
72 x=xk[soldat];
73 y=yk[soldat];
74 coboara(soldat,etaj,x,y); // coboara din (x,y) si vecini
75 for(etaj=2;etaj<=h;etaj++)
76 for(x=1;x<=m;x++)
77 for(y=1;y<=n;y++)
78 if(ok[etaj][x][y]) coboara(soldat,etaj,x,y);
79 if(aajunslaparter) ns++;
80 }
81 }
82
83 static void coboara(int soldat, int etaj, int x, int y)
84 {
85 if(etaj==h) {aajunslaparter=true; return;}
86 int i,j;
87 for(i=-1;i<=1;i++)
88 for(j=-1;j<=1;j++)
89 if((x+i>=1)&&(x+i<=m)&&(y+j>=1)&&(y+j<=n))
90 if(trece(G[soldat],codCamera[etaj][x+i][y+j]))
91 ok[etaj+1][x+i][y+j]=true;
92 }
93
94 static boolean trece(int a, int b) // a trece prin b ?
95 {
96 int k;
97 for(k=0;k<=7;k++)
98 if(((1<<k)&a)!=0) // pozitia k in a este 1
99 if(((1<<k)&b)==0) // pozitia k in b este 0
100 return false;
101 return true;
102 }
103
104 static void curatTraseu()
105 {
106 int etaj, x, y;
107 for(etaj=1;etaj<=h;etaj++)
108 for(x=1;x<=m;x++)
109 for(y=1;y<=n;y++)
110 ok[etaj][x][y]=false;
111 }
112
CAPITOLUL 38. ONI 2000 863
64
65 static void rezolvare() throws IOException
66 {
67 int soldat,etaj,x,y;
68 for(soldat=1;soldat<=K;soldat++)
69 {
70 curatTraseu();
71 aajunslaparter=false;
72 etaj=0;
73 x=xk[soldat];
74 y=yk[soldat];
75 coboara(soldat,etaj,x,y);
76 for(etaj=1;etaj<=h;etaj++)
77 for(x=1;x<=m;x++)
78 for(y=1;y<=n;y++)
79 if(ok[etaj][x][y]) coboara(soldat,etaj,x,y);
80 if(aajunslaparter) ns++;
81 }
82 }
83
84 static void coboara(int soldat, int etaj, int x, int y)
85 {
86 if(etaj==h) {aajunslaparter=true; return;}
87 int i,j;
88 for(i=-1;i<=1;i++)
89 for(j=-1;j<=1;j++)
90 if((x+i>=1)&&(x+i<=m)&&(y+j>=1)&&(y+j<=n))
91 if(!traseu[etaj+1][x+i][y+j])
92 {
93 traseu[etaj+1][x+i][y+j]=true;
94 if(trece(G[soldat],codCamera[etaj+1][x+i][y+j]))
95 ok[etaj+1][x+i][y+j]=true;
96 }
97 }
98
99 static boolean trece(int a, int b) // a trece prin b ?
100 {
101 int k;
102 for(k=0;k<=7;k++)
103 if(((1<<k)&a)!=0) // pozitia k in a este 1
104 if(((1<<k)&b)==0) // pozitia k in b este 0
105 return false;
106 return true;
107 }
108
109 static void curatTraseu()
110 {
111 int etaj, x, y;
112 for(etaj=0;etaj<=h;etaj++)
113 for(x=1;x<=m;x++)
114 for(y=1;y<=n;y++)
115 {
116 ok[etaj][x][y]=false;
117 traseu[etaj][x][y]=false;
118 }
119 }
120
121 static void afisare() throws IOException
122 {
123 out=new PrintWriter(
124 new BufferedWriter(new FileWriter("kommando.out")));
125 if(ns>=T) out.println("DA"); else out.println("NU");
126 out.println(ns);
127 out.close();
128 }
129 }
Glosar
19
10 , 533 rst, 19, 42, 300, 439, 540
=, 402 fracµie continu , 329
³ir al frecvenµelor, 638 front(), 320, 439
³ir circular, 615
1LL, 320 gcd, 269
getchar(), 398
accumulate, 363 greedy, 439
aib, 435
AIB 2D, 433 ifndef, 172
algorimul lui Euclid, 609 inline, 117
algoritm de interclasare, 475 insert, 154, 320
algoritm de tip mars, 316 int32_t, 297, 298, 320
algoritm de tip greedy, 433 int64_t, 298
algoritmul lui Eratostene, 494 isdigit, 398
algoritmul lui Euclid, 329 iterator, 154
assert, 25
auto, 7, 269, 271, 300, 328, 344, 358 lambda, 282
auto&, 271, 300, 379 Lambda expressions, 56
lazy, 19
back(), 298, 320, 366, 439 liniarizare matrice, 608
begin(), 19, 56, 154, 297, 298, 300, 320, 322, liniarizarea matricei, 440
366, 435, 439, 474 lower_bound, 7, 474
binarySearch, 42
bitset, 98, 414, 436 make_pair, 6, 540
bool, 154, 321, 322, 358, 405, 474 matrice, 334
bool operator, 435 mediana ³irului, 629
brute-force, 311 memset, 82, 106, 258
min, 398
c utare binar , 79, 81, 316, 336, 367, 378, 389, min_element, 363, 366
394, 433, 462, 476, 524, 615 multiplu comun, 609
char, 363, 366, 398
ciclu, 608 nth_element, 477
Ciurul lui Erastotene, 588 num rul de divizori, 221
Ciurul lui Eratostene, 490 numeric_limits, 298
ciurul lui Eratostene, 292, 387, 411, 414, 543 <int>::max(), 298
clear(), 300
cmmdc, 375, 376 operator, 322, 379, 405
const, 322, 344, 379, 405, 435 or (operator alternativ), 58
const auto&, 435 ordine lexicograc , 439
count, 300
pair, 19, 40, 42, 300, 439, 540
deque, 439 pop(), 540
descompunere în factori primi, 221, 292 pop_back(), 366, 439
directie, 46 pop_front(), 439
distanµa Manhattan, 339 prexe, 394
doi pointeri, 395 principiul lui Dirichlet, 400
programare dinamic , 433, 436
emplace_back, 19 push, 540
empty(), 439, 540 push_back, 269, 271, 297, 300, 313, 320, 322,
end(), 19, 154, 297, 298, 300, 320, 322, 366, 435, 344, 435, 439, 474
439, 474 push_front, 439
erase, 154, 298, 474
exponenµiere logaritmic , 602 rbegin(), 25, 300
865
GLOSAR 866
unique, 7, 474
unsigned, 117
upper_bound, 398, 478
using, 321
867
BIBLIOGRAFIE 868
[26] Od gescu, I.; Metode ³i tehnici de programare, Ed. Computer Lobris Agora, Cluj, 1998
[27] Popescu Anastasiu, D.; Puncte de articulaµie ³i punµi în grafuri, Gazeta de Informatic nr.
5/1993
[33] Skiena S.S., Revilla M.A.; Programming challenges - The Programming Contest Training
Manual, Springer, 2003
[34] Tomescu, I.; Probleme de combinatoric ³i teoria grafurilor, Editura Didactic ³i Pedagogic ,
Bucure³ti, 1981
[35] Tomescu, I.; Leu, A.; Matematic aplicat în tehnica de calcul, Editura Didactic ³i Pedago-
gic , Bucure³ti, 1982
[37] Vi³inescu, R.; Vi³inescu, V.; Programare dinamic - teorie ³i aplicaµii; GInfo nr. 15/4 2005
[38] Vlada, M.; Conceptul de algoritm - abordare modern , GInfo, 13/2,3 2003
[40] Weis, M.A.; Data structures and Algorithm Analysis, Ed. The Benjamin/Cummings Pu-
blishing Company. Inc., Redwoods City, California, 1995.
[42] Wirth N.; Algorithms + Data Structures = Programs, Prentice Hall, Inc 1976