Documente Academic
Documente Profesional
Documente Cultură
Gimnaziu + EJOI
2023-4
ALGORITMI ELEMENTARI
+
PROBLEME DE INFORMATICĂ
date la olimpiade
EJOI
ı̂n
Dacă ştii să rezolvi problemele date ı̂n ultimii 10-20 de ani
atunci vei şti să rezolvi problemele care se vor da ı̂n acest an!
https://www.scribd.com/user/552245048/Adi-Rabaea
2023-4-26
Figura 1: Descompunerea canonică a lui f
”O imagine valorează
cât 1000 de cuvinte!” 1
x1 x1
x3 x3
x2 x2
elevii f = aleg ”şeful” elevi
ı̂n clasă ı̂n clasă
fac echipe echipei
y1 y1
y3 y3
y2 y2
1
I.d.k.: ”I don’t know who the author is.”
Dedication
( in ascending order! )
2
https://www.femalefirst.co.uk/books/carol-lynne-fighter-1034048.html
3
https://otiliaromea.bandcamp.com/track/dor-de-el
4
https://en.wikipedia.org/wiki/To_be,_or_not_to_be
5
https://www.youtube.com/watch?v=eMtcDkSh7fU
ii
Prefaţă
Stilul acestor cărţi este ... ca şi cum aş vorbi cu nepoţii mei (şi chiar cu mine ı̂nsumi!) ... ı̂ncercând
ı̂mpreună să găsim o rezolvare cât mai bună pentru o problemă dată la olimpiadă.
Ideea, de a scrie aceste culegeri de probleme date la olimpiadele de informatică, a apărut acum
câţiva ani când am ı̂ntrebat un student (care nu reuşea să rezolve nişte probleme foarte simple):
”Ce te faci dacă un elev, care ştie că eşti student şi că studiezi şi informatică, te roagă, din când ı̂n
când, să-l ajuţi să rezolve câte o problemă de informatică dată la gimnaziu la olimpiadă, sau pur
şi simplu ca temă de casă, şi tu, aproape de fiecare dată, nu ı̂l poţi ajuta? Eu cred că nu este prea
bine şi poate că ... te faci ... de râs!” Pe vremea mea (!), când eram elev de gimnaziu, un student
era ca un fel de ... zeu! Cu trecerea anilor am ı̂nţeles că nu este chiar aşa! Şi ı̂ncă ceva: nu am
reuşit să ı̂nţeleg de ce, atunci când cineva nu poate să rezolve corect o problemă de informatică
de clasa a 6-a, dată la olimpiada de informatică sau ca temă de casă, foloseşte această scuză: ”eu
nu am făcut informatică ı̂n liceu!” şi acest cineva este ”zeul” sau ”zeiţa” despre care vorbeam!.
6
Sunt convins că este important să studiem cu atenţie cât mai multe probleme rezolvate! . Cred
că sunt utile şi primele versiuni ale acestor cărţi ... ı̂n care sunt prezentate numai enunţurile şi
indicaţiile ”oficiale” de rezolvare. Acestea se găsesc ı̂n multe locuri; aici ı̂ncerc să le pun pe ”toate
la un loc”! Fiecare urcă spre vârf ... cât poate! Sunt multe poteci care duc spre vârf iar această
carte este ... una dintre ele!
Limbajul de programare se alege ı̂n funcţie de problema pe care o avem de rezolvat. Cu nişte
ani ı̂n urmă alegerea era mai simplă: dacă era o problemă de calcul se alegea Fortran iar dacă era
o problemă de prelucrarea masivă a datelor atunci se alegea Cobol. Acum alegerea este ceva mai
7 8
dificilă! :-) Vezi, de exemplu, IOI2020 şi IOI2019 , IOI2015 .
Cred că, de cele mai multe ori, este foarte greu să gândim ”simplu” şi să nu ”ne complicăm”
atunci când cautăm o rezolvare pentru o problemă dată la olimpiadă. Acesta este motivul pentru
care vom analiza cu foarte mare atenţie atât exemplele date ı̂n enunţurile problemelor cât şi
”restricţiile” care apar acolo (ele sigur ”ascund” ceva interesant din punct de vedere al algoritmului
9
de rezolvare!) .
Am ı̂nceput câteva cărţi (pentru clasele de liceu) cu mai mulţi ani ı̂n urmă, pentru perioada
2000-2007 ([29] - [33]), cu anii ı̂n ordine crescătoare!). A urmat o pauză de câţiva ani (destul de
mulţi!). Am observat că acele cursuri s-au ”ı̂mprăştiat” un pic ”pe net” ([48] - [56])! Încerc acum
să ajung acolo unde am rămas ... plecând mereu din prezent ... până când nu va mai fi posibil ...
aşa că, de această dată, anii sunt ı̂n ordine ... descrescătoare! :-)
”Codurile sursă” sunt cele ”oficiale” (publicate pe site-urile olimpiadelor) sau publicate pe alte
site-uri (dacă mi s-a părut că sunt utile şi se poate ı̂nvăţa câte ceva din ele).
Pentru liceu perioada acoperită este de ”azi” (până când va exista acest ”azi” pentru mine!)
până ı̂n anul 2000 (aveam deja perioada 2000-2007!).
Pentru gimnaziu perioada acoperită este de ”azi” până ı̂n anul 2010 (nu am prea mult timp
10
disponibil şi, oricum, calculatoarele folosite la olimpiade ı̂nainte de 2010 erau ceva mai ’slabe’ şi
iii
12
depăşeşte pragul ”exascale”! (1.102 Exaflop/s). ”Peta” a fost depăşit ı̂n 2008, ”tera” ı̂n 1997,
13
”giga” ı̂n 1972. . Pentru ce a fost mai ı̂nainte, vezi https://en.wikipedia.org/wiki/Li
st_of_fastest_computers.
14
O mică observaţie: ı̂n 2017 a fost prima ediţie a olimpiadei EJOI ı̂n Bulgaria şi ... tot
15
ı̂n Bulgaria a fost şi prima ediţie a olimpiadei IOI ı̂n 1989. Dar ... prima ediţie a olimpiadei
16
IMO (International Mathematical Olympiad) a fost ı̂n România ı̂n 1959. Tot ı̂n România s-au
ţinut ediţiile din anii 1960, 1969, 1978, 1999 şi 2018. Prima ediţie a olimpiadei BOI (Balkan
Olympiad in Informatics) a fost ı̂n România ı̂n 1993 la Constanţa. Prima ediţie a olimpiadei
CEOI (Central-European Olympiad in Informatics) a fost ı̂n România ı̂n 1994 la Cluj-Napoca.
Revenind la ... “culegerile noastre” ... mai departe, probabil, va urma completarea unor
informaţii ı̂n ”Rezolvări detaliate” ... pentru unele probleme numai (tot din cauza lipsei timpului
necesar pentru toate!). Prioritate vor avea problemele de gimnaziu (nu pentru că sunt mai ’uşoare’
ci pentru că ... elevii de liceu se descurcă şi singuri!). Acum, ı̂n martie 2022, am ı̂nceput şi
redactarea unei culegeri de probleme date la bacalaureat ı̂n ultimii câţiva ani (câţi voi putea!).
Îmi aduc aminte că exista o interesantă vorbă de duh printre programatorii din generaţia mea:
”nu se trage cu tunul ı̂ntr-o muscă” . Sensul este: nu se scrie un cod complicat dacă se
poate scrie un cod simplu şi clar! Asta ı̂ncerc eu ı̂n ”Rezolvări detaliate”.
Vom ı̂ncerca, ı̂mpreună, şi câteva probleme de ... IOI ... dar asta este o treabă ... nu prea
uşoară! Cred totuşi că este mai bine să prezint numai enunţuri ale problemelor date la IOI ı̂n
ultimii câţiva ani! (asta aşa, ca să vedem cum sunt problemele la acest nivel!). Cei care ajung
acolo sau vor să ajungă acolo (la IOI) sigur nu au nevoie de ajutorul meu! Se descurcă singuri!
”ALGORITMI utili la olimpiadele de informatică”, separat pentru gimnaziu şi liceu, sper să
fie de folos, aşa cum cred că sunt [1] - [28], [34] - [47], [57] - [83], ... şi multe alte cărţi şi site-uri!.
Ar fi interesant să descoperim noi ı̂nşine cât mai mulţi algoritmi ... ı̂n loc să-i ı̂nvăţăm pur şi
simplu!
O altă mică observaţie: ce am strâns şi am scris ı̂n aceste cărţi
se adresează celor interesaţi de aceste teme! Nu cârcotaşilor! Sunt
evidente sursele ”de pe net” (şi locurile ı̂n care au fost folosite) aşa
că nu sunt necesare ”ghilimele anti-plagiat”, referinţe şi precizări
suplimentare la fiecare pas!
Şi un ultim gând: criticile şi sfaturile sunt utile dacă au valoare!
Dacă sunt numai aşa ... cum critică lumea la un meci de fotbal ...
sau cum, pe bancă ı̂n parc, ”ı̂şi dă cu părerea” despre rezolvarea
problemelor economice ale ţării ... atunci ... !!!
17
”I’m only responsible for what I say, not for what you understand.”
Adrese interesante (rezultatele elevilor români):
https://stats.ioinformatics.org/halloffame/
https://stats.ioinformatics.org/tasks/
http://stats.ioinformatics.org/results/ROU
Adresele acestor cursuri:
https://www.scribd.com/user/550183580/Adrian-Rabaea
https://www.scribd.com/user/552245048/Adi-Rabaea
https://drive.google.com/drive/folders/1hC5PZuslCdS95sl37SW46H-qy59GRDGZ
Adrese utile (programe şcolare):
http://programe.ise.ro/Portals/1/Curriculum/Progr_Lic/TH/Informatica_teoretic_vocatio
nal_intensiv_clasa%20a%20IX-a.pdf
http://programe.ise.ro/Portals/1/Curriculum/Progr_Lic/TH/Informatica_teoretic_vocatio
nal_intensiv_clasa%20a%20X_a.pdf
http://programe.ise.ro/Portals/1/Curriculum/Progr_Lic/TH/Informatica_teoretic_vocatio
nal_intensiv_clasa%20a%20XI-a.pdf
18
”I want to thank God most of all because without God I wouldn’t be able to do any of this.”
Adrian R.
18
I.d.k.: ”I don’t know who the author is.”
v
Despre autor
19
nume: Răbâea Aurel-Adrian, 18.03.1953 - ...
vi
Dhawan Sanjeev, Kulvinder Singh, Eduard-Marius Craciun, Adrian Răbâea, Amit Batra;
Next-Cart Recommendation by Utilizing Personalized Item Frequency Information in Online
Web Portals, Neural Processing Letters, 2023; https://doi.org/10.1007/s11063-023-11207-2
https://link.springer.com/article/10.1007/s11063-023-11207-2
https://scholar.google.com/citations?user=-sSE_1wAAAAJ&hl=en
https://www.scopus.com/authid/detail.uri?origin=resultslist&authorId=56122389200&zone=
http://www.facebook.com/adrian.rabaea
Cuprins
Prefaţă iii
Cuprins viii
2 Probleme elementare 21
2.1 Deplasarea cifrelor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.1.1 Deplasarea cifrelor spre stânga . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.1.2 Deplasarea cifrelor spre dreapta . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.2 Contor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.2.1 Introducere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.2.2 Mărire cu 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.2.3 Micşorare cu 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.2.4 Predecesor şi succesor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3 Ordine lexicografică . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.3.1 Cel mai mic număr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.3.2 Cel mai mare număr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.3.3 Succesorul unui număr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
viii
2.3.4 Predecesorul unui număr . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3 Programare C+++ 26
3.1 Structura unui program in C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.1.1 Şablon simplu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.1.2 namespace std; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.1.3 Pregătire suport pentru fişiere . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.1.4 Acces la fişiere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.1.5 Citire şi scriere folosind fişiere . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.1.6 Comentarii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.1.7 Reprezentarea internă a datelor ı̂n fişierele .txt . . . . . . . . . . . . . . . . 39
3.1.8 Două citiri din fişier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.1.9 Câteva explicaţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.1.10 Variabilă neiniţializată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.1.11 Alegerea identificatorilor (numelor) . . . . . . . . . . . . . . . . . . . . . . . 44
3.2 Alfabetul limbajului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.2.1 Un program util . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.2.2 Coduri de control şi spaţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.2.3 Caracterele printabile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.2.4 Codurile alfanumerice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.2.5 Simboluri ASCII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.3 Alocarea variabilelor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.3.1 Puţină istorie! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.3.2 ’Big endian’ sau ’Little endian’ . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.3.3 Afişare ı̂n ’hexa’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.3.4 Afişare ı̂n ’binar’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.3.5 Alocarea variabilelor ı̂n spaţiul de memorie . . . . . . . . . . . . . . . . . . 52
3.3.6 MSB şi LSB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.4 Instrucţiuni de decizie - structuri elementare de control . . . . . . . . . . . . . . . 57
3.4.1 Instrucţiunea if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.4.2 Instrucţiunea case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.4.3 Operatorul condiţional (ternar) ? : . . . . . . . . . . . . . . . . . . . . . . 57
3.5 Instrucţiuni repetitive - structuri elementare de control . . . . . . . . . . . . . . . . 57
3.5.1 Instrucţiunea for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.5.2 Instrucţiunea while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.5.3 Instrucţiunea do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.6 Instrucţiuni de salt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.6.1 Instrucţiunea continue; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.6.2 Instrucţiunea break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.7 Funcţii utile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.7.1 getchar(); . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.7.2 system(“PAUSE”); . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.8 Tipuri predefinite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.8.1 Character types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.8.2 Numerical integer types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.8.3 Floating-point types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.8.4 Boolean type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Index 510
Bibliografie 514
1.1 Monede: 8, 4, 2, 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Monede: 11 = 8 + 2 + 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Un program ciudat ı̂n Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.4 Un program ciudat ı̂n C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.5 Un program ciudat ı̂n Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.6 Calculator Standard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.7 Selectare ”Programmer” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.8 50 000 in bazele 16, 10, 8 şi 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.9 QWORD = 64 biţi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.10 DWORD = 32 biţi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.11 WORD = 16 biţi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.12 BYTE = 8 biţi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.13 QWORD ultimul byte din 50 000 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.14 Click pe 0 l-a schimbat ı̂n 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.15 DWORD valoare 208 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.16 WORD valoare 208 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.17 BYTE valoare -48 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.18 QWORD valoare 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.19 BYTE valoare 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.20 BYTE valoare 127 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.21 BYTE valoare -1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.22 Click pe poziţia indicată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.23 -128 se transformă ı̂n -120 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.24 BYTE 100 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.25 BYTE -100 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.26 Cercul reprezentării ı̂n cod complementar . . . . . . . . . . . . . . . . . . . . . . . . 17
xiv
3.16 f05.in vizualizat cu WinHex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.17 fişierul cu datele de ieşire f05.out şi rezultatul afişat pe ecran . . . . . . . . . . . . 38
3.18 fişierul f05.in ı̂n WinHex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.19 Dimensiuni fişiere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.20 Execuţie p05a.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.21 Alocarea spaţiului de memorie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.22 Poziţia capului de citire după prima citire . . . . . . . . . . . . . . . . . . . . . . . 42
3.23 Poziţia capului de citire după a doua citire . . . . . . . . . . . . . . . . . . . . . . 43
3.24 Poziţia capului de citire după a treia citire . . . . . . . . . . . . . . . . . . . . . . . 43
3.25 Execuţie p05a.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.26 isctrl+isspace+isblank . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.27 isprint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.28 isalnum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.29 simboluri ASCII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.30 Big or Little endian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.31 Big si Little endian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.32 Afişare hexa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.33 Afişare binar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.34 Plimbare prin biţi! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.35 MSB+LSB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.36 MSB endian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.37 LSBendian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.38 LSBendian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
xvii
Lista programelor
1.3.1 ciudat.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3.2 ciudat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3.3 ciudat.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.5.1 ascii litere mici.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.5.2 ascii litere mari.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.5.3 ascii cifre.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.5.4 whitespace.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.0.1 p00.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.0.2 p00.asm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.0.3 secvenţă de cod ’cpp’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.1.1 p01 structura unui program C++ . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.1.2 p02 namespace std; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.1.3 p03 fstream şi iostream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.1.4 p04 ifstream şi ofstream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.1.5 p05 fin şi fout şi cout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.1.6 p05a citire dublă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.1.7 p00x1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.1.8 p05b variabilă neiniţializată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.1.9 p06 nume pentru variabile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.2.1 ascii comentat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.3.1 Big or Little endian.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.3.2 afisare hexa.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.3.3 afisare binar.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.3.4 adrese in memorie.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.3.5 show bytes in memory.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.4.1 p07 instrucţiunea if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.5.1 p08 instrucţiunea for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.5.2 p09 instrucţiunea while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.5.3 p10 instrucţiunea do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.6.1 p11 instrucţiunea continue; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.6.2 p12 instrucţiunea break; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.7.1 p13 instrucţiunea getchar(); . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.7.2 p14 instrucţiunea system(“PAUSE”); . . . . . . . . . . . . . . . . . . . . . . . 59
4.1.1 .cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.1.2 .cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.5.1 .cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.5.2 .cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.5.3 .cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
6.1.1 EJOI2022 Perechi ModelSolution.cpp . . . . . . . . . . . . . . . . . . . . . . . . 72
6.1.2 EJOI2022 Perechi check.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
6.2.1 EJOI2022 Root rw 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
6.2.2 EJOI2022 Root check.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
6.3.1 EJOI2022 Tree mhq.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
6.3.2 EJOI2022 Tree check.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
6.4.1 EJOI2022 game fast power 2 m.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 91
6.4.2 EJOI2022 game check.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
6.5.1 EJOI2022 permutations solution.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 97
6.5.2 EJOI2022 permutations check.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
6.6.1 EJOI2022 LCS 16774096.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
xviii
6.6.2 EJOI2022 LCS check.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
8.1.1 checkerFountain.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
8.1.2 Fountain-979362.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
8.1.3 Fountain-981117.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
8.1.4 Fountain-981322.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
8.1.5 Fountain-983271.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
8.1.6 Fountain-985016.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
8.1.7 Fountain-992243.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
8.1.8 Fountain-992296.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
8.1.9 Fountain-994277.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
8.2.1 triangulation-981145.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
8.2.2 triangulation-981153.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
8.2.3 triangulation-981926.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
8.2.4 triangulation-983329.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
8.2.5 triangulation-985775.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
8.3.1 exam-981110.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
8.3.2 exam-982347.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
8.3.3 exam-984751.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
8.3.4 exam-985120.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
8.3.5 exam-986828.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
8.3.6 exam-992381.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
8.4.1 checkerXorSort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
8.4.2 xorsort-980965.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
8.4.3 xorsort-982930.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
8.4.4 xorsort-986772.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
9.1.1 216711-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
9.1.2 217942-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
9.1.3 229739-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
9.1.4 232150-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
9.1.5 232196-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
9.1.6 237579-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
9.1.7 237607-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
9.1.8 237667-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
9.1.9 237671-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
9.1.10 240337-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
9.1.11 242103-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
9.1.12 246139-rack.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
9.2.1 218063-XORanges.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
9.2.2 220350-XORanges.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
9.2.3 229737-XORanges.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
9.2.4 236349-XORanges.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
9.2.5 237576-XORanges.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
9.2.6 237584-XORanges.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
9.2.7 242110-XORanges.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
9.2.8 246138-XORanges.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
9.2.9 246793-XORanges.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
9.2.10 checkerXORanges.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
9.3.1 229752-covering.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
9.3.2 248792-covering.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
9.4.1 218070-adventure.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
9.4.2 218553-adventure.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
9.4.3 226630-adventure.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
9.4.4 226699-adventure.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
9.4.5 229759-adventure.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
9.4.6 232209-adventure.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
9.4.7 240339-adventure.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
9.4.8 242112-adventure.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
9.4.9 244272-adventure.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
9.6.1 218172-colouring.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
9.6.2 226737-colouring.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
9.6.3 250194-colouring.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
10.1.1 ds n2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
10.1.2 ds n2 other.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
10.1.3 gr ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
10.1.4 ig n2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
10.1.5 isaf ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
10.1.6 11899245-hills.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
10.1.7 56159794-hills.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
10.1.8 81469343-hills.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
10.1.9 88103111-hills.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
10.1.10 Hills1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
10.1.11 checkerHills.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
10.2.1 passports pkun.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
10.2.2 41334650-passports.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
10.2.3 41335815-passports.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
10.2.4 48114130-passports.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
10.2.5 48115887-passports.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
10.2.6 52626176-passports.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
10.2.7 56188505-passports.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
10.2.8 79747607-passports.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
10.2.9 checkerPassports.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
10.3.1 rg wa.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
10.3.2 rg wa2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
10.3.3 solve.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
10.3.4 ds ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
10.3.5 gr ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
10.3.6 isaf ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
10.3.7 rg ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
10.3.8 11899245-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
10.3.9 56157022-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
10.3.10 86481283-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
10.3.11 86488789-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
10.3.12 86816257-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
10.3.13 86816797-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
10.3.14 87021285-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
10.3.15 87201594-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
10.3.16 87466173-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
10.3.17 87522420-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
10.3.18 88013224-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
10.3.19 88040747-chemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
10.3.20 chem1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
10.3.21 checkChemistry.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
10.4.1 ds diams.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
10.4.2 ds zhfs.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
10.4.3 full random.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
10.4.4 many random.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
10.4.5 prime tree pashka.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
10.4.6 print id.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
10.4.7 sol 100.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
10.4.8 solve is.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
10.4.9 solve is no local.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
10.4.10 solve qoo2p5.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
10.4.11 checkPrime-tree.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
10.5.1 cycle sort ad.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
10.5.2 gr ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
10.5.3 ig ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
10.5.4 isaf ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
10.5.5 isaf ok slowio.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
10.5.6 40973023-cycle sort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
10.5.7 41148878-cycle sort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
10.5.8 43081231-cycle sort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
10.5.9 67068459-cycle sort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
10.5.10 75463698-cycle sort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
10.5.11 87786210-cycle sort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
10.5.12 checkCycle-sort.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
11.1.1 482109.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
11.1.2 483136-magic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
11.1.3 484114-magic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
11.1.4 484759-magic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
11.1.5 484817-magic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
11.1.6 1703927-magic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
11.1.7 1748766-magic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
11.1.8 2119774-magic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
11.1.9 2210797-magic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
11.2.1 482015-particles.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
11.2.2 482536-particles.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
11.2.3 482782-particles.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
11.2.4 483295-particles.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
11.2.5 484328-particles.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
11.2.6 485011-particles.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
11.2.7 1497611-particles.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
11.2.8 1628810-particles.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
11.2.9 checkerParticles.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
11.3.1 481436-six.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394
11.3.2 482515-six.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
11.3.3 505367-six.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
11.3.4 1275534-six.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
11.3.5 1633337-six.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
11.3.6 1709178-six.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
11.3.7 2123900-six.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
11.3.8 2219732-six.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
11.4.1 486658-camel.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
11.4.2 486713-camel.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
11.4.3 502953-camel.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
11.4.4 2220355-camel.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
11.4.5 2659930-camel.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
11.4.6 checkerCamel.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
11.5.1 486102-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
11.5.2 486224-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
11.5.3 486736-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
11.5.4 487126-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
11.5.5 489869-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
11.5.6 501765-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
11.5.7 1082259-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
11.5.8 1549152-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
11.5.9 1573243-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445
11.5.10 1593395-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446
11.5.11 1696625-experience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
11.5.12 checkerExperience.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
11.6.1 486962-game.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
11.6.2 487418-game.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452
11.6.3 487442-game.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
11.6.4 488403-game.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
11.6.5 488741-game.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
11.6.6 490435-game.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
11.6.7 507893-game.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
11.6.8 594280-game.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
11.6.9 1173310-game.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
11.6.10 1275946-game.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460
11.6.11 checkerGame.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
C.4.1exponentiere rapida1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
C.4.2exponentiere rapida2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491
C.4.3exponentiere rapida3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492
C.4.4exponentiere rapida MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492
C.5.1exponentiere naiva MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493
C.5.2exponentiere rapida MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494
C.6.1secventa cod.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
D.2.1cautare binara-v1-iterativ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497
D.2.2cautare binara-v1-recursiv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498
D.3.1cautare binara-v2-iterativ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499
D.3.2cautare binara-v2-recursiv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 500
D.4.1cautare binara-v3-iterativ.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501
D.4.2cautare binara-v3-recursiv.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
Part I
1
Capitolul 1
Noţiuni elementare
1.1 Numărare
Să numărăm: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ... Asta ı̂n baza 10, baza noastră de numeraţie!
Să notăm cu B10 mulţimea cifrelor pe care le folosim.
Deci
B10 r0, 1, 2, 3, 4, 5, 6, 7, 8, 9x
cifrele fiind scrise ı̂n ordine crescătoare.
Cifra cea mai mică este 0 (zero).
Cifra cea mai mare este 9, iar baza noastră este 10.
Observaţia 1. Cifra cea mai mare este egală cu ”baza-1”.
Să continuăm numărarea: 13, 14, 15, 16, 17, ...
Observaţia 2. Numai ultima cifră se modifică (se măreşte).
Să continuăm să numărăm: 18, 19, 20, ...
Observaţia 3. Dacă ultima cifă (poziţia din dreapta) este 9 (cea mai mare cifră) urmează 0 (zero
pe poziţia respectivă) şi se măreşte cu 1 cifra din stânga (poziţia zecilor, ı̂n cazul nostru!)
Este ca şi cum am avea 3 cutii:
1
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.1. NUMĂRARE 2
şi primim o bancnotă de 1 leu pe care trebuie să o punem ı̂n cutia corectă. Dar ... acolo sunt
deja 9 bancnote şi cu bancnota asta se fac 10 bancnote!
Luăm toate cele 10 bancnote de 1 leu ... cutia 0 rămn̂e goală ... deci 0 (zero) acolo ... mergem
la bancă şi schimbăm cele 10 bancnote de 1 leu ı̂n o bancnotă de 10 lei ... venim acasă şi punem
bancnota de 10 lei ı̂n cutia corectă. Dar ... ı̂n cutia 1 erau deja 9 bancnote de 10 lei şi cu această
bancnotă se fac ... 10 bancnote de 10 lei.
Suntem obligaţi să le luăm pe toate cele 10 bancnote ... cutia 1 rămâne goală (la fel este şi
cutia 0, să nu uităm!) ... deci 0 (zero) acolo ... mergem la bancă şi schimbăm cele zece bancnote
de 10 lei ı̂ntr-o bancnotă de 100 de lei ... venim acasă şi punem bancnota de 100 lei ı̂n cutia
corectă. Astfel, cutia 2 conţine acum două bancnote de câte 100 de lei, cutia 1 conţine acum zero
bancnote de câte 10 de lei şi cutia 0 conţine acum zero bancnote de câte 1 leu.
Observaţia 5. La fiecare pas (când mai primim câte 1 leu) vom ı̂ncerca să mărim cifra din
dreapta. Dacă reuşim ... o mărim şi gata ... dar ... dacă acolo este cea mai mare cifră atunci
vom pune zero ı̂n locul ei şi ı̂ncercăm să mărim cifra/poziţia imediat la stânga ... şi tot aşa mai
departe ... până când reuşim (ı̂n stânga numărului sunt ... multe zerouri ... care nu se scriu când
nu avem nevoie de ele dar ... sunt acolo atunci când avem nevoie de ele)!
Aceste observaţii sunt simple şi valabile ı̂n orice bază! De exemplu ı̂n B2 şi B16 ... (ı̂nlocuind
10 cu 2, 16, ...).
Evident, atunci când vrem să luăm o bancnotă, contează foarte mult care este poziţia cutiei
din care vom lua acea bancnotă! Acesta este motivul pentru care se spune: ”Sistemul zecimal este
27
un sistem de numeraţie poziţional, având baza 10” .
27
https://ro.wikipedia.org/wiki/Sistem_zecimal
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.2. CONVERSII ALE DATELOR NUMERICE3
B10 r0, 1, 2, 3, 4, 5, 6, 7, 8, 9x
29
vom ı̂nţelege uşor de ce ı̂n sistemul de numeraţie ı̂n baza 2 se folosesc cifrele
B2 r0, 1x
30
şi ı̂n sistemul de numeraţie ı̂n baza 16 se folosesc ”cifrele”
La baza 16 apare o problemă: de exemplu, ı̂n scrierea 112 pot să ı̂nteleg că este vorba de alipirea
cifrelor 1, 1, 2 sau 1, 12 sau 11, 2. Pentru a elimina această situaţie, cifrele considerate pentru
sistemul de numeraţie ı̂n baza 16 au fost notate astfel:
B16 r0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F x.
monedă de 2 bani, de fiecare dată când le ı̂ntâlnim ı̂n parcurgerea monedelor de la stânga
la dreapta.
În a doua etapă (notată E2 ı̂n figură) vom schimba două monede alăturate de 2 bani, cu o
monedă de 4 bani, de fiecare dată când le ı̂ntâlnim ı̂n parcurgerea monedelor de la stânga
la dreapta.
În a treia etapă (notată E3 ı̂n figură) vom schimba două monede alăturate de 4 bani, cu o
monedă de 8 bani, de fiecare dată când le ı̂ntâlnim ı̂n parcurgerea monedelor de la stânga
la dreapta.
...
Vom proceda ı̂n acest mod până când nu mai avem de făcut schimbări de monede!
k1
Algoritm: pentru etapa cu numărul k vom schimba două monede alăturate de 2 bani, cu o
k
monedă de 2 bani, de fiecare dată când le ı̂ntâlnim ı̂n parcurgerea monedelor de la stânga la
dreapta, pentru k 1, 2, 3, ... până când nu mai avem de făcut schimbări de monede!
Observaţie: Orice monedă poate apărea cel mult o dată la sfârşitul acestui ’joc’ ! În exemplul
de mai sus nu a apărut, ı̂n finalul jocului, moneda de 4 bani. Întotdeauna, la finalul acestui ’joc’,
numărul de apariţii este 0 sau 1 pentru orice tip de monedă!
Numărul de apariţii al monedei de 8 bani este 1
Putem scrie aceste numere (’de apariţie’) de la stânga spre dreapta astfel: 1011 2 (este chiar
scrierea binară a lui 11 10 (unsprezece ı̂n baza 10). Cel mai din stânga este numărul de apariţii
al monedei cu valoarea cea mai mare (aceasta sigur apare, deci sigur scrierea ı̂ncepe cu 1). Cel
mai din dreapta este numărul de apariţii al monedei cu valoarea cea mai mică (poate fi 1 sau 0).
Iniţial am avut 11 monede (valoarea a fost de 11 bani) iar la final numai 3 monede (dar valoarea
36
ı̂n bani nu s-a schimbat!). Se pare că scopul acestui joc (de fapt este un mic algoritm ) a fost
să obţinem un număr cât mai mic de monede (fără să modificăm valoarea banilor pe care i-am
37
avut iniţial)! Pentru că monedele nu au fost alese oricum, ci sunt puteri consecutive ale lui 2,
rezultatul acestui ’joc’-’algoritm’ este, de fapt, conversia unui număr din baza 10 ı̂n baza 2. Un
38
mic secret: strategia folosită ı̂n acest joc se numeşte strategie ’bottom-up’.
36
https://ro.wikipedia.org/wiki/Algoritm
37
https://ro.wikipedia.org/wiki/Putere_(matematic%C4%83)
38
https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.2. CONVERSII ALE DATELOR NUMERICE5
Pentru că este foarte greu să folosim desene şi pentru monedele de 16 bani, 32 de bani, 64 de
bani, ..., vom folosi numai valorile lor, adică: 1, 2, 4, 8, 16, 32, 64, 128, ...
Jocul 2: Să presupunem că, iniţial, avem 111 monede de câte 1 ban şi vrem să le schimbăm
cu monede de valori cât mai mari (astfel vom avea cât mai puţine monede dar valoarea lor va fi
aceeaşi cu cea iniţială, 111 bani).
Ce monedă să folosim când avem 111 bani? Desigur 128 este prea mare dar 64 se poate folosi.
Mai rămân de schimbat 111-64 = 47 de bani.
Ce monedă să folosim când avem 47 de bani? Desigur 64 este prea mare dar 32 se poate folosi.
Mai rămân de schimbat 47-32 = 15 bani.
Ce monedă să folosim când avem 15 bani? Desigur 16 este prea mare dar 8 se poate folosi.
Mai rămân de schimbat 15-8 = 7 bani.
Ce monedă să folosim când avem 7 bani? Desigur 8 este prea mare dar 4 se poate folosi.
Mai rămân de schimbat 7-4 = 3 bani.
Ce monedă să folosim când avem 3 bani? Desigur 4 este prea mare dar 2 se poate folosi.
Mai rămân de schimbat 3-1 = 1 ban.
Ce monedă să folosim când avem 1 ban? Desigur 2 este prea mare dar 1 se poate folosi.
Mai rămân de schimbat 1-1 = 0 bani.
Ce monedă să folosim când avem 0 bani? Desigur ... niciuna!
Însumând valorile folosite (64, 32, 8, 4, 2, 1) obţinem 111.
Într-un tabel cu 2 linii şi mai multe coloane (!) vom pune valorile monedelor şi ı̂n dreptul
fiecăreia vom pune 1 dacă acea monedă a fost folosită şi 0 dacă nu a fost folosită. Pentru exemplul
anterior, tabelul este:
7 6 5 4 3 2 1 0
moneda: 128=2 64=2 32=2 16=2 8=2 4=2 2=2 1=2
apariţie: 0 1 1 0 1 1 1 1
Este evident că, ı̂ntr-o astfel de reprezentare, se ı̂nsumează numai valorile monedelor care au
1 la ’apariţie’. Secvenţa 01101111 2 este reprezentarea ı̂n baza 2 a numărului 111 (din baza 10).
39
Valorile monedelor fiind puteri, le putem identifica numai prin exponentul la care apare 2:
exponent: 7 6 5 4 3 2 1 0
apariţie: 0 1 1 0 1 1 1 1
În urma acestor ı̂mpărţiri obţinem că 11 din baza 10 se scrie ı̂n baza 2 astfel: 1011 (resturile
obţinute ... scrise ı̂n ordine inversă).
Această afirmaţie se notează pe scurt astfel: 1110 10112 . Când nu punem ı̂n evidenţă baza,
vom considera că este vorba de baza 10. Putem să nu punem ı̂n evidenţă baza ı̂n notaţia numărului
şi atunci când este foarte clar despre ce bază este vorba!
Primul rest este ultima cifră ı̂n reprezentarea lui 11 ı̂n baza 2. Al doilea rest este penultima
cifră, şi aşa mai departe. Altfel spus, cifrele ı̂n baza 2 se obţin ı̂n ordine inversă.
39
https://www.mathsisfun.com/exponent.html
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.2. CONVERSII ALE DATELOR NUMERICE6
Ca să ”acceptăm” mai uşor acest algoritm, să ı̂ncercăm să facem o conversie din baza 10 ı̂n
baza 10 (da, nu este nicio greşeală, este tot baza 10). Mai precis, vom ı̂ncerca să obţinem cifrele
numărului.
40
Fie x 1395 numărul ı̂n baza 10 (acest număr ne aminteşte de ... Mircea cel Bătrân ).
Secvenţa de ı̂mpărţiri este:
În urma acestor ı̂mpărţiri obţinem că 1395 din baza 10 are cifrele 5, 9, 3, 1 dar acestea sunt
ı̂n ordine inversă (adică, dacă vrem să obţinem numărul corect, trebuie să le scriem ı̂n ordinea
inversă faţă de ordinea ı̂n care le-am obţinut).
În tabelul anterior putem să notăm, ı̂n loc de 1000, numai de câte ori apare 10, ı̂n
1000=10*10*10, adică (exponentul puterii):
Valoarea numărului se obţine făcând suma produselor dintre fiecare ”cifră” şi ”ordinul bazei”
corespunzătoare acelei cifre. În exemplul din tabel trebuie să facem produsele:
cifra 1 cu ordinul corespunzător 1000
cifra 3 cu ordinul corespunzător 100
cifra 9 cu ordinul corespunzător 10
cifra 5 cu ordinul corespunzător 1
La fel vom face şi când vom avea baza 2 sau altă bază (nu baza 10 ca acum).
Oricum, aceste lucruri sunt şi ı̂n manualele de matematică de clasa a 5-a, de exemplu:
https://manuale.edu.ro/manuale/Clasa%20a%20V-a/Matematica/ART/#book/u1-p50-51
Pentru conversia din baza 2 ı̂n baza 16 se ı̂nlocuiesc grupuri de câte 4 cifre binare cu simbolul
corespunzător din baza 16 din tabel. Dacă numărul de cifre binare nu este multiplu de 4 se
completează ı̂n stânga numărului cu atâtea 0-uri câte sunt necesare ca numărul de cifre să fie
multiplu de 4.
De exemplu: 1011011010 À 10 1101 1010 À 0010 1101 1010 À 2 D A À 2DA
Invers, pentru conversia din baza 16 ı̂n baza 2, se ı̂nlocuieţe fiecare cifră cu câte un grup de 4
cifre binare corespunzător cifrei hexazecimale din tabel.
De exemplu: ABAC À 1010 1011 1010 1100 À 1010101110101100
1.3 Programe ciudate
Atunci când dorim să participăm la olimpiadele de informatică, nu are prea mare importanţă dacă
limbajul de programare pe care ı̂l folosim este Java, C/C++, Pascal sau alt limbaj de programare.
Oricare ar fi limbajul de programare, este bine să ştim cum se reprezintă numerele ı̂n memoria
calculatorului. Altfel putem avea surprize ciudate!
Dacă nu suntem atenţi la valorile pe care le pot lua variabilele cu care lucrăm, putem obţine
rezultate greşite chiar dacă modalitatea de rezolvare a problemei este corectă. Iată astfel de situaţii
ı̂n Pascal, C/C++ şi Java.
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.3. PROGRAME CIUDATE 8
Deşi ne aşteptam să apară ca rezultat 50.000, surpriza este că pe ecran apare
20000+30000=-15536
Deşi ne aşteptam să apară ca rezultat 50.000, surpriza este că pe ecran apare din nou
20000+30000=-15536
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.3. PROGRAME CIUDATE 9
Şi mai ciudat pare a fi faptul că a apărut acelaşi rezultat greşit care a apărut la programul ı̂n
Numerele sunt reprezentate ı̂n baza 2 ı̂n calculator (nu ı̂n baza 10).
Dar noi suntem obişnuiţi cu ... baza 10.
Dacă reuşim să facem analogii cu baza 10, vom reuşi să ı̂nţelegem mai uşor şi mai repede atunci
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
Poziţia de semn este 1 şi asta ı̂nseamnă că numărul este negativ! Deci rezultatul este - 4433.
Iată cum apare ”ciudăţenia”!
Cam asta s-a ı̂ntâmplat ı̂n cele 3 programe ”ciudate”!
Trebuie să fim atenţi la câte ”pătrăţele” cerem calculatorului pentru numerele noastre!
Iniţial calculator.exe oferă interfaţa ”Standard” (Figura 1.6) dar aceasta se poate schimba
ı̂n interfaţa ”Programmer” (Figura 1.7). Aceasta din urmă ne va ajuta să ı̂nţelegem ceea ce s-a
ı̂ntâmplat ı̂n programele anterioare.
Să introducem valoarea 50 000, direct cu ajutorul tastaturii calculatorului/laptopului pe care
lucrăm sau, cu ajutorul mouse-lui, făcând ”click” pe cifrele corespunzătoare din tastatura oferită
de interfaţa programului ”calculator.exe”.
Figura 1.8: 50 000 in bazele 16, 10, 8 şi 2 Figura 1.9: QWORD = 64 biţi
În Figura 1.8, ı̂n partea stângă-sus, apar reprezentările numărului 50 000 ı̂n bazele 16 (”HEX”),
10 (”DEC”), 8 (”OCT”) şi 2 (”BIN”).
În baza 16 reprezentarea numărului 50 000 este C350.
În baza 8 reprezentarea numărului 50 000 este 141 520.
În baza 16 reprezentarea numărului 50 000 este 1100 0011 0101 0000.
Obs: Spaţiile folosite ı̂ntre grupuri de cifre sunt numai pentru a se citi mai uşor!
Un click pe ’cerculeţul galben’ (Bit Toggling keypad) din Figura 1.8 ne va conduce la Figura
41 42
1.9 ı̂n care avem reprezentarea pe biţi ı̂n format QWORD (4 * 16 = 64 biţi, QUAD WORD).
Biţii din această reprezentare sunt numerotaţi de la 0 la 63, de la dreapta spre stânga şi de jos
ı̂n sus. Pentru o ”vizibilitate” mai bună, apar notaţi numai biţii care sunt multiplii de 4.
Bitul 63 este bit de semn (0 pentru +, 1 pentru -).
Un click pe ’cerculeţul galben’ (’QWORD’) din Figura 1.9 ne va conduce la Figura 1.10 ı̂n care
avem reprezentarea pe biţi ı̂n format DWORD (2 * 16 = 32 biţi, DOUBLE WORD).
În Figura 1.10 biţii sunt numerotaţi de la 0 la 31, de la dreapta spre stânga şi de jos ı̂n sus.
41
https://en.wikipedia.org/wiki/Bit
42
https://en.wikipedia.org/wiki/Word_(computer_architecture)
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.3. PROGRAME CIUDATE 13
Figura 1.12: BYTE = 8 biţi Figura 1.13: QWORD ultimul byte din 50 000
Figura 1.14: Click pe 0 l-a schimbat ı̂n 1 Figura 1.15: DWORD valoare 208
Un click pe ’QWORD’ din Figura 1.14 ne va conduce la Figura 1.15. Prin acest ’click’ s-a
renunţat la jumătate din cifrele numărului (cele 32 din stânga; mai precis, s-a renunţat la cifrele
din zona poziţiilor 32-63).
Un click pe ’DWORD’ din Figura 1.15 ne va conduce la Figura 1.16. Prin acest ’click’ s-a
renunţat la jumătate din cifrele numărului (cele 16 din stânga; mai precis, s-a renunţat la cifrele
din zona poziţiilor 16-31).
Figura 1.16: WORD valoare 208 Figura 1.17: BYTE valoare -48
Un click pe ’WORD’ din Figura 1.16 ne va conduce la Figura 1.17. Prin acest ’click’ s-a
renunţat la jumătate din cifrele numărului (cele 8 din stânga; mai precis, s-a renunţat la cifrele
din zona poziţiilor 8-15).
În Figura 1.17 bitul de semn este pe poziţia 7 si are valoarea 1, deci valoarea numărului este
negativă. Mai precis, valoarea este -48.
1. : calculator
Ajungem astfel ı̂n situaţia din Figura 1.18. Un click pe ’QWORD’, apoi un click pe ’DWORD’
şi ı̂n final un click pe ’WORD’ ne duc situaţia din ı̂n Figura 1.19.
Un click pe poziţia 0 va schimba valoarea 0 ı̂n 1. Procedăm la fel pentru poziţiile 1-6 (fără
poziţia 7) şi obţinem Figura 1.20.
Bitul 7 este bit de semn şi valoarea este +127 (aceasta este valoarea maximă care se poate
obţine pe BYTE).
Dacă facem acum un click pe poziţia 7, vom schimba bitul de semn din 0 ı̂n 1 şi ... surpriza
este că valoarea se schimbă din 127 ı̂n -1 (vezi Figura 1.21). Altfel spus, valoarea -1 se reprezintă
ı̂n calculator ca ... ”1 peste tot”! Iar acest fapt nu se ı̂ntâmplă numai pentru BYTE ci şi pentru
WORD, DWORD şi QWORD.
Nu trebuie să ţinem minte acest fapt! Cred că vom ţine minte fără să vrem mai târziu, când
vom mai ı̂nvăţa câte ceva!
Să lăsăm acum 1 pe bitul de semn (poziţia 7) şi să schimbăm poziţiile 0-6 din 1 ı̂n 0. Adică, 1
pe poziţia de semn şi 0 ı̂n rest. Obţinem Figura 1.22.
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.3. PROGRAME CIUDATE 16
Figura 1.22: Click pe poziţia indicată Figura 1.23: -128 se transformă ı̂n -120
Valoarea -128 este cea mai mică valoare care se poate ı̂nregistra pe BYTE. Adică, ”1 pe poziţia
de semn şi ı̂n rest 0” generează cea mai mică valoare negativă care se poate ı̂nregistra pe BYTE.
La fel se ı̂ntâmplă şi pentru WORD, DWORD şi QWORD numai că vor fi alte valori.
Continuând joaca noastră, dacă facem click pe poziţia 3 vom schimba valoarea poziţiei din 0
ı̂n 1 iar valoare pe BYTE se schimbă din -128 ı̂n -120 (vezi Figura 1.23).
Poziţia 3 corespunde valorii 8=2*2*2 şi există o legătură uşor de observat ı̂ntre valoarea veche
-128, valoarea nouă -120 şi acest 8.
Din cele două figuri se poate observa uşor cum se poate trece de la 100 la -100 ı̂n reprezentarea
44
binară (ı̂n cod complementar ):
1. se parcurge reprezentarea lui 100 de la dreapta spre stânga până se ı̂ntâlneşte cifra 1 (marcat
cu o săgeată roşie ı̂n figurile de mai sus)
2. această zonă “10...0” (formată din un 1 urmat de mai multe 0-uri) se lasă neschimbată
3. cifrele care urmează, spre stânga zonei “10...0” se vor schimba, toate (cifra 0 se schimbă ı̂n
1, iar cifra 1 se schimbă ı̂n 0), inclusiv cifra de semn care este pe prima poziţie din stânga!
44
https://en.wikipedia.org/wiki/Signed_number_representations
https://en.wikipedia.org/wiki/Two%27s_complement
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.4. CODIFICAREA NUMERELOR ÎNTREGI
17
Între cele două cercuri sunt trecute reprezentările binare (pe 4 biţi) corespuzatoare numerelor
0, 1, ..., 15 (care sunt scrise ı̂n exteriorul cercului mare).
Ne propunem să considerăm că avem numere pozitive ı̂n dreapta lui 0 şi numere negative ı̂n
stânga lui 0. Asta presupune să “rupem” cercul pe undeva (ı̂n partea de jos pare mai bine!). În
figura de mai sus cercul este “rupt” ı̂ntre numerele 7 şi 8 (din exteriorul cercului mare!).
Primul numâr din stânga lui 0 ar trebui să fie -1, al doilea număr din stânga lui 0 ar trebui să
fie -2, şi aşa mai departe! Pe figură, ı̂n dreptul lui 15 este scris cu roşu -1, ı̂n dreptul lui 14 este
scris cu roşu -2, şi aşa mai departe!
O “justificare” pentru tăietura cercului ı̂ntre 7 şi 8 ar putea fi următoare:
1. de la 0 la 15 sunt 16 numere
2. considerăm jumătate pozitive şi jumătate negative
45
https://en.wikipedia.org/wiki/Two%27s_complement
46
https://en.wikipedia.org/wiki/Ones%27_complement
47
https://en.wikipedia.org/wiki/C%2B%2B20
48
https://en.wikipedia.org/wiki/ASCII
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.5. CODURI ASCII 19
1.5.2 Litere
Literele au coduri ı̂n zona 65-90 şi 97-122.
Litere mici
Literele mici au coduri ı̂n zona 97-122. În hexazecimal zona este 0x61-0x7A
Listing 1.5.1: ascii litere mici.cpp
#include<iostream>
int main()
{
for(int i = 97; i <= 122; i++)
//cout<<i<<" : "<<(char)i<<’\n’;
cout<<(char)i<<’ ’;
return 0;
}
Litere mari
Literele mari au coduri ı̂n zona 65-90. În hexazecimal zona este 0x41-0x5A
Listing 1.5.2: ascii litere mari.cpp
#include<iostream>
int main()
{
for(int i = 65; i <= 90; i++)
//cout<<i<<" : "<<(char)i<<’\n’;
cout<<(char)i<<’ ’;
return 0;
}
1.5.3 Cifre
Cifrele au coduri ı̂n zona 48-57. În hexazecimal zona este 0x30-0x39
Listing 1.5.3: ascii cifre.cpp
#include<iostream>
int main()
{
for(int i = 48; i <= 57; i++)
//cout<<i<<" : "<<(char)i<<’\n’;
cout<<(char)i<<’ ’;
return 0;
}
CAPITOLUL 1. NOŢIUNI ELEMENTARE 1.5. CODURI ASCII 20
1.5.4 ’Whitespace’
49 50
Spaţiile albe (white-spaces ) sunt caracterele de separare ı̂ntre entităţile limbajului.
Acestea sunt:
51
Ele sun folosite pentru ’tabularea’ informaţiilor.
int main()
{
char ch;
return 0;
}
52
Pe ecran apar codurile (ı̂n baza 10) din tabela ASCII ale caracterelor white-space:
49
https://docs.microsoft.com/en-us/cpp/c-language/white-space-characters?view=msvc-160
50
C++ “sare” peste ele!
51
https://en.wikipedia.org/wiki/Tab_key
52
https://en.wikipedia.org/wiki/ASCII
Capitolul 2
1 2 3 4 5 6 7
Deplasare spre stânga cu 1 poziţie este echivalentă cu ı̂nmulţirea numărului cu 10, deci, 891 se
transformă ı̂n 8910.
1 2 3 4 5 6 7
Deplasare spre stânga cu 2 poziţii este echivalentă cu ı̂nmulţirea numărului cu 10*10, deci, 891
se transformă ı̂n 89100.
1 2 3 4 5 6 7
Deplasare spre stânga cu 3 poziţii este echivalentă cu ı̂nmulţirea numărului cu 10*10*10 şi
21
CAPITOLUL 2. PROBLEME ELEMENTARE 2.2. CONTOR 22
astfel 891 se transformă ı̂n 891000 dar ... cifra 8 ajunge ı̂n zona roşie (roz)! ... şi “se pierde” pur
şi simplu ... deci, 891 se transformă ı̂n 91000 prin ı̂nmulţire cu 1000.
Astfel de lucruri se ı̂ntâmplă şi ı̂n baza 2, ı̂n calculator, ı̂n C++, ı̂n Pascal, ı̂n Java, ...! Numerele
au alocate nişte căsuţe ı̂n care să fie scrise. Dacă ieşim din acele căsuţe atunci se pierd cifre şi
astfel se obţin rezultate greşite ... despre care noi am crezut că sunt numai ... “ciudate”!
1 2 3 4 5 6 7
Deplasare spre dreapta cu 1 poziţie este echivalentă cu ı̂mpărţirea numărului prin 10, deci 891 se
transformă ı̂n 89 pentru că cifra 1 “se pierde” pur şi simplu!
Acelaşi număr 891, dacă ar fi fost deplasat spre dreapta cu 2 poziţii ar fi devenit 8 iar dacă ar
2.2.2 Mărire cu 1
Ce se ı̂ntâmplă când se măreşte valoarea unui număr ı̂ntreg cu o unitate?
1. Dacă se poate, se măreşte cu o unitate ultima cifră (cea din dreapta) şi ... gata!.
2. Dacă nu se poate mări ultima cifră (pentru că este ”9” = cea mai mare cifră permisă pe
poziţia verificată), se caută spre stânga prima poziţie care se poate mări, se măreşte acea
poziţie şi se pun pe ”0” toate poziţiile prin care s-a trecut. (”0” este cea mai mică cifră
permisă pe poziţia verificată).
Observaţie:
După mărire cu 1 a cifrei de pe poziţia posibilă, se pune cel mai mic număr pe zona cifrelor din
dreapta poziţiei mărite!
2.2.3 Micşorare cu 1
Ce se ı̂ntâmplă când se micşorează valoarea unui număr ı̂ntreg cu o unitate?
1. Dacă se poate, se micşorează cu o unitate ultima cifră (cea din dreapta) şi ... gata!.
2. Dacă nu se poate micşora ultima cifră (pentru că este ”0” = cea mai mică cifră permisă pe
poziţia verificată), se caută spre stânga prima poziţie care se poate micşora, se micşorează
acea poziţie şi se pun pe ”9” toate poziţiile prin care s-a trecut. (”9” este cea mai mare cifră
permisă pe poziţia verificată).
CAPITOLUL 2. PROBLEME ELEMENTARE 2.2. CONTOR 23
Observaţie:
După micşorare cu 1 a cifrei de pe poziţia posibilă, se pune cel mai mare număr pe zona cifrelor
din dreapta poziţiei micşorate!
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
8 8 8 8 8 8 8 8 8 88 8 8 8 8 8
7 7 7 7 77 7 7 7 7 7 7 7 7 7 7
6 6 66 6 6 6 6 66 6 6 6 6 66 6 6
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
3 33 3 33 3 3 33 3 33 3 3 33 3 33 3
22 2 2 2 2 22 2 2 2 2 22 2 2 2 2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4 3 2 1 0 4 3 2 1 0 4 3 2 1 0
În cazul 1 ultima cifră a contorului ı̂n starea curentă este 8. Pentru succesor trebuie să mărim
8 cu 1 iar pentru predecesor trebuie să micşorăm 8 cu 1. Ambele cazuri sunt “uşoare” pentru că
restul cifrelor nu se schimbă!
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
8 8 8 8 88 8 8 8 8 8 8 8 8 8 8
7 7 7 7 7 7 7 7 7 7 7 7 77 7 7
6 6 66 6 6 6 6 66 6 6 6 6 6 6 6
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
3 33 3 3 3 3 33 3 3 3 3 33 3 3 3
22 2 2 2 2 22 2 2 2 2 22 2 2 2 2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4 3 2 1 0 4 3 2 1 0 4 3 2 1 0
curentă” este cea care conţine cifra 6. 6 va deveni 7 iar pe poziţiile din dreapta trebuie să punem
cele mai mici cifre!
Mai ı̂n glumă, mai ı̂n serios ... ne dăm seama că:
dacă ultima cifră este 9 atunci predecesorul se obţine uşor, dar succesorul ... mai greu!
dacă ultima cifră este 0 atunci succesorul se obţine uşor, dar predecesorul ... mai greu!
dacă ultima cifră este diferită de 9 şi 0 atunci ambele se obţin uşor (se modifică numai ultima
cifră)!
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
8 8 8 8 8 8 8 8 8 8 8 8 8 8 8
7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
6 6 6 6 6 6 6 66 6 6 6 6 66 6 6
5 5 55 5 5 5 5 5 5 5 5 5 5 5 5
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
3 33 3 3 3 3 33 3 3 3 3 33 3 3 3
22 2 2 2 2 22 2 2 2 2 22 2 2 2 2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 11
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4 3 2 1 0 4 3 2 1 0 4 3 2 1 0
Observaţie:
Mai ı̂n glumă, mai ı̂n serios ... (din nou!) ne dăm seama că cele două “Reguli” sunt aproape
identice; practic sunt numai interschimbate “mic” cu “mare” şi “crescător” cu “descrescător”!
Să presupunem că avem la dispoziţie aceleaşi cifre ca ı̂n exemplele anterioare: 2,3,5,3,7.
Să presupunem că avem 3 numere “consecutive” a, b, c şi “numărul curent” este b 52733.
Cât este a? Cât este b?. Sau altfel spus: care sunt predecesorul şi succesorul lui 52733?
Mai ı̂n glumă, mai ı̂n serios ... (iarăşi? ) ne dăm seama că cele două “Argumente cen-
trale” sunt aproape identice; practic sunt numai interschimbate “mic” cu “mare” şi “crescător”
cu “descrescător” (desigur, şi cifrele corespunzătoare!)!
Capitolul 3
Multe lucruri se pot face “ı̂n fel şi chip” şi la fel se ı̂ntâmplă şi cu programarea ı̂n C++!
Vom spune de multe ori că “se face aşa ...” deşi ... se poate face ı̂n multe alte feluri!
Pentru ı̂nceput (şi mai ales pentru ı̂ncepători!) este mai bine să folosim variante standard,
simple, uşor de ı̂nţeles şi de ţinut minte (asta se realizează prin muncă, prin repetare, aşa cum fac
şi sportivii la antrenamente!).
#include<iostream>
int main()
{
int a, b, sum;
cin >> a;
cin >> b;
sum = a + b;
cout << sum << endl;
return 0;
}
Calculatorul ı̂nţelege numai codul să maşină iar programul anterior este scris ı̂n C++ care este
un limbaj de programare evoluat. Există programe speciale care transformă codul sursă scris de
programator ı̂n C++ (sau ı̂n alt limbaj de programare: Java, Pascal, ...) ı̂n cod maşină care poate
54
fi executat pe calculator.
În limbaj de asamblare acest cod arată astfel:
26
CAPITOLUL 3. PROGRAMARE C+++ 27
Se poate folosi https://godbolt.org/ pentru a verifica acest exemplu sau pentru a vedea
alte coduri proprii.
Este util şi acest link: https://www.geeksforgeeks.org/convert-cc-code-to-a
ssembly-language/
Secvenţa
cin >> a;
cin >> b;
sum = a + b;
cout << sum << endl;
55
este reprezentată ı̂n cod maşină astfel:
00000 10011110
00001 11110100
00010 10011110
00011 11010100
00100 10111111
00101 00000000
Ca să fie tacâmul complet ... vreau să spun că, ı̂n studenţie, scriam programele pe cartele:
55
http://www.cplusplus.com/doc/tutorial/introduction/
CAPITOLUL 3. PROGRAMARE C+++ 28
Mai ı̂nainte, prin liceu (la cercul de informatică), foloseam bandă perforată care arăta cam aşa:
Rezultatul programelor (şi codul sursă) ı̂l primeam pe hârtie de imprimanta care arăta cam aşa:
CAPITOLUL 3. PROGRAMARE C+++ 29
Programele noastre aveau instrucţiuni pe mai multe cartele pe care le legam cu elastic, cam aşa:
int main()
{
return 0;
}
56
exemplul clasic este: http://www.cplusplus.com/doc/tutorial/program_structure/
CAPITOLUL 3. PROGRAMARE C+++ 3.1. STRUCTURA UNUI PROGRAM IN C++ 31
Scrierea codului pe linii este complet liberă! Se pot scrie toate instrucţiunile (tot programul)
57 58
pe un singur rând! Totuşi, un cod lizibil este de preferat! Indentarea standard oferită de
Code::Blocks ajută la scrierea unui cod lizibil!
59
Fiecare editează şi programează cum vrea dar ... este util, din mai multe puncte de vedere,
60 61
să citim câte ceva despre “best practice” ı̂n domeniul programării ı̂n C++.
57
DEX - lizibil: care poate fi citit uşor
58
DEX - indentare: plasare a programelor pe linii, pentru scrierea cât mai clară a acestora
59
https://www.learncpp.com/cpp-tutorial/whitespace-and-basic-formatting/
60
https://en.wikipedia.org/wiki/Best_practice
61
http://web.mit.edu/6.s096/www/standards.html
https://www.learncpp.com/cpp-tutorial/why-functions-are-useful-and-how-to-use-them-eff
ectively/
CAPITOLUL 3. PROGRAMARE C+++ 3.1. STRUCTURA UNUI PROGRAM IN C++ 32
Eu prefer să las setările implicite! Până la urmă ... ele au fost stabilite aşa de către specialişti
Pentru indentarea codului sursă, ı̂n Code::Blocks, setarea implicită pentru TAB este: 4. Mulţi
preferă TAB size in spaces: 2.
De asemenea, trebuie să menţionez, mulţi folosesc opţiunea Optimize even more (for
speed) [-O2] dar ... eu cred că adevărata “viteză” se obţine cu ajutorul ... algoritmului!
Câteva observaţii pentru primul program ı̂n C++ din figurile (3.6 - 3.8):
62
este butonul build pentru complilare (Figura 3.6)
Despre liniile de cod din p01.cpp: ce este cu roşu este “şablon” (nu le schimbăm niciodată!).
int main()
{
return 0;
}
Am adăugat o instrucţiune ı̂n şablon! Este acelaşi program care face ... “nimic” ... şi care era
funcţional şi fără using namespace std; dar ... este mai bine aşa! ... Oricum, are şi ea
rolul ei şi este utilă!
#include<fstream>
#include<iostream>
int main()
{
return 0;
}
Am mai adăugat două instrucţiuni ı̂n şablon! #include¡fstream¿ ne permite să accesăm
fişiere iar #include¡iostream¿ ne permite să accesăm tastatura şi ecranul.
63
In a C program, all lines that start with # are processed by preprocessor which is a special
program invoked by the compiler. In a very basic term, preprocessor takes a C program and
produces another C program without any #.
The C preprocessor or cpp is the macro preprocessor for the C, Objective-C and C++ computer
programming languages. The preprocessor provides the ability for the inclusion of header files,
macro expansions, conditional compilation, and line control.
In many C implementations, it is a separate program invoked by the compiler as the first part
of translation.
The language of preprocessor directives is only weakly related to the grammar of C, and so is
sometimes used to process other kinds of text files.[1]
The following are some interesting facts about preprocessors in C.
1) When we use include directive, the contents of included header file (after preprocessing)
are copied to the current file. Angular brackets ¡ and ¿ instruct the preprocessor to look in the
standard folder where all header files are held. Double quotes and instruct the preprocessor to
64
look into the current folder (current directory).
2) When we use define for a constant, the preprocessor produces a C program where the
65
defined constant is searched and matching tokens are replaced with the given expression.
#include<fstream>
#include<iostream>
ifstream fin("f04.in");
ofstream fout("f04.out");
int main()
{
return 0;
}
#include<fstream>
#include<iostream>
int main()
{
int n;
fin >> n;
fout << n*n << "\n";
cout << "nˆ2 = " << n*n << "\n";
return 0;
}
În acest program (p05.cpp) pe linia 13 instructiunea int n; declară variabila n. Este
aproape ca la matematică atunci când folosim o ’necunoscută’ n sau ceva notat cu n. Aici
’variabila este caracterizată de:
nume (aici este n)
Fişierul de intrare f05.in conţine 3 numere: 12345, 67 şi 89. Să observăm că ı̂ntre 12345 şi 67
66
există un spaţiu. Acesta are codul 20 ı̂n tabela de coduri ASCII. Să mai observăm că 89 este pe
rândul următor faţă de 67. Este normal să “bănuim” că ı̂ntre 67 şi 89 trebuie să fie o comandă
pentru a “trece pe rândul următor, la ı̂nceput de rând”! O vom vedea ... imediat!
Capul de citire din fişier este poziţionat la ı̂nceputul fişierului.
67
Numerele sunt despărţite de nişte “separatori” care se numesc “caractere whitespace”.
66
https://en.wikipedia.org/wiki/ASCII
67
https://en.cppreference.com/w/cpp/string/byte/isspace
CAPITOLUL 3. PROGRAMARE C+++ 3.1. STRUCTURA UNUI PROGRAM IN C++ 38
space (0x20, ’ ’)
line feed (0x0a, ’\n’)
carriage return (0x0d, ’\r’)
horizontal tab (0x09, ’\t’)
Instrucţiunea int n; (rândul 13) generează alocarea spaţiului de memorie pentru variabila n şi
68
precizează (prin cuvântul cheie rezervat int) cum să fie prelucrat acel spaţiu de memorie.
Cât spaţiu se alocă pentru n? Depinde!
69
Depinde, ı̂n primul rând, de cuvântul scris ı̂n faţa lui n (se numeşte tipul lui n, iar ı̂n
70
exemplul nostru este int). Dar ... mai depinde şi de compilatorul de C++ pe care ı̂l folosim,
71 72
de standardul pe care ı̂l utilizează acest compilator şi de sistemul de operare pe care ı̂l avem
73
pe calculatorul nostru (de obicei Windows sau Linux dar ... unii au Mac ). Apropo de sistem
de operare, compilatoare, etc.: la Olimpiada Internaţională de Informatică din septembrie 2020
s-a folosit sistemul de operare Ubuntu 20.04 LTS, compilatoarele folosite au fost OpenJDK
74 75 76
11.0.7 şi Gcc 9.3.0 , iar interpretoarele folosite au fost Ruby 2.7 şi Python 3.8.2. (adică,
limbajele de programare folosite au fost Java, C++, Ruby şi Python).
Instrucţiunea fin >> n; (de pe rândul 15) citeşte din fişier, preia valoarea 12345, depozitează
această valoare la adresa lui n şi poziţionează capul de citire după 12345 şi ı̂nainte de 67.
Figura 3.17: fişierul cu datele de ieşire f05.out şi rezultatul afişat pe ecran
Instrucţiunea fout << n*n << "\n"; (de pe rândul 16) scrie ı̂n fout valoarea calculată a
expresiei n*n = 12345*12345 = 152399025 şi apoi execută comanda "\n" (trece pe rândul
următor, la ı̂nceput de rând).
Poate că aceste instrucţiuni par “grele” la ı̂nceput (pentru ı̂ncepători) dar ele sunt sugestive!
Simbolul >> sugerează o deplasare de la stânga spre dreapta!
Simbolul << sugerează o deplasare de la dreapta spre stânga!
fin >> n; ı̂nseamnă că se deplasează ceva de la fin spre n.
Ce se poate deplasa din fişierul fin? Evident ... ce este acolo!
fout << n*n << "\n"; ı̂nseamnă că se deplasează n*n şi "\n" spre fout.
68
https://en.cppreference.com/w/cpp/keyword
69
https://www.tutorialspoint.com/cplusplus/cpp_data_types.htm
70
http://www.cplusplus.com/doc/tutorial/introduction/
71
https://en.wikipedia.org/wiki/C%2B%2B
. https://isocpp.org/std/status
72
https://en.wikipedia.org/wiki/Operating_system
73
https://en.wikipedia.org/wiki/Macintosh
74
https://gcc.gnu.org/releases.html
75
https://en.wikipedia.org/wiki/Interpreter_(computing)
76
https://ioi2020.sg/contestantpc/
CAPITOLUL 3. PROGRAMARE C+++ 3.1. STRUCTURA UNUI PROGRAM IN C++ 39
Primul care ajunge la fout este n*n şi apoi "\n". Expresia n*n se calculează şi numai
rezultatul ei “va pleca” spre fout. Apoi “va pleca” spre fout şi "\n" care este o comandă pentru
77
trecerea pe rândul următor.
cout, din linia de cod 17, este numele pe care trebuie să-l folosim atunci când ne referim la
ecranul calculatorului nostru.
linia de cod 17: cout << "nˆ2 = " << n*n << "\n";
cout << ... ı̂nseamnă că vine ceva spre ecran!
78
Ce este scris ı̂ntre ghilimele se scrie exact aşa cum este scris ı̂ntre ghilimele!
n*n este o expresie aritmetică, ea se evaluează şi numai rezultatul “se duce” spre cout.
79
"\n" este un caracter de control (generează trecerea pe rândul următor la ı̂nceput de rând).
3.1.6 Comentarii
Instrucţiunea “comentată” arată astfel:
// cout << "nˆ2 = " << n*n << "\n";
deci, cu două slash-uri ı̂n faţa ei.
Devine comentariu, până la sfârşitul liniei, tot ce este scris ı̂n dreapta celor două slash-uri.
80
Dacă trebuie să comentăm mai multe linii consecutive vom folosi acest model :
/*
...
*/
81
30 este codul ASCII pentru 0.
77
https://www.w3schools.com/cpp/cpp_new_lines.asp
78
se numeşte “string”: https://www.w3schools.com/cpp/cpp_strings.asp
79
https://www.ascii-code.com/
80
https://www.w3schools.com/cpp/cpp_comments.asp
30 16 3 16 0 48 10 , vezi: https://en.wikipedia.org/wiki/ASCII
81
CAPITOLUL 3. PROGRAMARE C+++ 3.1. STRUCTURA UNUI PROGRAM IN C++ 40
07 este codul ASCII pentru BEL (comandă: produce un beep - semnalizare sonoră ).
0D 0A este combinaţia care realizează trecere cursorului pe rândul următor la ı̂nceput de rând.
Asta se ı̂ntâmplă pe Windows! Pe Linux este altfel!
Fişierul f05.in, care este un fişier de tip txt, are dimensiunea de 12 octeţi: 10 caractere
obişnuite (9 cifre şi un spaţiu, codificate cu 31, 32, 33, 34, 35, 36, 37, 38, 39 şi 20) şi 2 caractere
care sunt de fapt comenzi (0D şi 0A).
Acelaşi fişier ı̂n Word ar avea 11,687 de octeţi. Sunt foarte multe comenzi inserate!
Programul nostru executabil p05.exe are 15,584,734 octeţi. Asta da dimensiune mare!
#include<fstream>
#include<iostream>
ifstream fin("f05.in");
ofstream fout("f05.out");
int main()
{
int n;
return 0;
}
Instrucţiunea de citire fin >> n >> n; are următorul efect: din fişierul fin se trimite primul
număr către primul n şi al doilea număr către a doua variabilă, care este tot n (apare astfel o
suprascriere, o depozitare peste o valoare existentă; rămâne numai ultima valoare scrisă la locaţia
respectivă de memorie).
Fişierul fin (f05.in) avea următorul conţinut: 12345 67 89. Instrucţiunea de citire preia 12345
şi-l depozitează la adresa de memorie a lui n, apoi preia 67 şi-l depozitează tot la adresa de
memorie a lui n. După citire n va rămâne cu valoarea 67 ı̂nregistrată la adresa sa de memorie.
Pe ecran va apărea valoarea n*n = 67*67 = 4489.
se numeşte “octet” sau “byte” şi ... aşa ı̂i vom spune mai departe!
#include<iostream>
int main()
{
int b1, b2;
int b3=1, b4=1;
return 0;
}
/*
82
https://en.wikipedia.org/wiki/Byte_addressing
83
https://en.wikipedia.org/wiki/Byte
84
https://en.wikipedia.org/wiki/Bit
CAPITOLUL 3. PROGRAMARE C+++ 3.1. STRUCTURA UNUI PROGRAM IN C++ 42
85
Când se declară o variabilă, “ţineva - nu spui ţine ... persoană ı̂nsemnată ...” alocă o zonă
de memorie pentru acea variabilă, la o anumită adresă din memorie. Astfel, “toată lumea” ştie la
la ce adresă este acea ... variabilă! Dacă persoana vizualizează spaţiul alocat fără să fi pus
fotografia lui acolo, va vedea o fotografie veche a altei persoane (vechiul conţinut al memoriei).
Este important să folosim zona alocată numai după ce am depozitat noi ceva acolo!
În Figura 3.21 este considerată situaţia ı̂n care ı̂n zona alocată pentru n există ı̂nregistrat 555.
Dacă afişăm n, fără să depozităm noi ceva acolo, pe ecran va apărea 555. După citirea din fişier a
primului număr, dacă am afişa n ar apărea 12345. Dacă am citi din nou din fişier şi am depozita
tot ı̂n n, la afişare ar apărea 67 (pntru că s-a suprascris 67 peste 12345 la adresa lui).
Instrucţiunea fin >> n; (de pe rândul 15) citeşte primul număr din fin şi depozitează valoarea
citită ı̂n spatiul de memorie alocat variabilei n. Se spune pe scurt: citeşte n din fin. În spaţiul de
memerie alocat lui n se află acum valoarea 12345.
Capul de citire din fişierul fin se află acum după 12345 şi ı̂nainte de 67. (Figura 3.22)
85
https://ro.wikisource.org/wiki/O_scrisoare_pierdut%C4%83
CAPITOLUL 3. PROGRAMARE C+++ 3.1. STRUCTURA UNUI PROGRAM IN C++ 43
După a doua citire, capul de citire din fişierul fin se află după 67 şi ı̂nainte de 89. (Figura 3.23)
După o eventuală a treia citire, capul de citire din fişierul fin s-ar fi aflat după 89. (Figura 3.24)
#include<fstream>
#include<iostream>
ifstream fin("f05.in");
ofstream fout("f05.out");
int main()
{
int n;
return 0;
}
De aceea e mai bine ca, după declararea variabilei (care alocă spaţiu pentru variabilă), să
suprascriem ı̂n acea zonă de memorie o valoare care să fie “valoarea noastră” (să nu mai fie o
“rămăşiţă” de valoare despre care nu ştim “cât” este!).
CAPITOLUL 3. PROGRAMARE C+++ 3.2. ALFABETUL LIMBAJULUI 44
vrem noi!
ifstream finput("f06.in");
ofstream foutput("f06.out");
int main()
{
int n;
finput >> n;
return 0;
}
dreptate (!) ... noi vom merge mai departe spunând aşa!
Am văzut, ı̂n exemplele anterioare, că ı̂n C++ se folosesc litere, cifre, semne de punctuaţie,
86
simbolul adunării “+”, etc. Acestea se numesc caractere.
Totalitatea caracterelor permise ı̂n limbaj se numeşte “alfabetul” limbajului.
86
caracter: 1. Semn săpat (ı̂n piatră, ı̂n metal) sau scris (https://dexonline.ro/definitie/caracter)
CAPITOLUL 3. PROGRAMARE C+++ 3.2. ALFABETUL LIMBAJULUI 45
87
În acest alfabet sunt 96 de caractere (standard pentru limbajul C) :
litere mici: a b c d e f g h i j k l m n o p q r s t u v w x y z
litere mari: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
cifre: 0 1 2 3 4 5 6 7 8 9
caractere speciale:
_ { } [ ] # ( ) < > % : ; . ? * + - / ˆ & | ˜ ! = , \ " ’
Observaţie: 26 + 26 + 10 + 29 = 91
Parcă lipsesc 5 caractere!
88
Dar ... iată-le (White Spaces) :
1. caracterul HT (horizontal tab) \t cu codul ASCII 9 (0x09) ***
2. caracterul LF (new line / line feed) \n cu codul ASCII 10 (0x0A) ***
3. caracterul VT (vertical tab) \v cu codul ASCII 11 (0x0B) ***
4. caracterul FF (form feed / new page) \f cu codul ASCII 12 (0x0C) ***
5. caracterul CR (carriage return) \r cu codul ASCII 13 (0x0D)
6. caracterul space cu codul ASCII 32 (0x20) ***
89
Sunt chiar 6 caractere!
În
https://publications.gbdirect.co.uk/c_book/chapter2/alphabet_of_c.html
şi ”Sailing Through C: A Complete C Programming Guide” - De Farheen Siddiqui,
erau numai 5.
int main()
{
int ch;
int nrv;
// ------------------------------------
cout<<"iscntrl: \n";
nrv=1;
for(ch=0; ch<=255; ch++)
if (iscntrl(ch))
{
cout<<setw(3)<<(int)ch<<" ";
if((nrv%10)==0) cout<<"\n";
++nrv;
//getchar();
}
cout<<"\n\n";
// ------------------------------------
cout<<"isspace: ";
for(ch=0; ch<=255; ch++)
if (isspace(ch))
{
cout<<(int)ch<<" ";
//getchar();
87
https://publications.gbdirect.co.uk/c_book/chapter2/alphabet_of_c.html
88
https://www.techiedelight.com/remove-whitespaces-string-cpp/
89
https://www.techiedelight.com/remove-whitespaces-string-cpp/
CAPITOLUL 3. PROGRAMARE C+++ 3.2. ALFABETUL LIMBAJULUI 46
}
cout<<"\n\n";
// ------------------------------------
cout<<"isblank: ";
for(ch=0; ch<=255; ch++)
if (isblank(ch))
{
cout<<(int)ch<<" ";
//getchar();
}
cout<<"\n\n";
// ------------------------------------
cout<<"isprint: \n";
for(ch=0; ch<=255; ch++)
if (isprint(ch))
{
cout<<setw(3)<<(int)ch<<" ";
if((ch%16)==15) cout<<"\n";
//getchar();
}
cout<<"\n\n";
cout<<"isalnum: \n";
nrv=1;
for(ch=0; ch<=255; ch++)
if (isalnum(ch))
{
cout<<setw(3)<<(int)ch<<" ";
if((nrv%16)==0) cout<<"\n";
++nrv;
//getchar();
}
cout<<"\n\n";
nrv=1;
for(ch=0; ch<=255; ch++)
if (isalnum(ch))
{
cout<<setw(3)<<(char)ch<<" ";
if((nrv%16)==0) cout<<"\n";
++nrv;
//getchar();
}
cout<<"\n\n";
// ------------------------------------
// ------------------------------------
return 0;
}
Caracterele de control sunt ı̂n zona codurilor 0-31 (0x00-0x1F ı̂n hexazecimal).
90
Codul 127 (0x7F ı̂n hexazecimal) este pentru DEL.
Codurile 9 (HT ’horizontal tabulation’) şi 32 (’space’) sunt considerate şi ’space’ şi ’blank’.
Codurile alfanumerice conţin codurile cifrelor şi codurile literelor (mari şi mici).
Nu sunt trecute aici simbolurile din zona codurilor ASCII extins, zona 128-255 (80-FF ı̂n hexa).
92
Configuraţiile calculatoarelor care s-au folosit la I.O.I. cu mai mulţi ani ı̂n urmă au fost:
93
La IOI2000 s-au folosit calculatoare cu următoarea configuraţie:
’Competition Equipment’:
”The competition computers will be PCs, each with an Intel Pentium III CPU running at
94
La IOI1995 s-au folosit calculatoare cu următoarea configuraţie:
’Competition Equipment’:
”The computer is a Tulip Vision Line with a 75 MHz Pentium processor, a standard U.S.
95
La IOI1994 s-au folosit calculatoare cu următoarea configuraţie:
’Competition Equipment’:
”The computer is an AST with a 33 MHz Intel 486 processor running MS-DOS”
96
La IOI1993 s-au folosit calculatoare cu următoarea configuraţie:
’Tools’:
”For the Olympiad each participant will be provided with a personal computer with a USA
style, 101-key, QWERTY keyboard and the necessary software. MS-DOS V. 5.0 will be
provided.”
Din 1989 (de când au ı̂nceput olimpiadele de informatică) până acum, puterea calculatoarelor
personale folosite la olimpiade a crescut de peste 1 000 de ori, atât din punct de vedere al vitezei
de calcul cât şi din punct de vedere al memoriei folosite pentru stocarea informaţiilor necesare
rezolvării problemelor date ı̂n concurs!
În general, la olimpiadele de informatică, s-au folosit calculatoare personale cu procesoare
destul de noi! Caracteristicile acestora sunt:
http://www.cpu-collection.de/?tn=1&l0=cl&l1=80186/188&l2=Intel
https://en.wikipedia.org/wiki/List_of_Intel_processors#80186
https://en.wikipedia.org/wiki/Intel_80286
int main()
{
unsigned int i1 = 0x87654321; // se aloca 4 octeti
unsigned int i2 = 0x21436587; // bitii din octet nu se inverseaza
if(*c1 == 0x10)
{
//printf("calculatorul tau este ... ’Little endian’ ... !!!\n\n");
cout<<"calculatorul tau este ... ’Little endian’ ... !!!\n\n";
}
else
{
//printf("calculatorul tau este ... ’Big endian’ ... !!!\n\n");
cout<<"calculatorul tau este ... ’Big endian’ ... !!!\n\n";
}
cout<< std::dec;
cout << "i1 = 0x87654321; *(c1+3) --> "
<< (int)((unsigned char)(*(c1+3))) << " "
<< std::hex << " hex: " << (int)((unsigned char)(*(c1+3))) << "\n";
cout<<"\n";
cout<< std::dec;
cout << "i2 = 0x21436587; *(c2+0) --> "
<< (int)((unsigned char)(*(c2+0))) << " "
<< std::hex << " hex: " << (int)((unsigned char)(*(c2+0))) << "\n";
cout<< std::dec;
cout << "i2 = 0x21436587; *(c2+3) --> "
<< (int)((unsigned char)(*(c2+3))) << " "
95
http://olympiads.win.tue.nl/ioi/ioi94/contest/
96
http://ioi.te.lv/locations/ioi93/rules.txt
CAPITOLUL 3. PROGRAMARE C+++ 3.3. ALOCAREA VARIABILELOR 50
<< std::hex << " hex: " << (int)((unsigned char)(*(c2+3))) << "\n";
return 0;
}
Observaţie:
21 ı̂n baza 16 este de fapt 33 ı̂n baza 10 pentru că 2*16+1=33
87 ı̂n baza 16 este de fapt 135 ı̂n baza 10 pentru că 8*16+7=135
Ce ı̂nseamnă asta?
Povestea este cam aşa: să presupunem că cineva cere (de la primărie!) un teren pentru 4 case
(’casa1’, ’casa2’, ’casa3’ şi ’casa4’). Primăria ı̂i dă terenul solicitat pe strada ’Memorie’ la numerele
consecutive 123, 124, 125 şi 126 (deci, grupul de case ı̂ncepe la numărul 123 şi se termină la
numărul 126). Trebuie spus că strada ’Memorie’ are case numai pe o parte a străzii ... deci ... pe
acea parte sunt şi numerele cu soţ şi numerele fără soţ! Casele vor fi construite una după alta.
Trebuie să mai ştim ceva important: casele au valori diferite! Cea mai valoroasă este ’casa4’
şi valorile lor descresc spre ’casa1’. Un exemplu fictiv este: ’casa4’ valorează 10 000, ’casa3’
valorează 1 000, ’casa2’ valorează 100 şi ’casa1’ valorează 10.
Iar ı̂ntrebarea este: la ce număr se află cea mai valoroasă casa? La 123 sau la 126?
int main()
CAPITOLUL 3. PROGRAMARE C+++ 3.3. ALOCAREA VARIABILELOR 51
{
unsigned int i = 0x04030201; // se aloca 4 octeti
return 0;
}
Pe R8 (rândul 8 din programul sursă) 0x ı̂nseamnă că urmează scrierea numărului ı̂n ‘hexa’
(baza 16).
Pe R10 setw(8) ı̂nseamnă că urmează afişarea numărului pe 8 poziţii (aliniat la dreapta!).
Pe R11 std::hex ı̂nseamnă că urmează afişarea numărului ı̂n ’hexa’. Afişările următoare se
vor face tot ı̂n ’hexa’ până când se va seta afişarea ı̂n ’dec’ (’decimal’, ı̂n baza 10) aşa cum este
făcut ı̂n R13.
R14 este o afişare de verificare că mai departe se vor face afişări ı̂n maza 10.
int main()
{
unsigned int x = 1234567890; // se aloca 4 octeti
return 0;
}
Pe ecran apare:
CAPITOLUL 3. PROGRAMARE C+++ 3.3. ALOCAREA VARIABILELOR 52
https://en.wikipedia.org/wiki/DOS_memory_management
97
https://en.cppreference.com/w/cpp/language/operator_precedence
CAPITOLUL 3. PROGRAMARE C+++ 3.3. ALOCAREA VARIABILELOR 53
https://en.wikipedia.org/wiki/Conventional_memory
https://en.wikipedia.org/wiki/High_memory_area
https://en.wikipedia.org/wiki/Upper_memory_area
int x1g=12;
int x2g=23;
int x3g=34;
void functie()
{
int xx1f=1234;
int xx2f=2345;
int xx3f=3456;
int main()
{
int x1m=123;
int x2m=234;
int x3m=345;
cout<<"\n";
cout<<"\n";
functie(); cout<<"\n";
stiva1(x1m,x2m,x3m); cout<<"\n";
stiva2(x1g,x2g,x3g); cout<<"\n";
stiva3(x1m,x2m,x3m); cout<<"\n";
stiva4(x1g,x2g,x3g);
return 0;
}
Pe ecran apare:
In zona ’MAIN’ adresele se aloca consecutiv descrescator
&x1m = 0x61fdec x1m = 123
&x2m = 0x61fde8 x2m = 234
&x3m = 0x61fde4 x3m = 345
#include <stdio.h>
//printf("\n");
}
Pe ecran apare:
0061fdec : 1234567
0061fdec : 67
0061fded : 45
0061fdee : 23
0061fdef : 01
98
MSB (most-significant byte)
98
https://en.wikipedia.org/wiki/Bit_numbering
CAPITOLUL 3. PROGRAMARE C+++ 3.3. ALOCAREA VARIABILELOR 56
Ordinea octeţilor (ordinea biţilor nu se schimbă ı̂n ı̂n interiorul octeţilor). De exemplu pentru
numărul 23 MSB=2 şi LSB=3. plasează ordinul unităţilor (cifra 3) la adresă mare şi ordinul
zecilor (cifra 2) la adresă mică. Deci, ordin mic la adresă mare, ordin mare la adresă mică - ı̂n
reprezentarea Big Endian!
Ordinea octeţilor (ordinea biţilor nu se schimbă ı̂n ı̂n interiorul octeţilor). De exemplu pentru
numărul 23 LSB plasează ordinul unităţilor (cifra 3) la adresă mică şi ordinul zecilor (cifra 2) la
adresă mare. Deci, ordin mic la adresă mică, ordin mare la adresă mare - ı̂n reprezentarea Little
Endian!!
”Picture from:” https://aticleworld.com/little-and-big-endian-importance/
O reprezentare ”pe verticală” ... cred că produce mai puţină ı̂ncurcătură!
https://www.geeksforgeeks.org/little-and-big-endian-mystery/
https://en.cppreference.com/w/cpp/types/endian
https://aticleworld.com/little-and-big-endian-importance/ ... OK !!!
https://en.wikipedia.org/wiki/Endianness
ifstream fin("f07.in");
ofstream fout("f07.out");
int main()
{
int a, b;
fin >> a;
fin >> b;
if(a > b)
{
cout << " a este mai mare decat b";
}
else
{
cout << " a NU este mai mare decat b";
}
return 0;
}
Obs: if(x=3) ... in loc de x==3 ... ??? de dat exemplu ... Atenţie ... !!!
99
https://ro.wikipedia.org/wiki/Operator_ternar
100
https://en.wikipedia.org/wiki/%3F:
CAPITOLUL 3. PROGRAMARE C+++ 3.5. INSTRUCŢIUNI REPETITIVE -
STRUCTURI ELEMENTARE DE CONTROL 58
ifstream finput("fa08.in");
ofstream foutput("fa08.out");
int a, b;
int k;
int main()
{
finput >> a;
finput >> b;
//cout<<"k = "<<k;
return 0;
}
ifstream finput("f09.in");
ofstream foutput("f09.out");
int a, b;
int main()
{
finput >> a;
finput >> b;
int k=a;
while(k <= b)
{
cout << k << " : " << k*k << "\n";
k = k+1;
}
return 0;
}
3.5.3 Instrucţiunea do
CAPITOLUL 3. PROGRAMARE C+++ 3.6. INSTRUCŢIUNI DE SALT 59
int main()
{
for(int i=1; i<23; i++)
{
cout<<i<<" ";
if(i%5==0) getchar(); // getc(stdin);
}
return 0;
}
3.7.2 system(“PAUSE”);
int main()
{
for(int i=1; i<23; i++)
{
cout<<i<<" ";
if(i%5==0) getchar(); // getc(stdin);
}
return 0;
}
CAPITOLUL 3. PROGRAMARE C+++ 3.8. TIPURI PREDEFINITE 60
(1) Mulimea valorilor creia i aparine o constant a tipului n cauz, respectiv mulimea valorilor pe
care le poate asuma o variabil, o expresie sau care pot figenerate de o funcie ncadrat n acel
tip
(2) Un anumit grad de structurare (organizare) a informaiei;
(3) Unset de operatori specifici.
(1) Un tip de date determinmulimea valorilor creia i aparine o constant, sau pe care le poate
asuma o variabil sau o expresie, sau care pot fi generate de un operator sau o funcie.
(2) Tipul unei valori precizate de o constant, variabil sau expresie poate fi dedusdin forma sau
din declaraia sa, fr a fi necesar execuia unor procese de calcul.
(3) Fiecare operator sau funcie acceptargumente de un tip precizat i conduce la un rezultat de
un tip precizat.
(4) Un tip presupune un anumit nivel de structurare (organizare) a informaiei.
A type is a purely syntactic label associated with a variable when it is declared. Such definitions
of ”type” do not give any semantic meaning to types.[clarification needed]
Representation
A type is defined in terms of its composition of more primitive typesoften machine types.
Representation and behaviour
A type is defined as its representation and a set of operators manipulating these representations.
Value space
A type is a set of possible values which a variable can possess. Such definitions make it possible
to speak about (disjoint) unions or Cartesian products of types.
Value space and behaviour
A type is a set of values which a variable can possess and a set of functions that one can apply
to these values.
The definition in terms of a representation was often done in imperative languages such as
ALGOL and Pascal, while the definition in terms of a value space and behaviour was used in
higher-level languages such as Simula and CLU.
Classes of data types
Primitive data types
Primitive data types are typically types that are built-in or basic to a language implementation.
Machine data types
Boolean type
Enumerations
Numeric types: integer, floating point, fixed point, Bignum
Composite types: array, record, union, set, object
String and text types: character, string,
Abstract data types:
Other types: Pointers and references, Function types, ...
Type systems:
4.1 Vectori
https://www.geeksforgeeks.org/introduction-to-arrays/
#include <bits/stdc++.h>
int main()
{
int array[100]; // Static Implementation
return 0;
}
#include <bits/stdc++.h>
int main()
{
int* arr = new int[100]; // Dynamic Implementation
63
CAPITOLUL 4. MASIVE DE DATE ÎN C++ 4.2. ŞIRURI DE CARACTERE 64
Dynamic in nature. The size automatically changes as elements are added or removed.
Occupies a lot of memory, due to being dynamic in nature. A typical vector implementation
grows by doubling its allocated space rather than incrementing it by 1. Reallocating memory is
usually an expensive operation in vectors.
https://www.modernescpp.com/index.php/c-core-guidelines-std-array-a
nd-std-vector-are-your-friends
Okay, I can make it short today. Here is a rule of thumb: If you want to add elements to your
container or remove elements from your container, use a std::vector; if not, use a std::array.
std::array and std::vector offer the following advantages:
the fastest general-purpose access (random access, including being vectorization-friendly);
the fastest default access pattern (begin-to-end or end-to-begin is prefetcher-friendly);
the lowest space overhead (contiguous layout has zero per-element overhead, which is cache-
friendly).
Tipuri de date structurate.
Tipuri de date tablou unidimensional https://invat.online/lectia/priveste/988
Tipul tablou (Array )
array vs vector ...
https://towardsdatascience.com/8-common-data-structures-every-progr
ammer-must-know-171acf6a1a42
4.3 Matrice
4.3.1 Implementare statică - array
4.3.2 Implementare dinamică - array
4.3.3 Implementare STL - vector¡***¿
Liniarizare matrice si matrice rare
4.4.4 Heap
struct Test
{
int x, y, z;
} v[3];
int main()
{
int n=3;
v[0]={11,12,13};
v[1]={21,22,23};
v[2]={31,32,33};
for (int i=0;i<n;i++)
{
cout << v[i].x << ", " << v[i].y<< ", " << v[i].z << endl;
}
return 0;
}
struct Test
{
int x, y, z;
};
int main()
{
// Creating a vector of Test
vector<Test> myvec;
int s = myvec.size();
for (int i=0;i<s;i++)
{
// Accessing structure members using their
// names.
cout << myvec[i].x << ", " << myvec[i].y
<< ", " << myvec[i].z << endl;
}
return 0;
}
int main()
{
// We make a pair with first element as normal
// element and second element as another pair.
// therefore 3 elements simultaneously.
vector< pair<int, pair<int, int> > > myvec;
int s = myvec.size();
for (int i=0; i<s; i++)
{
// The elements can be directly accessed
// according to first or second element
// of the pair.
cout << myvec[i].first << ", " << myvec[i].second.first
<< ", " << myvec[i].second.second << endl;
}
return 0;
}
68
Part II
Olimpiada Europeană de
102
Informatică pentru juniori
102
Este organizată după regulile şi standardele Olimpiadei Internaţionale de Informatică (IOI).
Potrivit regulamentului, pot fi ı̂nscrişi elevi din ı̂nvăţământul secundar, cu vârsta de până la 15 ani, fiecare echipă
având doi profesori coordonatori şi maximum 4 elevi.
69
Capitolul 6
103
EJOI 2022
6.1 adjacent
Problema 1 - Perechi adiacente 100 de puncte
Vom numi un şir b1 , b2 , ..., bm bun, dacă bi j bi1 pentru orice i cu 1 & i & m 1.
Se dă un şir bun de n numere ı̂ntregi pozitive a1 , a2 , a3 , ..., an .
Puteţi efectua următoarea operaţie asupra acestui şir:
Alegeţi un indice i (1 & i & n) şi un număr x (1 & x & 10 ). Apoi atribuiţi lui a valoarea x.
9
lungimea şirului.
A doua linie a fiecărui test conţine n numere ı̂ntregi a1 , a2 , ..., an (1 & ai & n), reprezentând
elementele şirului. Se garantează că ai j ai1 pentru 1 & i & n 1 (adică şirul dat este bun).
5
Se garantează că suma valorilor lui n pentru toate testele nu depăşeşte 2 10 .
Date de ieşire
Pentru fiecare test, afişaţi un singur număr ı̂ntreg - cel mai mic număr de operaţii necesare
pentru a obţine un şir ı̂n care sunt exact două valori distincte.
Exemplu
Intrare:
2
5
4 5 2 4 5
2
1 2
Ieşire:
3
0
103
aur: SAVU Ştefan Cătălin, Colegiul Naţional ”I.L. Caragiale”/CJEX, Ploieşti
. aur: VOICU Mihai Valeriu, Liceul Teoretic Internaţional de Informatică, Bucureşti
. argint: CHENGLIN Shang, Liceul Teoretic Internaţional de Informatică, Bucureşti
. argint: REBENGIUC Mircea, C.N. de Informatică ”Tudor Vianu”’, Bucureşti
. argint: DUMITRU Alexandru, C.N. ”I.L. Caragiale” / CJEX, Ploieşti
. argint: DIMA Alexandru, Şcoala Gimnazială Internaţională ”‘Spectrum”’, Cluj Napoca
. btonz: GUBA Daniel, Liceul Teoretic Internaţional de Informatică, Bucureşti
. menţiune de onoare: MATEESCU Alexandru, Liceul Teoretic Internaţional de Informatică, Bucureşti
70
CAPITOLUL 6. EJOI 2022 6.1. ADJACENT 71
Explicaţie
Pentru primul test, o secvenţă optimă de operaţii este:
(4, 5, 2, 4, 5) (2, 5, 2, 4, 5) (2, 5, 2, 4, 2) (2, 5, 2, 5, 2).
Pentru al doilea test, şirul deja conţine doar două valori distincte, deci răspunsul este 0.
Punctaj
1. (20 puncte): Suma valorilor lui n pentru toate testele nu depăşeşte 100
2. (10 puncte): Suma valorilor lui n pentru toate testele nu depăşeşte 500
3. (25 puncte): Suma valorilor lui n pentru toate testele nu depăşeşte 4000
4. (45 puncte): Fără restricţii suplimentare
Subtask 1. Let’s call an array good if all adjacent pairs of elements are different. At the beginning
the array is good, and after each operation the array will stay good. So the ending array must
have the form: [c, d, c, d, ...]; c j d . This means that there are O n possible ending states.
2
(For any ending state with c or d not in r1, 2, ..., nx, it doesn’t matter what the value is exactly,
so there are only O n interesting options for those cases).
For this subtask we can try all pairs.
So we fix some c and d. Let’s call the final array b c, d, c, d, ....
Then we greedily make moves, trying to change elements in a to b. It could happen that a j b
but no greedy move is possible:
a 1, 2, 3, 1, 2
b 1, 2, 1, 2, 1
The last three elements of the array cannot be changed greedily, because this would cause
adjacent equal valued elements.
Such a blockage is always caused by some subarray that is of the form d, c, d, c, ... which is
the desired pattern, but with the wrong parities. Let’s call subarrays which have values d and c at
indices of the wrong parity and that can’t be extended further bad subarrays. It turns out that
9
changing the second element of any bad subarray to 10 is optimal (for the proof, see subtask 2).
So a simple algorithm will try to find a greedy move, if there’s no greedy move, it finds any
starting point of a bad subarray and changes the second element.
This can be implemented to run in O n per iteration, and there are at most O n iterations
4
per pair of c and d, so this will run in O n , with a small constant.
Subtask 2. Instead of simulating the process of converting the array we can calculate the
number of moves needed more directly.
Firstly, for each c and d we find all bad subarrays, with a single for loop.
For a bad subarray of size k it’s optimal to first do k ©2$ extra moves, where we place the
9
value 10 on positions 2, 4, 6, ... of the subarray. After this, the whole subarray can be finished
greedily.
To show that this is the best we can do, let’s consider all possible moves we can make on this
subarray.
When a value in the subarray is replaced, we are always left with two bad subarrays of sizes
l and r, such that k l r 1. Notice that for a bad subarray of size 1, there’s no problem.
Because it is maximal, the elements around it cannot be equal to c and d, but this means the
only element of the subarray can be greedily changed. By induction on the size of the subarray,
and basecases 0 and 1 the lowerbound of k ©2$ extra moves can be proven. The formula for the
number of moves needed will be:
#moves n # of i, such that ai bi = k ©2$
bad subarrays
CAPITOLUL 6. EJOI 2022 6.1. ADJACENT 72
3
Now the time per pair is reduced to O n, and the total complexity is O n .
Subtask 3. It’s intuitively clear that values that appear more frequent are better candidates
for c or d.
2
We can show that instead of O n pairs, we can only examine the O n best pairs. For all
pairs c and d, calculate
and sortsort them increasingly on this quantity. To calculate this value in O 1 per pair, we can
count the number of occurrences of x (1 & x & n) at odd and even indices as a precomputation
step.
Notice that the total number of bad subarrays over all pairs c and d is O n (here we ignore bad
subarrays of length 1, because they don’t change the answer). This is because two bad subarrays
cannot overlap by more than 1 element. So there are only O n pairs of c and d that cannot
immediately be finished by greedy moves.
So by the pigeonhole principle, if we examine more pairs than this, we will always have at least
one pair with no bad subarrays.
After this point no other pairs in the increasing order of greedy moves can give a better answer,
so we can break the loop early.
With this observation we only need to check O n pairs, and the time complexity becomes
2 2
O n or O n log n, depending on the implementation.
Subtask 4. Instead of finding bad subarrays for each pair c and d independently, all bad
subarrays can be found at once, with a single pass through array a, with some simple logic. We
can use a map to store c, d extra moves needed, and add bad subarray size / 2 $ to the map
appropriately.
Now for finding the best c, d pair, iterate through all possible c, the final value of all odd
indices of the array.
For the value of d, we can loop through all d in decreasing order of occeven d (the number of
occurrences of d in even positions). By reusing the same observation as subtask 3, we can break
this loop over d as soon as c, d can be solved with only greedy moves (i.e. it isn’t in the map).
The total number of iterations of the inner for loop is bounded by (size of the map) + n = O n.
This gives an O n log n algorithm, because of the sorting of d and the map. By changing
out the map to a hash map, and changing the sorting algorithm to counting sort, O n is also
possible.
For deterministic linear time, with clever use of a global array that is reused between the
iterations of c, the hashmap is no longer needed. These optimizations were not needed to obtain
the full score.
//template<typename A, typename B> ostream& operator<<(ostream &os, const pair<A, B> &p)
// { return os << ’(’ << p.first << ", " << p.second << ’)’; }
//#define debug(a) cerr << "(" << #a << ": " << a << ")\n";
int main()
{
//-----------------------------------------------------
std::clock_t c_start = std::clock();
auto t_start = std::chrono::high_resolution_clock::now();
auto t1 = clock();
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
vector<int> a(n);
for(int& i : a)
cin >> i, --i;
int ans=n; // just change the numbers to the pattern 10**9-1, 10**9 ...
array<vi,2> cnt = {vi(n),vi(n)};
for(int i=0;i<n;++i)
{
cnt[i%2][a[i]]++;
}
vi ord(n);
iota(all(ord),0);
sort(all(ord),[&](int i,int j) {return cnt[1][i]>cnt[1][j];});
ans = min(ans,cur+cost[{c,d}]);
}
}
// the second for loop runs only O(n) times total (the number of pairs in
the cost map + n iterations)
}
cout << ans << ’\n’;
}
// ----------------------------------------------------------------
auto t2 = clock();
std::clock_t c_end = std::clock();
auto t_end = std::chrono::high_resolution_clock::now();
return 0;
// ----------------------------------------------------------------
}
#include "testlib.h"
#include <sstream>
int main()
//int main(int argc, char * argv[])
{
//-----------------------------------------------------------------------
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/186", // input
(char*)"../tests/186.a", // rezultat corect
(char*)"perechi.out", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
registerTestlibCmd(argc, argv);
int n = 0;
string firstElems;
int extraInAnsCount = 0;
while (!ans.seekEof())
{
ans.readLong();
extraInAnsCount++;
}
int extraInOufCount = 0;
while (!ouf.seekEof())
{
ouf.readLong();
extraInOufCount++;
}
if (extraInAnsCount > 0)
quitf(_wa, "Answer contains longer sequence [length = %d], but output contains %
d elements", n + extraInAnsCount, n);
if (extraInOufCount > 0)
quitf(_wa, "Output contains longer sequence [length = %d], but answer contains %
d elements", n + extraInOufCount, n);
if (n <= 5)
quitf(_ok, "%d number(s): \"%s\"", n, compress(firstElems).c_str());
else
quitf(_ok, "%d numbers", n);
}
/* la verificare apare:
argc = 4
checker
../tests/186
../tests/186.a
perechi.out
----------------------
ok 1 number(s): "199390"
6.2 root
Problema 2 - Unde este rădăcina? 100 de puncte
Aceasta este o problemă interactivă.
Vi se dă un arborearbore cu n noduriU̇n arbore este un graf ı̂n care există un singur drum ı̂ntre
oricare două noduri. De asemenea, se garantează că există cel puţin un nod care este conectat
direct prin câte o muchie de cel puţin alte 3 noduri. Unul dintre noduri este rădăcina arborelui,
iar obiectivul vostru este să găsiţi această rădăcină. Pentru a rezolva problema, veţi putea pune
interogări de forma:
Pentru o mulţime de noduri a1 , a2 , ..., am , verifică dacă cel mai apropiat strămoş comun al
nodurilor din mulţime se află de asemenea ı̂n mulţime.
Un nod v este un strămoş comun al unei mulţimi de noduri S dacă drumurile de la fiecare nod
CAPITOLUL 6. EJOI 2022 6.2. ROOT 76
din S la rădăcină trec prin nodul v. Cel mai apropiat strămoş comun al mulţimii de noduri S este
strămoşul comun al mulţimii S aflat la distanţă maximă faţă de rădăcină.
Interacţiune
Porniţi interacţiunea prin citirea unui singur număr ı̂ntreg n (4 & n & 500) - numărul de
noduri.
Citiţi apoi următoarele n 1 linii. A i-a linie va conţine doi ı̂ntregi a, b (1 & a, b & n), care
semnifică existenţa unei muchii ı̂ntre nodurile a şi b din arbore.
Se garantează că cele n 1 muchii formează un arbore şi că există cel puţin un nod care este
conectat direct prin câte o muchie de cel puţin alte 3 noduri.
Pentru a trimite o interogare, afişaţi mai ı̂ntâi caracterul ” ? ”, apoi numărul ı̂ntreg m, apoi
m numere ı̂ntregi distincte a1 , a2 , ..., am (1 & m & n, 1 & a & n, toate a distincte) - mulţimea de
noduri pentru care vreţi să verificaţi dacă cel mai apropiat strămoş comun se află printre ele.
Ca răspuns, interactorul va afişa ” YES ” dacă cel mai apropiat strămoş comun al mulţimii
interogate este unul dintre nodurile a1 , a2 , ..., am , sau ” NO ” ı̂n caz contrar.
Puteţi pune cel mult 1000 de interogări, dar veţi fi punctaţi diferit ı̂n funcţie de numărul lor.
Afişarea răspunsului final nu se va număra ca interogare. Citiţi cu atenţia secţiunea Punctaj de
mai jos.
Atunci când aţi identificat rădăcina, afişaţi caracterul ” ! ” urmat de un număr ı̂ntreg v
(1 & v & n) - rădăcina. Apoi terminaţi execuţia programului vostru.
După afişarea unei interogări nu uitaţi să afişaţi caracterul pentru final de linie (newline) şi să
goliţi (flush) outputul. Pentru aceasta, folosiţi:
Se garantează că pentru toate testele arborele şi rădăcina sa sunt fixate ı̂nainte de ı̂nceperea
interacţiunii. Cu alte cuvinte, interactorul nu este adaptiv.
Exemplu
Input:
7
4 1
1 2
4 3
3 5
3 6
4 7
Output:
? 2 5 6
Input:
NO
Output:
? 3 6 3 5
Input:
YES
Output:
? 2 1 7
Input:
NO
Output:
? 2 4 6
Input:
YES
Output:
! 4
Explicaţii
CAPITOLUL 6. EJOI 2022 6.2. ROOT 77
Subtask 1. You can just ask about each possible subset of nodes. As we will show later, for
each two root candidates there is a query for which their answers would be different, so we can
n
determine the root uniquely. It’s enough to ask 2 1 queries.
CAPITOLUL 6. EJOI 2022 6.2. ROOT 78
Subtask 2. Let’s ask a query for each pair of nodes. Clearly, if root is v, then the answer to
each query r; v for v j r is YES. If there is only one node that gives YES for each query, it must
be the root. Suppose that some node r1 j r also gives YES for each query in which it’s included.
If r is not a lead, then there is a node v j r1 ; v j r such that LCA r1 ; v r, contradiction. So,
r must be a leaf.
Suppose that there is another leaf r1 that gives YES for all queries. Then consider any leaf
v different from r, r1 (in a graph in which at least one degree is at least 3, there are at least 3
leaves). Then, LCA r1 , v can’t be equal to r1 and v, so the answer would be NO. Contradiction.
So, if there is only one such node, it’s the root, otherwise it’s the unique leaf among the nodes
n n
which gave YES for each query in which they were involved. It’s enough to ask 2 queries.
Subtask 3. There are many different approaches that achieve various bounds. We will describe
the solutions which work for n 500 in 10 queries, and in 9 queries.
10 queries: Suppose that r is the root. First, let’s ask a query about all leaves. Their LCA
has to be r (if r is a leaf, it’s clear; otherwise, there is a leaf in each of the subtrees of r). So, we
can determine if r is a leaf with this query.
Now if r is not a leaf, let’s ask queries for sets, which contain all leaves. We will get YES iff
we have included r into the set. So, we can do binary search on the non-leaf nodes, discarding
roughly half at each time. This way, we will need at most 9 queries.
Suppose now that r is a leaf. If we ask a question about some subset of the leaves of size '
2, the answer will be YES if and only if r is in the chosen set. So, we can once again do binary
search on the leaves, until we get at most 2 candidates r1 , r2 . At that point, we can ask a query
for nodes r2 , r3 , where r3 is any other leaf, to determine if r2 is the root. This way, we will also
need at most 9 queries.
Adding the initial query about all leaves, we are done in 10 queries.
9 queries: Our algorithm loses one query at the first step: it might be the case that the
number of remaining candidates is n - some small number (when the root is a leaf, and almost all
nodes are leaves, for example). Let’s try to solve this issue.
Let’s arrange our nodes in the following fashion: first all leaves, then all non-leaves. What
happens if we ask a query about the some prefix of this order of length at least 2? Let’s consider
two cases.
Our prefix contains all the leaves, and, maybe, some other nodes. Then their LCA is r, and
we will get YES if and only if r is in that prefix.
Our prefix is some subset of the leaves. Then, if r is among them, we will get YES, otherwise
their LCA would be some node different from any of them, so we will get NO. Once again,
we will get YES if and only if r is in that prefix.
So, we can do binary search on this order of nodes! The only exception is when we end up
with a prefix of length 2. Then, as in previous subtask, we should ask one of these leaves with
one of other leaves.
This solves the problem in 9 queries.
int deg[MAX];
VI G[MAX];
int P[MAX];
bool T[MAX];
auto t1 = clock();
VI A, B;
FOR(i,0,n) {
if (deg[i] == 1)
A.push_back(i);
else
B.push_back(i);
}
for(auto x: B)
A.push_back(x);
int L = 1;
int R = n;
FOR(i,0,50) {
cout << "? 1 1" << endl;
string res;
cin >> res;
}
while (R - L > 1) {
CAPITOLUL 6. EJOI 2022 6.2. ROOT 80
int M = (L + R) / 2;
VI Q;
FOR(i,0,M) {
Q.push_back(A[i]);
}
if (L == 1) {
dfs(A[0], -1);
int v = A[1];
while (v != -1) {
T[v] = true;
v = P[v];
}
cout << "? 2 " << A[0] + 1 << ’ ’;
FOR(i,0,n) {
if (!T[i]) {
cout << i + 1 << endl;
break;
}
}
string res;
cin >> res;
if (res == "YES")
R = 1;
}
cout << "! " << A[R - 1] + 1 << endl;
// ----------------------------------------------------------------
auto t2 = clock();
std::clock_t c_end = std::clock();
auto t_end = std::chrono::high_resolution_clock::now();
return 0;
// ----------------------------------------------------------------
}
int main()
//int main(int argc, char * argv[])
//int main(int argc, char **argv)
{
//-----------------------------------------------------------------------
int argc=4;
CAPITOLUL 6. EJOI 2022 6.3. TREE 81
char* argv[] =
{
(char*)"checker",
(char*)"../tests/145", // input
(char*)"../tests/145.a", // rezultat corect
(char*)"root.out", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
registerTestlibCmd(argc, argv);
int n = inf.readInt();
int v = inf.readInt();
int g = inf.readInt();
int q = ouf.readInt();
if (g == 0) {
quitf(_ok, "OK");
}
if (g == 1) {
quitf(_ok, "OK");
}
if (g == 2) {
quitf(_ok, "OK");
}
int max_points = 83;
int points = ((q <= 9) ? 83: max(10, int(83 * (1 - log(q - 6.0) / 7))));
if (points == 83) {
quitf(_ok, "OK");
} else {
quitp(points, "OK");
}
}
6.3 tree
Problema 3 - Arbore de acoperire limitat 100 de puncte
Vi se dă un graf neorientat, conex, cu muchii ponderate cu n vârfuri şi m muchii. În acest
graf nu există bucle proprii (adică nu există muchie care să unească un vârf cu el ı̂nsuşi), dar pot
exista mai multe muchii ı̂ntre anumite perechi de vârfuri.
Prietenul tău ţi-a spus următoarele despre acest graf:
Toate ponderile muchiilor sunt numere ı̂ntregi distincte din intervalul 1, m. Cu alte cuvinte,
ele trebuie să formeze o permutare a numerelor ı̂ntregi de la 1 la m.
Ponderea celei de-a i-a muchii este din intervalul l, r pentru fiecare i de la 1 la m.
Muchiile cu indicii 1, 2, ..., n 1 (primele n 1 muchii din datele de intrare) formează un
arbore de acoperire minim al acestui graf.
Vreţi să ştiţi dacă această configuraţie este posibilă. Determinaţi dacă există astfel de atribuiri
de ponderi ale muchiilor pentru care aceste condiţii sunt valabile şi, dacă da, găsiţi una dintre ele.
Reamintim că, un arbore de acoperire al unui graf este orice submulţime de muchii care
formează un arbore (graf conex cu n noduri şi n 1 muchii).
Arborele de acoperire minim al unui graf este orice arbore de acoperire cu cea mai mică sumă
de ponderi dintre toţi arborii de acoperire ai grafului.
CAPITOLUL 6. EJOI 2022 6.3. TREE 82
Date de intrare
Prima linie conţine un singur număr ı̂ntreg t ( 1 & t & 10 ) - numărul de teste.
5
Prima linie a fiecărui test conţine două numere ı̂ntregi n şi m (1 & n1 & m & 5 5
10 ) -
numărul de vârfuri şi, respectiv, numărul de muchii.
Linia i dintre următoarele m linii conţine patru numere ı̂ntregi u, v, l, r (1 & u $ v & n,
1 & l & r & m) - indicând că există o muchie care leagă nodurile u , v şi că ponderea acesteia ar
trebui să fie ı̂n intervalul l, r.
Se garantează că, pentru fiecare test, muchiile cu indicii 1, 2, ..., n 1 formează un arbore de
acoperire al grafului dat.
5
Se garantează că suma valorilor m din toate testele nu depăşeşte 5 10 .
Date de ieşire
Pentru fiecare test, dacă nu există un vector de ponderi ale muchiilor care să ı̂ndeplinească
condiţiile, se afişează ” NO ” pe prima linie.
În caz contrar, pe prima linie se afişează ” YES ”. Pe a doua linie, se afişează m numere ı̂ntregi
w1 , w2 , ..., wm (1 & w & m, toate valorile wi sunt distincte) ce reprezintă ponderile muchiilor
(unde wi este ponderea atribuită celei de-a i-a muchii din datele de intrare).
În cazul ı̂n care există mai multe răspunsuri, se afişează oricare dintre ele.
Pentru afişarea datelor de ieşire puteţi utiliza litere mari şi/sau litere mici (de exemplu, ” YES
”, ” Yes ”, ” yes ”, ” yEs ”, ” yEs ” vor fi considerate ca răspunsuri corecte).
Exemplu
Date de intrare:
3
4 6
1 2 1 3
1 3 2 6
3 4 1 2
1 4 2 5
2 3 2 4
2 4 4 6
4 4
1 2 2 2
2 3 3 3
3 4 4 4
1 4 1 4
5 6
1 2 1 1
2 3 1 2
3 4 2 4
4 5 6 6
1 4 4 6
1 4 5 6
Date de ieşire:
YES
2 3 1 5 4 6
NO
YES
1 2 3 6 4 5
Punctaj
1. (4 puncte): l r (1 & i & m)
2. (6 puncte): Suma valorilor m din toate testele nu depăşeşte 10.
3. (10 puncte): Suma valorilor m din toate testele nu depăşeşte 20.
CAPITOLUL 6. EJOI 2022 6.3. TREE 83
Subtask 1. For each edge, its weight is known. There is need to check that edges can have
different weights from the range 1, m and that edges with indices 1, 2, ..., n 1 form a minimum
spanning tree of the given graph. The last can be done using any suitable algorithm. Time
complexity: O m log m or O m.
Subtask 2. Just try all possible assignments for the weights of the edges and for each one check
compliance with the rules described in the statement. Time complexity: O m! m.
Subtask 3. Use dynamic programming on subsets of the edges. Lets denote dpS as a boolean
variable indicating that there is assignment of the weights 1, 2, ..., ¶S ¶ to the edges from S, such
that there is no rules were broken. Here by ”breaking mst rule” we mean assigning to a non-
spanning-tree edge such value that this edge will be taken into minimum spanning tree when
m
considering it in the process of execution of Kruskal’s algorithm. Time complexity: O 2 m.
Subtask 4. The same idea as in the Subtask 5, but with worse algorithm complexity. Also
3
possible to solve using ”matching in bipartite graph” approach. Time complexity: O m or
2
O m .
Subtask 5. We see that for this subtask there is no ”mst rule”. So we just need to find an
assignment of the edge weights using integers from the range 1, m. It is possible to do this
using greedy approach: set 1 to the edge that have li 1 with the minimum possible ri . This is
true, since any valid assignment can be changed without losing validity to be compatible with the
mentioned greedy assignment. So the overall greedy algorithm is the following: for each i from 1
to m set i as edge weight for the edge with lj & i with the minimum possible rj , between all edges
with unset weight. Time complexity: O m log m.
Subtask 6. Lets call the non-spanning-tree edge as ”special”. After the assigning a value for the
special edge we need to be sure that there exist possibility of assigning for spanning-tree edges
weights from the range 1, m (except the already assigned one). Lets find all suitable possible
values that satisfy this condition, choose the greatest one from the range of the special edge and
update rj for the edges on the cycle to be sure that they are smaller that the value we assigned
to the special edge.
For finding all suitable possible values that satisfy mentioned condition we can use Hall’s
104
marriage theorem on the bipartite graph (first part consists of vertices corresponding to the
edges and second part consists of vertices corresponding to possible edge weights): value k is
suitable if and only if there is no L, R such that L & k & R and R & L 1 & (# i such that
1 & i & n 1 and L & li & ri & R. Time complexity: O m log m.
Subtask 7. Lets call pair of edges (etree , enon tree ) interesting (here etree is a spanning-tree
edge and enon tree is a non-spanning-tree edge) if etree lies on the simple path in the expected
minimum spanning tree between vertices that connects enon tree . It is easy to see that for each
104
https://en.wikipedia.org/wiki/Hall%27s_marriage_theorem
CAPITOLUL 6. EJOI 2022 6.3. TREE 84
With such modifications, any assignment found by the greedy algorithm from the Subtask 5
will satisfy ”mst rule”. Time complexity: O mcdotn.
Subtask 8. The same idea as in the Subtask 7, but with better algorithm complexity. You can
use segment tree to do mentioned updates. Time complexity: O m log n.
Subtask 9. The same idea as in the Subtask 7, but with better algorithm complexity. You can
105 2
use heavy-light decomposition to do mentioned updates. Time complexity: O m log n.
Subtask 10. The same idea as in the Subtask 7, but with better algorithm complexity. You can
106
use binary lifting approach or non-trivial heavy-light decomposition approach to do mentioned
updates. Time complexity: O m log n.
#include<bits/stdc++.h>
int n, m;
}
void update(int u, int v, int val)
{
if (h[u] < h[v]) swap(u, v);
for (int k = LOG - 1; k >= 0; k--) {
if (h[u] - (1 << k) >= h[v]) {
mn[k][u] = min(mn[k][u], val);
u = up[k][u];
}
}
if (u == v) return;
for (int k = LOG - 1; k >= 0; k--) {
if (up[k][u] != up[k][v]) {
mn[k][u] = min(mn[k][u], val);
mn[k][v] = min(mn[k][v], val);
u = up[k][u];
v = up[k][v];
}
}
assert(up[0][u] == up[0][v]);
mn[0][u] = min(mn[0][u], val);
mn[0][v] = min(mn[0][v], val);
}
vector<int> ev[maxN];
int ans[maxN];
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) {
g[i].clear();
}
for (int i = 1; i <= m; i++) {
ev[i].clear();
}
for (int k = 0; k < LOG; k++) {
for (int i = 0; i <= n; i++) {
up[k][i] = mx[k][i] = 0;
mn[k][i] = m;
}
}
for (int i = 1; i <= m; i++) {
cin >> u[i] >> v[i] >> l[i] >> r[i];
if (i < n) {
g[u[i]].emplace_back(v[i], i);
g[v[i]].emplace_back(u[i], i);
}
}
dfs(1, -1);
CAPITOLUL 6. EJOI 2022 6.3. TREE 86
int main()
{
//-----------------------------------------------------
std::clock_t c_start = std::clock();
auto t_start = std::chrono::high_resolution_clock::now();
auto t1 = clock();
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
#ifdef DEBUG
freopen("input.txt", "r", stdin);
#endif
int tst;
cin >> tst;
while (tst--) {
solve();
CAPITOLUL 6. EJOI 2022 6.3. TREE 87
}
return 0;
}
struct edge {
int u, v;
int l, r;
edge() {
u = v = 0;
l = r = 0;
}
};
int n,m;
vector<edge> edges;
vector<int> p;
int f(int v) {
return p[v] == v ? v : p[v] = f(p[v]);
}
string upper(string s) {
for(char &c : s) {
c = toupper(c);
}
return s;
}
--p;
if (edge_with_value[p] != -1) {
in.quitf(_wa, "p is not a permutation");
}
edge_with_value[p] = i;
}
p.resize(n);
iota(p.begin(), p.end(), 0);
for (int i = 0; i < m; ++i) {
int edge_id = edge_with_value[i];
int u = f(edges[edge_id].u);
int v = f(edges[edge_id].v);
return true;
}
}
void check_test() {
n = inf.readInt();
m = inf.readInt();
edges.resize(m);
for (int i = 0; i < m; ++i) {
edges[i].u = inf.readInt();
edges[i].v = inf.readInt();
edges[i].l = inf.readInt();
edges[i].r = inf.readInt();
--edges[i].u;
--edges[i].v;
}
int main()
//int main(int argc, char *argv[])
{
//-----------------------------------------------------------------------
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/238", // input
(char*)"../tests/238.a", // rezultat corect
(char*)"tree.out", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
if (part_but_not_jury) {
quitf(_fail, "participant found the answer but jury didn’t");
} else if (jury_but_not_part) {
quitf(_wa, "jury found the answer but participant didn’t");
} else {
quitf(_ok, "all is ok");
}
}
6.4 game
Problema 4 - Joc cu numere 100 de puncte
Doi jucători joacă un joc. Ei au primit un şir a1 , a2 , ..., an , precum şi un şir b1 , b2 , ..., bm .
Jocul constă din m runde. Jucătorii participă la runde alternativ. Pe parcursul celei de-a i-a
CAPITOLUL 6. EJOI 2022 6.4. GAME 89
runde (pentru i de la 1 la m) jucătorul corespunzător (primul jucător, dacă i este impar, şi al
doilea dacă i este par) are de făcut exact una dintre următoarele:
şterge toate elementele din şirul a care sunt divizibile cu bi ,
şterge toate elementele din şirul a care nu sunt divizibile cu bi .
Primul jucător doreşte să minimizeze suma elementelor rămase ı̂n şirul a după toate cele m
runde, iar al doilea doreşte să o maximizeze. Aflaţi suma elementelor rămase ı̂n şirul a după toate
cele m runde, dacă ambii jucători joacă optim.
Date de intrare
Prima linie conţine doi ı̂ntregi n, m (1 &n&2 4
10 , 1 &m&2 5
10 ) - lungimea şirului a şi
numărul de runde ale jocului.
A doua linie conţine n ı̂ntregi a1 , a2 , ..., an (4 10
14
& ai & 4 14
10 ) - elementele şirului a.
A treia linie conţine m ı̂ntregi b1 , b2 , ..., bm (1 & bi &4 14
10 ) - elementele şirului b.
Date de ieşire
Afişaţi un singur ı̂ntreg - suma elementelor rămase ı̂n şirul a după toate cele m runde dacă
ambii jucători joacă optim.
Exemple
Date de intrare 1:
6 2
2 2 5 2 2 7
2 5
Date de ieşire 1:
Date de intrare 2:
5 1
-5000111000 -5000222000 -15 5 2
5
Date de ieşire 2:
-10000333010
Explicaţii
În primul exemplu, o posibilă desfăşurare a jocului este următoarea:
Runda 1: primul jucător şterge din a toate elementele divizibile cu 2. şirul a devine (5, 7).
Runda 2: al doilea jucător şterge din a toate elementele divizibile cu 5. şirul a devine (7).
Dacă el ar şterge din a toate elementele nedivizibile cu 5, a ar deveni (5), care ar avea o
sumă mai mică a elementelor şi prin urmare nu ar fi de dorit pentru al doilea jucător.
Punctaj
1. (3 puncte): m 1
2. (6 puncte): bi1 bi (1 & i $ m), adică toate elementele şirului b sunt egale
3. (15 puncte): bi1 mod bi 0 (1 & i $ m)
4. (9 puncte): 1 & m & 7
5. (11 puncte): 1 & m & 20
6. (15 puncte): 1 & m & 100
(18 puncte): 1 & ai , bi & 10
9
7.
8. (11 puncte): m mod 2 0, b2i1 b2i (1 & i & m 2
)
9. (12 puncte): Fără restricţii suplimentare
CAPITOLUL 6. EJOI 2022 6.4. GAME 90
Subtask 1. In the first subtask m 1 so you can find two sums s1 and s2 : the sum of all
elements that are divisible by b1 and the sum of all elements that are not divisible by b1 . Then
the answer is min s1 , s2 because the first player wants to minimize the sum of the remaining
elements. Time complexity: O n.
Lemma 1. Before describing the solution for each individual subtask let’s prove the following
lemma: if both players can remove all the elements from the array a using only their own rounds,
then the answer is 0. Indeed, in such a case both players can make the sum of the remaining
elements in the array a equal to 0 regardless of the actions of the second player. The first player
wants to minimize the sum, therefore the answer is not bigger than zero. At the same time, the
second player wants to maximize the sum, therefore the answer is not less than zero. Thus the
only possible answer is 0.
Subtask 2. In the second subtask two own rounds are enough for the first player to remove
all the elements: he can remove all the numbers that are divisible by b1 and are not divisible
by b3 . At the same time, only one own round is enough for the second player to remove all the
elements: he can make an opposite operation to the first player due to the condition b1 b2 . Thus
by the lemma 1 the answer is 0 for m % 2. For m 2 the answer is ©max 0, min s1 , s2 . Time
complexity: O n.
Subtask 3. In the third subtask two own rounds are enough for each player to remove all the
elements: the first player can remove all the numbers that are divisible by b1 and are not divisible
by b3 , and the second player can do the same using b2 and b4 . Thus by the lemma 1 the answer is
0 for m % 3. For m & 3 you can either solve the problem recursively by considering each possible
game scenario or consider up to 8 cases manually. Time complexity: O n.
Subtask 4. In the fourth subtask no additional observations are required. The entire game
can be simulated recursively: you can represent the state of the game as a pair operations, pos,
where operations is an array with chosen operations and pos is a current round. Then at each
state of the recursion you can try to make all two possible operations and select the best one. The
m
total number of states is O 2 and for each final state with pos m you can calculate the sum
m
of the remaining elements in O nm. Therefore such a solution works in O 2 nm.
Subtask 5. In the fifth subtask you can modify recursion in the following way: instead of
representing the state of the game as a pair operations, pos you can represent it as a pair a, pos,
where a is an array with remaining elements and pos is a current round. Then at each state of
the recursion you can try to make all two possible operations and select the best one. The total
m
number of states is O 2 but the total size of all arrays a across all states is only O nm due to
the fact that each initial element of the array a is contained in exactly m states. Therefore such
m
a solution works in O 2 nm. See the following code on Python for a better understanding.
def solve(a, pos):
if pos == len(b):
return sum(a)
na = [[], []]
for x in a:
na[(x % b[pos]) == 0].append(x)
return [min,max][pos % 2](solve(na[0],pos+1),solve(na[1],pos+1))
n, m = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
print(solve(a, 0))
m
Subtask 6. In the sixth subtask you can notice that the majority of O 2 states inside the
recursion have an empty array a that allows to immediately return 0 as a result:
CAPITOLUL 6. EJOI 2022 6.4. GAME 91
Subtask 7. In the seventh subtask ai ' 1 that means that the final sum of the remaining
elements is always non-negative. It simplifies the proof of the lemma 1 because now the goal of the
first player is to remove all the elements from the array a. Also it can be proven that the answer
is equal to 0 when mge19 under the constraint ai & 10 . Such proof is left as an exercise for the
9
reader (see bonus section). Such a fact means that the only difference from the fifth subtask is
that we can just output 0 when m % 20.
Subtask 8. In the eighth subtask the second player can always remove all the elements by
making the opposite second operation. It means that the answer is always non-negative. When the
answer is positive the only strategy for the second player is to repeat the corresponding operations
m©2
of the first player. It allows us to speed up the solution from the fifth subtask to O 2 nm
which is ok for the m & 40. See the solution for the next subtask to understand what to do in
case m % 40.
Subtask 9. For the full solution you can notice that O log n own rounds are enough for
each player to remove all the elements. Indeed, at each round one of the two possible operations
removes at least half of all remaining elements, therefore *log2 n0 rounds are always enough to
remove all the elements. It means that the only difference from the sixth subtask is that we can
just output 0 when m % 100 by the lemma 1.
Bonus. What is the maximum value of m where the answer is not equal to zero?
long long solve(const vector<long long> &a, const vector<long long> &b, int pos) {
if (pos == b.size()) {
return accumulate(a.begin(), a.end(), 0LL);
}
vector<long long> na[2];
for (long long x : a) {
na[(x % b[pos]) == 0].push_back(x);
}
if (pos % 2) {
return max(solve(na[0], b, pos + 1), solve(na[1], b, pos + 1));
}
return min(solve(na[0], b, pos + 1), solve(na[1], b, pos + 1));
}
int main()
{
//-----------------------------------------------------
std::clock_t c_start = std::clock();
auto t_start = std::chrono::high_resolution_clock::now();
auto t1 = clock();
ios_base::sync_with_stdio(0);
cin.tie(0);
int n, m;
CAPITOLUL 6. EJOI 2022 6.4. GAME 92
// ----------------------------------------------------------------
auto t2 = clock();
std::clock_t c_end = std::clock();
auto t_end = std::chrono::high_resolution_clock::now();
return 0;
// ----------------------------------------------------------------
}
#include <string>
pattern pnum("0|-?[1-9][0-9]*");
int main()
//int main(int argc, char * argv[])
{
//-----------------------------------------------------------------------
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/161", // input
(char*)"../tests/161.a", // rezultat corect
(char*)"game.out", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
string ja = ans.readWord();
string pa = ouf.readWord();
CAPITOLUL 6. EJOI 2022 6.5. PERMUTATIONS 93
if (!isNumeric(ja))
quitf(_fail, "%s is not a valid integer", compress(ja).c_str());
if (!ans.seekEof())
quitf(_fail, "expected exactly one token in the answer file");
if (!isNumeric(pa))
quitf(_pe, "%s is not a valid integer", compress(pa).c_str());
if (ja != pa)
quitf(_wa, "expected ’%s’, found ’%s’", compress(ja).c_str(), compress(pa).c_str
());
6.5 permutations
Problema 5 - LCS al permutărilor 100 de puncte
Pentru două şiruri x şi y, definim LCS x, y ca lungimea celui mai lung subşir comun al
acestora.
Se dau 4 numere ı̂ntregi n, a, b, c. Determinaţi dacă există 3 permutări p, q, r de numere
ı̂ntregi de la 1 la n, astfel ı̂ncât:
LCS p, q a
LCS p, r b
LCS q, r c
Dacă există astfel de permutări, determinaţi orice triplet de permutări care respectă cerinţa.
O permutare p a numerelor ı̂ntregi de la 1 la n este un şir de lungime n cu proprietatea că
toate elementele sunt ı̂ntregi distincţi din intervalul 1, n. Spre exemplu, (2, 4, 3, 5, 1) este o
permutare a numerelor ı̂ntregi de la 1 la 5, ı̂n timp ce (1, 2, 1, 3, 5) şi (1, 2, 3, 4, 6) nu sunt.
Un şir c este un subşir al şirului d dacă c poate fi obţinut din d prin ştergerea câtorva (posibil,
zero sau toate) elemente. Spre exemplu, (1, 3, 5) este un subşir al şirului (1, 2, 3, 4, 5), ı̂n timp
ce (3, 1) nu este.
Cel mai lung subşir comun al şirurilor x şi y este cel mai lung şir z care este subşir atât
pentru x, cât şi pentru y. Spre exemplu, cel mai lung subşir comun al şirurilor x 1, 3, 2, 4, 5 şi
y 5, 2, 3, 4, 1 este z 2, 4 ı̂ntrucât este subşir al ambelor şiruri şi este cel mai lung astfel de
subşir. LCS x, y reprezintă lungimea celui mai lung subşir comun, care ı̂n cazul de mai devreme
este 2.
Date de intrare
Datele de intrare conţin mai multe scenarii de test. Prima linie a datelor de intrare conţine un
singur număr ı̂ntreg t (1 & t & 10 ) - numărul de teste. După care urmează descrierea testelor.
5
Fiecare test este descris printr-o singură linie şi conţine 5 numere ı̂ntregi n, a, b, c, output
(1 & a & b & c & n & 2 10 , 0 & output & 1).
5
Dacă output 0, determinaţi doar dacă există astfel de permutări. Dacă output 1, trebuie,
de asemenea, să determinaţi un astfel de triplet de permutări, dacă există.
5
Se garantează că suma valorilor n pentru toate scenariile de test nu depăşeşte 2 10 .
Date de ieşire
Pentru fiecare test, afişaţi pe o singură linie ” YES ”, dacă există astfel de permutări p, q, r,
şi ” NO ” ı̂n caz contrar. Dacă output 1, şi există astfel de permutări, afişaţi ı̂ncă trei linii:
Pe prima linie afişaţi n numere ı̂ntregi p1 , p2 , ..., pn (1 & p & n, toate pi distincte) - elementele
permutării p.
CAPITOLUL 6. EJOI 2022 6.5. PERMUTATIONS 94
Pe a doua linie afişaţi n numere ı̂ntregi q1 , q2 , ..., qn (1 & q & n, toate q distincte) - elementele
permutării q.
Pe a treia linie afişaţi n numere ı̂ntregi r 1, r2 , ..., rn (1 & r & n, toate r distincte) - elementele
permutării r.
Dacă există mai multe triplete corecte, afişaţi oricare dintre acestea.
Puteţi afişa răspunsul cu litere mici sau mari (de exemplu, ”YES”, ”Yes”, ”yes”, ”yEs”, ”yEs”
vor fi considerate răspunsuri corecte).
Exemple
Date de intrare:
8
1 1 1 1 1
4 2 3 4 1
6 4 5 5 1
7 1 2 3 1
1 1 1 1 0
4 2 3 4 0
6 4 5 5 0
7 1 2 3 0
Date de ieşire:
YES
1
1
1
NO
YES
1 3 5 2 6 4
3 1 5 2 4 6
1 3 5 2 4 6
NO
YES
NO
YES
NO
Explicaţii
În primul test, LCS 1, 1 este 1.
În al doilea test, se poate demonstra că astfel de permutări nu există.
În al treilea test, unul dintre exemple este p 1, 3, 5, 2, 6, 4, q 3, 1, 5, 2, 4, 6, r
1, 3, 5, 2, 4, 6. Este uşor să observăm că:
Subtask 3. Note that if LCS q, r n, we must have q r, so we also must have a b. We are
still considering p 1, 2, ..., n. Also, note that LCS 1, 2, ..., n, q is just equal to the length of
the longest increasing subsequence of q.
Now, we need to check if there exists a permutation with LIS q a (from now on, by LIS q
I will denote the length of the longest increasing subsequence of q). It turns out that it exists for
each 1 & a & n.
Indeed, it’s enough to consider q n, n 1, ..., a 2, a 1, 1, 2, ..., a.
Subtask 4. If LCS p; q 1, then q must be the reverse of p. In our case, we would have
p 1, 2, ..., n, q n, n 1, ..., 1. Note that LCS n, n 1, ..., 1, r LDS r for any
permutation, where by LDS r we denote the length of the longest decreasing subsequence of r.
So, we just need to determine if there exists a permutation of length n with LIS b and
LDS c. Here, the ErdősSzekeres theorem might be useful. It states that in any sequence with
length r 1 s 1, there is an increasing subsequence of length r, or a decreasing subsequence
of length s. We will use it in the following form: LIS pLDS p ' n (indeed, if LIS pLDS p &
n 1, then the subsequence of length n would have an increasing subsequence of length LIS p 1,
or a decreasing subsequence of length LDS p 1.
So, we must have bc ' n. Is this condition sufficient? Sadly, no. Consider b c n, for
example. We would have to have p q r, but p j q (for n % 1).
Then, we might notice the second condition: LCS p LDS p & n 1 for any permutation
p of length n. Indeed, any increasing subsequence may have at most 1 common element with any
decreasing one, so at most one of n elements can contribute to both LCS and LDS, and others
can contribute to at most one of them.
So, we get: b c & n 1, bc ' n. Are these conditions sufficient? Turns out, yes. Consider
permutation c, c 1, ..., 1, 2c, 2c 1, ..., c 1, 3c, ..., bc, bc 1, ..., bc c 1 of integers from 1 to
bc. It’s easy to see that its LIS is b, and its LDS is c. (For example, the argument for LDS: it
clearly has an increasing subsequence c, 2c, ..., bc, but also is split into b decreasing blocks, none
of which can contain more than one element from LIS).
Consider some subsequence of this permutation, which contains elements c, 2c, ..., bc, as well as
elements c, c 1, ..., 1 (c in written twice, yes) n 1 elements in total. Any such subsequence will
have LIS b and LDS c. As b c 1 & n & bc, we can take some extra n b c 1 elements
CAPITOLUL 6. EJOI 2022 6.5. PERMUTATIONS 96
of this permutation, and obtain a sequence with LIS b and LDS c of length n. Then, we can
just ”compress” the sequence to the permutation by mapping different values to 1, 2, ..., n in the
relative order.
Subtask 5. In some sense, this subtask was included so that participants would be able to check
if their criteria were correct, basically guessing before getting to the actual construction. That’s
what we are going to do here, leaving the proof and the construction for the subtask 6.
Let’s try to guess these criteria. We already know some criteria for the case a 1. Maybe we
can generalize them somehow?
First, let’s try to get something similar to LIS p LDS q & n 1. Consider common
subsequences of p, r and q, r. If their lengths are b, c correspondingly, they must have at least
b c n elements in common. These common elements would form a common subsequence of p, q
so b c n & a, or b c & a n.
Now, let’s try to get something similar to LIS pLDS p ' n. I claim, that
LCS p, q LCS q, rLCS p, r ' n. Proof: suppose that abc & n. As p 1, 2, ..., n, we get that
LIS q a
LDS q ' n2 ' bc 1. Consider some decreasing subsequence of q of length bc 1.
Let’s look at how the elements of this subsequence are situated in r. No b 1 of these elements
can form an increasing subsequence in r (as then we would have LCS p, r ' b 1. No c 1 of
these elements can form a decreasing subsequence in r (as then we would have LCS q, r ' c 1.
107
But at least one of these has to hold, by the Erdős-Szekeres theorem ! Contradiction.
So, we found two necessary conditions:
bc&an
abc & n
It turns out that these conditions are actually sufficient. We will prove this in the next section.
Subtask 6. Let’s prove that for such a, b, c, n there always exists such a triple of permutations.
We will prove this by induction. We already know this is the case if a 1, and it’s clear for n 1.
Now, suppose that it’s true for all tuples a1 , b1 , c1 , n1 with a1 & a, b1 & b, c1 & c, n1 & n.
Suppose that b c & a n and abc ' n. If a % 1 and a 1 b 1 c 1 ' n 1, then we know
that there is such a triple of permutations for tuple a 1, b 1, c 1, n 1 as well. Consider
these permutations p1 , q1 , r1 . Let’s append n to each of them. Clearly, the LCS of each pair will
increase by precisely 1, so we would get the desired outcome.
Now, let’s provide a construction for the case abc n. Let’s take:
p 1, 2, ..., abc
q abc a 1, abc a 2, ..., abc, abc 2a 1, abc 2a 2, ..., abc a, ..., 1, 2, ..., a (bc
increasing blocks, each of length a)
r ac, ac 1, ..., 1, 2ac, 2ac 1, ..., ac 1, ..., abc, abc 1, ..., abc ac 1 (b decreasing blocks,
each of length ac)
It’s easy to see that LIS q a and LIS r b, it only remains to prove that LCS q; r c.
Sequence ac, a 1c, ..., 2c, c is a subsequence of both. Suppose that some sequence of length c 1
is a subsequence of both. If some two elements x $ y of it are from different blocks of length ac
(here I mean blocks ac, ac 1, ..., 1, 2ac, 2ac 1, ..., ac 1, ..., abc, abc 1, ..., abc ac 1,
then in q x goes after y, and in r before, which is impossible. So, they all must be from the same
block, say, kac, kac 1, ..., k 1ac 1.
Then, this subsequence must be decreasing. However, the elements kac, kac1, ..., k 1ac1
in q go in order (kac a 1, kac a 2, ..., kac, kac 2a 1; kac 2a 2, ..., kac a, ...,
k 1ac 1, k 1ac 2, ..., k 1ac a) - that is, c increasing blocks, each of size a. So, it
can’t have decreasing subsequence of length c 1 (as some two elements would have to be in the
same block). Contradiction.
How to use this construction for n abc to get construction for smaller n, the same way as we
did in the case a 1? Let’s select elements 1, 2, ..., a, 1, ac 1, 2ac 1, ..., b 1ac 1, ac c 1,
ac 2c 1, ..., 1 (1 appears in all 3 of these sequences). We want to take some subset of size n
of integers from 1 to abc, containing all the a b c 2 elements above, and remove from each
107
https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93Szekeres_theorem
CAPITOLUL 6. EJOI 2022 6.5. PERMUTATIONS 97
of p, q, r all elements not contained in this subset (and later ”compress” by mapping k-th largest
number among selected to k). If we do this, we will get precisely LCS p, q a, LCS p, r b,
LCS q, r c). We can do this when a b c 2 & n.
If we haven’t succeeded, we have the following conditions:
a 1 b 1 c 1 ' n
a 1 b 1 c 1 & n 2
When is xyz & x y z 2 possible in general for positive integers x & y & z?
If x ' 2, we get xyz ' 4z % x y z % x y z 2, so we must have x 1, or yz & y z 1.
For y ' 2, we get yz ' 2z ' y z % y z 1, so we must have y 1. In this case, we
get a b 2, and c 1 ' n, c 1 & n 2, implying c n 1. So, the only remaining case is
2, 2, n 1, n (when n ' 3).
For this case, there is a simple construction:
p 1, 2, ..., n
q n, n 1, ..., 5, 4, 3, 1, 2
r n, n 1, ..., 5, 4, 1, 3, 2
We have covered all cases, and provided an algorithm how to construct such permutations, so
we are done.
#include <bits/stdc++.h>
typedef tree<
pair<int, int>,
null_type,
less<pair<int, int>>,
rb_tree_tag,
tree_order_statistics_node_update>
ordered_set;
#define mp make_pair
return s;
}
int inv(int n)
{
return po(n, MOD-2);
}
mt19937 rnd(time(0));
void init()
{
facs[0] = 1;
for (int i = 1; i<LIM; i++) facs[i] = mul(facs[i-1], i);
invfacs[LIM-1] = inv(facs[LIM-1]);
for (int i = LIM-2; i>=0; i--) invfacs[i] = mul(invfacs[i+1], i+1);
struct DSU
{
vector<int> sz;
vector<int> parent;
void make_set(int v) {
parent[v] = v;
sz[v] = 1;
}
int find_set(int v) {
if (v == parent[v])
return v;
return find_set(parent[v]);
}
if (a != b) {
if (sz[a] < sz[b])
swap(a, b);
parent[b] = a;
sz[a] += sz[b];
}
}
DSU (int n)
{
parent.resize(n);
sz.resize(n);
for (int i = 0; i<n; i++) make_set(i);
}
};
CAPITOLUL 6. EJOI 2022 6.5. PERMUTATIONS 99
void print(vector<int> a)
{
for (auto it: a) cout<<it<<’ ’;
cout<<endl;
}
void print(vector<bool> a)
{
for (auto it: a) cout<<it<<’ ’;
cout<<endl;
}
void solve()
{
int n; cin>>n;
vector<int> a(n); for (int i = 0; i<n; i++) cin>>a[i];
int answer = 1;
vector<vector<int>> prv(n);
vector<vector<int>> ans(n);
if (!pos.empty())
{
auto pt = pos.end();
int cnt = 5;
while (cnt && pt!=pos.begin())
{
pt = prev(pt); prv[i].push_back(*pt); cnt--;
}
}
//Updating
if (last_pos.find(a[i])!=last_pos.end())
{
pos.erase(last_pos[a[i]]);
}
last_pos[a[i]] = i;
pos.insert(i);
}
cout<<answer<<endl;
}
int main()
{
//-----------------------------------------------------
std::clock_t c_start = std::clock();
auto t_start = std::chrono::high_resolution_clock::now();
auto t1 = clock();
int t;
cin>>t;
// ----------------------------------------------------------------
auto t2 = clock();
std::clock_t c_end = std::clock();
auto t_end = std::chrono::high_resolution_clock::now();
return 0;
// ----------------------------------------------------------------
}
int main()
//int main(int argc, char * argv[])
{
//-----------------------------------------------------------------------
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/306", // input
(char*)"../tests/306.a", // rezultat corect
(char*)"permutations.out", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
//-----------------------------------------------------------------------
registerTestlibCmd(argc, argv);
int n = 0;
string firstElems;
int extraInAnsCount = 0;
while (!ans.seekEof())
{
ans.readLong();
extraInAnsCount++;
}
int extraInOufCount = 0;
while (!ouf.seekEof())
{
ouf.readLong();
extraInOufCount++;
}
if (extraInAnsCount > 0)
quitf(_wa, "Answer contains longer sequence [length = %d], but output contains %
d elements", n + extraInAnsCount, n);
if (extraInOufCount > 0)
quitf(_wa, "Output contains longer sequence [length = %d], but answer contains %
d elements", n + extraInOufCount, n);
if (n <= 5)
quitf(_ok, "%d number(s): \"%s\"", n, compress(firstElems).c_str());
else
quitf(_ok, "%d numbers", n);
}
/* la verificare apare:
argc = 4
checker
../tests/306
../tests/306.a
permutations.out
----------------------
ok 40000 numbers
6.6 unfriendly
Problema 6 - Cel mai lung subşir neprietenos 100 de puncte
Numim şirul b1 , b2 , ..., bm neprietenos, dacă următoarea condiţie este ı̂ndeplinită:
dacă 1 & i $ j & m şi j i & 2, atunci bi j bj .
Cu alte cuvinte, un şir este neprietenos dacă oricare două elemente aflate la distanţă cel mult
2 sunt distincte.
Vi se dă un şir a1 , a2 , ..., an . Găsiţi lungimea celui mai lung subşir neprietenos al acestuia.
Un şir c se numeşte subşirul unui şir d dacă c poate fi obţinut din d prin ştergerea unui număr
de elemente (posibil zero sau chiar toate). De exemplu, (1, 3, 5) este un subşir al şirului (1, 2, 3,
4, 5), ı̂n timp ce (3, 1) nu este.
Date de intrare
Datele de intrare conţin mai multe scenarii de test. Prima linie conţine un singur număr ı̂ntreg
t ( 1 & t & 10 ) - numărul de teste. Urmează descrierea celor t teste.
5
Prima linie a fiecărui test conţine un singur număr ı̂ntreg n (1 & n & 2 10 ) - lungimea şirului.
5
A doua linie a fiecărui test conţine n ı̂ntregi a1 , a2 , ..., an (1 & ai & 109 ) - elementele şirului a.
Se garantează că suma valorilor n pentru toate scenariile de test din datele de intrare nu
5
depăşeşte 2 10 .
Date de ieşire
Pentru fiecare test, afişaţi un singur număr ı̂ntreg - lungimea celui mai lung subşir neprietenos
al şirului a.
Exemple
Date de intrare:
3
5
1 2 1 2 1
7
1 2 3 2 1 2 3
8
1 10 10 1 1 100 100 1
Date de ieşire:
2
6
4
Explicaţii
În primul test, cele mai lungi subşiruri neprietenoase sunt (1, 2) şi (2, 1). Subşirul (1, 2, 1),
de exemplu, nu este neprietenos, ı̂ntrucât primul element şi al treilea element sunt egale.
În al doilea test, cel mai lung subşir neprietenos este (1, 2, 3, 1, 2, 3). Este evident că subşirul
corespunzător ı̂ntregului şir nu este neprietenos, aşadar răspunsul este 6.
În al treilea test, cel mai lung subşir neprietenos este (1, 10, 100, 1).
Punctaj
1. (3 puncte): ai & ai1
CAPITOLUL 6. EJOI 2022 6.6. UNFRIENDLY 103
2. (6 puncte): n & 8
3. (8 puncte): Suma valorilor n din toate scenariile de test nu depăşeşte 500
4. (10 puncte): ai & 3
5. (10 puncte): ai & 10
6. (20 puncte): Suma valorilor n din toate scenariile de test nu depăşeşte 10 000
7. (43 puncte): Fără restricţii suplimentare
Subtask 3. Clearly, for n 1 answer is 1, and for n ' 2 it’s ' 2 (as any subsequence of length
exactly 2 is unfriendly).
Let’s use dynamic programming. Let dpij for 1 & i $ j & n denote the length of the longest
unfriendly subsequence of a, in which the last element is aj , and the second last is ai . If ai aj ,
dp[i][j] = 0. Otherwise, dpij max 2, max1&k$i dpk i 1 over k for which ak j ai and
ak j aj . We can calculate this dp table in O n for a single test case, which is fast enough.
3
Subtask 4. Let’s look at any unfriendly sequence b1 , b2 , ..., bm such that for all i 1 & bi & 3.
Each 3 consecutive elements of b are distinct, therefore bi , bi1 , bi2 are some permutation of
1, 2, 3 for 1 & i & n 2. Then, however, bi1 , bi2 , bi3 also are such a permutation. As bi and
bi3 both differ from two distinct values bi1 , bi2 , they must be equal. So, bi bi3 for each i;
b has to be periodic with period 3.
Then, just try each possible start of the subsequence b p1 , p2 , p3 - every permutation of 1, 2, 3.
For each of them, take elements p1 , p2 , p3 , p1 , p2 , ... as soon as you see them. Output the largest
answer over these 6 options.
Subtask 5. Let’s go through our sequence a from left to right and keep the following dynamic
programming table: let dpxy denote the length of the longest unfriendly subsequence of a up
to this moment, whose last element is y, and second last element is x.
9
Initially, we can set each value in this table to IN F (where IN F 10 , for example). Let’s
also keep track of what elements have already appeared in our sequence.
It turns out that it’s easy to update this table: when we are at position i, we just need
to update the values of dpxai for each x j ai . If x hasn’t appeared before, there is no
subsequence ending with x, ai , otherwise, do dpxai max dpxai , 2. Then, we need to
do dpxai max dpxai , dpy x 1 over all y j x, ai . Updating this table after seeing
2 2
the next element takes O M AX , with overall complexity O M AX n per test case, which fits
easily.
108
time limit
CAPITOLUL 6. EJOI 2022 6.6. UNFRIENDLY 104
Subtask 6. Let’s modify our algorithm from Subtask 5 a little. Clearly, we can assume that
elements are in the range 1, n (just map k-th smallest value to k, we don’t care about the exact
values of elements, we only care about which elements are equal to which). Now, again, let’s keep
dpxy for x j y: the length of the longest unfriendly subsequence of a up to this moment which
ends with x, y . The difficulty lies in updating dpxai max dpxai , dpy x 1 over all
y j x, ai : this can take O n , which for n 10 000 has no chance of passing.
3
But let’s note that we don’t actually need all the values dpy x to update this table. We
need the largest value among the ones for which y j ai . Then, for each y let’s keep two values
x1 j y; x2 j y, such that the values dpx1 y , dpx2 y are the largest among all dpxy .
Then, we would just have 2 (at most) candidates to check. After we do this for each y, we will
recalculate the best choices for the previous element for ai .
2
This way, processing new element takes O n, and the entire algorithm runs in O n time,
which passes easily.
Subtask 7. For this subtask, we will have to analyze the structure of the longest unfriendly
subsequence a bit more.
Consider the longest unfriendly subsequence of a. Suppose that it contains ai . What could be
the previous element before ai , if there is any? Clearly, if it’s some value x, it’s optimal to take
the last occurrence of x before ai .
What we did in previous subtasks was going through all possible candidates for x. However, as
it turns out, we don’t need that many. Among all last occurrences of elements before ai , consider 5
rightmost (if there are at least 5). Suppose that we don’t take any of those as our x. Then, I claim,
we can extend our unfriendly subsequence by inserting one of these rightmost 5 last occurrences
into it.
Indeed, two (or less, if there are less than two) elements to the left of ai in this subsequence,
ai , and the element to the right, if there is any. They are the only prohibited values for the x
(if we want to insert x right before ai in this subsequence). Then one of those 5 last occurrences
would not be prohibited, and the subsequence wouldn’t be the longest possible.
So, for each ai , we know the set of at most 5 possible candidates for the previous element in
the longest unfriendly subsequence. Therefore, we can once again use dynamic programming of
form candlast, indicating the length of the longest possible unfriendly subsequence, ending in
acand , alast . For each last, we have at most 5 cand. So, when processing new last, we need to
2
do just M AGIC checks (where M AGIC 5).
We can keep this dp in maps, and keep the last occurrence of each element with a simple set.
2
The total complexity is O n 5 log n.
#include <bits/stdc++.h>
vector<int> p,q,r;
int main()
{
//-----------------------------------------------------
std::clock_t c_start = std::clock();
auto t_start = std::chrono::high_resolution_clock::now();
auto t1 = clock();
// ----------------------------------------------------------------
auto t2 = clock();
std::clock_t c_end = std::clock();
auto t_end = std::chrono::high_resolution_clock::now();
return 0;
// ----------------------------------------------------------------
}
#include "testlib.h"
#include <bits/stdc++.h>
int n, a, b, c, output;
int ans = 0;
for (int i = 0; i <= n; i++) {
if (d[i] < INF)
ans = i;
}
return ans;
}
string upper(string s) {
for(char &c : s) {
c = toupper(c);
}
return s;
}
bool check_perm(vector<int> a)
{
set<int> guys(a.begin(), a.end());
return (guys.size() == n);
}
return true;
}
int main()
//int main(int argc, char* argv[])
{
//-----------------------------------------------------------------------
int argc=4;
CAPITOLUL 6. EJOI 2022 6.6. UNFRIENDLY 107
char* argv[] =
{
(char*)"checker",
(char*)"../tests/110", // input
(char*)"../tests/110.a", // rezultat corect
(char*)"LCS.out", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
int t = inf.readInt();
if (output==0)
{
if (juryAns!=partAns) quitf(_wa, "Wrong answer");
}
else
{
if (juryAns && (!partAns)) quitf(_wa, "Jury found the answer but participant
didn’t");
if ((!juryAns) && partAns) quitf(_fail, "Participant found the answer but
jury didn’t");
}
}
quitf(_ok, "Correct");
}
/*
Apare la executie:
argc = 4
checker
../tests/110
../tests/110.a
LCS.out
----------------------
ok Correct (50000 test cases)
7.1 AddK
Problema 1 - AddK 100 de puncte
Se consideră un şir A cu N elemente numere naturale A1 , ..., AN şi un număr natural K. Se
cere să se proceseze Q cerinţe de următoarele două tipuri:
1 i1 i2 . . . iK : se permută circular la stânga elementele şirului Ai1 , ..., AiK . Astfel noile
valori ale elementelor Ai1 , Ai2 , ..., A iK 1 , AiK vor fi Ai2 , Ai3 , ..., AiK , Ai1 . Remarcaţi că
i1 , ..., ik sunt distincte şi nu neapărat in ordine crescătoare.
2 l r m: se cere calculul sumei elementelor tuturor subsecvenţelor continue de lungime m
din secvenţa Al , Al1 , ..., Ar1 , Ar . Remarcaţi că elementele care apar ı̂n mai multe secvenţe
vor fi adunate de mai multe ori.
Date de intrare
Prima linie a fisierului de intrare standard conţine două numere ı̂ntregi, N şi K. A doua linie
conţine N numere ı̂ntregi: elementele vectorului A. A treia linie conţine un ı̂ntreg Q, numărul de
cerinţe, şi apoi Q linii conţinând cerinţele, care pot fi din cele două tipuri descrise mai sus.
Date de ieşire
Fişierul standard de ieşire trebuie să conţină răspunsurile la cerinţele de tip 2, câte unul pe linie.
Restricţii
# Punctaj Restricţii
0 & Ai & 10
6
1 36 1 & N, Q & 10 000, K 1
1&l&r&N
10 001 & N, Q & 100 000, K 1
1&m&rl1
2 56
3 8 1 & N, Q & 100 000, 2 & K & 10
Example
Explicaţii
Prima cerinţă este de tip 2 şi trebuie să calculăm suma elementelor tuturor subsecvenţelor de
lungime m 4 din secvenţa 2, 5, 1, 9, 3, 4. Aceste subsecvenţe sunt (2, 5, 1, 9), (5, 1, 9, 3), (1,
9, 3, 4), iar suma elementelor lor este 52.
109
aur: Ştefan Cătălin Savu, cls7, Colegiul Naţional ”I.L. Caragiale”, Ploieşti
. argint: Iulian George Arsenoiu, cls8, Şcoala Gimnazială ”Ing. Gh. Pănculescu”, Vălenii de Munte
. argint: Rareş Felix Tudose, cls8, Colegiul Naţional ”Alexandru Papiu Ilarian”, Târgu Mureş
. bronz: Tudor Ştefan Muşat, cls8, Colegiul Naţional de Informatică ”Tudor Vianu”, Bucureşti
108
CAPITOLUL 7. EJOI 2021 7.1. ADDK 109
A doua cerinţă este de tip 1 şi are ca efect permutarea circulară a elementelor din şirul A,
situate pe poziţiile 2, 5, 8. Astfel, şirul A devine 7, 9, 5, 1, 6, 3, 4, 2.
A treia cerinţă este de tip 2 şi trebuie să calculăm suma elementelor tuturor subsecvenţelor de
lungime m 3 din secvenţa 9, 5, 1, 6, 3, 4. Aceste subsecvenţe sunt (9, 5, 1), (5, 1, 6), (1, 6, 3),
(6, 3, 4), iar suma elementelor lor este 50.
If the length of the sequence Al , Al1 , ..., Ar1 , Ar , ie r l 1, is at least 2 m, then the sum
of the elements of all subsequences of length m in this sequence will be S S1 S2 S3 ,
where
S1 1 Al 2 Al1 ... m 1 Alm2 ,
S2 r l 1 2 m 1 Alm Alm1 ... Arm1 ,
S3 m 1 Arm2 ... 2 Ar1 1 Ar .
If the length of the sequence Al , Al1 , ..., Ar1 , Ar is less than 2 m, then the sum of the
elements of all subsequences of length m in this sequence will be S S1 S2 S3 , where
S1 1 Al 2 Al1 ... rlm Arm1 ,
S2 r l 2 m Arm Arm1 ... Alm1 ,
S3 rl m 1 Alm ... 2 Ar1 1 Ar .
***
CAPITOLUL 7. EJOI 2021 7.2. KPART 110
7.2 KPart
Problema 2 - KPart 100 de puncte
Virgil tocmai şi-a propus să studieze proprietăţi ale şirurilor. Astfel, el defineşte un K-şir ca
fiind orice şir de numere naturale nenule care are proprietatea că orice subsecvenţă a sa de lungime
K se poate partiţiona ı̂n două subşiruri disjuncte, nu neapărat subsecvenţe, având suma egală.
De exemplu 1, 2, 1, 3 e un 3-şir, căci 1, 2, 1 poate fi partiţionat ı̂n 1, 1 şi 2, şi 2, 1, 3 poate fi
partiţionat ı̂n 2, 1 şi 3. Nu este 2-şir căci 1, 2 nu poate fi partiţionat ı̂n două subşiruri cu sumă
egală. Totodată nu este 4-şir.
Pentru T şiruri de numere naturale nenule A, Virgil doreşte să afle toate valorile K, pentru
care şirul A poate fi numit K-şir.
Date de intrare
Pe prima linie se află numărul T . Urmează apoi T şiruri. Fiecare şir este dat prin două linii.
Prima linie conţine valoarea lui N . A doua linie conţine elementele şirului separate prin câte un
spaţiu.
Date de ieşire
Afişaţi răspunsurile pentru fiecare şir ı̂n ordine. Pentru fiecare şir afişaţi câte o linie care
conţine mai ı̂ntâi numărul de valori K pentru care şirul este K-şir şi apoi, ı̂n ordine crescătoare,
acele valori K pentru care şirul este K-şir.
Restricţii
# Punctaj Restricţii
1 10 1 & N & 30
2 20 31 & N & 120
3 70 121 & N & 1 000
Example
Explicaţii
Primul şir, cel de lungime 7 este 4-şir şi 6-şir, deoarece fiecare secvenţă de lungime 4, respectiv
6, conţin câte două subşiruri disjuncte cu suma egală care partiţionează secvenţa. Al doilea şir,
cel de lungime 6 este 3-şir şi 6-şir, deoarece fiecare secvenţă de lungime 3 şi fiecare secvenţa de
lungime 6, conţin câte două subşiruri disjuncte cu suma egală care partiţionează secvenţa.
K-string. The pos string is defined by poss= the highest index, between 1, 2, 3, ..., N , for which
there is a sub-sequence that starts with Aposs and has the amount s. The values poss will
be equal to -1 for the amounts s, 1 & s & 50 000, which have not yet been reached. The value
pos0 is initially equal to 0.
Suppose we have solved the problem ksir A, N 1, pos, kV alues and we want to get the
solution for the problem ksir A, N, pos, kV alues. How can we proceed?
The newly appeared value is AN , so we will update in a first step the string pos by going
through decreasing all the positive amounts s already reached and updating the poss AN
each time s AN & 50 000. The update will be made using the expression poss AN
max poss AN , poss. Then it will update posAN with N .
In the second stage we will go through the string kV alues and update it. Note that the values
kV aluesj , 1 & j & length kV alues are all already validated for the sub-string A1 , A2 , ..., AN 1 .
What we are interested in now is to check/validate the sub-strings AN kV aluesj 1 ...AN , check-
ing if the amounts s AN kV aluesj 1 AN kV aluesj 2 ... AN are even and poss©2 '
N kV aluesj 1, where 1 & j & length kV alues, which ensures that the amounts s©2 can
be obtained using only elements of a sub-sequence inside the verified sub-string. The sub-string
A1 ...AN is checked/validated separately using the same idea. Obviously, all valid kV aluesj
values will be kept.
Initially it will start with the context of the ksir A, 0, pos, kV alues in which A is the empty
string, length kV alues 0, pos0 0 and posj 1 for 1 & j & 50 000, and then step
by step the contexts will be updated ksir A, i, pos, kV alues, for 1 & i & N . The complexity is
O T N S , where S & 50 000.
***
7.3 XCopy
Problema 3 - XCopy 100 de puncte
Astăzi, la finalul orei de informatică, profesorul a dat ca temă pentru acasă o problemă foarte
dificilă, aşa că elevii s-au hotărât să copieze unii de la alţii. Vor trebui totuşi să lucreze cât mai
deştept pentru a nu fi prinşi că au copiat.
Clasa este alcatuită din N M elevi, aşezaţi ı̂n bănci pe N rânduri şi M coloane. Spunem că
doi elevi sunt vecini dacă se află ı̂n bănci adiacente fie pe rânduri, fie pe coloane. Tema fiecărui
copil constă ı̂n găsirea unui număr natural. Pentru ca elevii să nu fie prinşi că au copiat, toate
temele acestora vor trebui să fie distincte. Mai mult, elevii sunt foarte leneşi, aşa că ı̂şi vor modifica
tema foarte puţin faţă de tema vecinilor. Mai exact, tema oricarui elev diferă prin exact un bit ı̂n
scrierea ı̂n baza 2 faţă de tema oricărui vecin al său. De exemplu 3 şi 2 diferă prin exact un bit,
pe când 2 şi 4 diferă prin doi biţi.
Pentru a nu ridica suspiciuni prea mari, elevii doresc să creeze temele astfel ı̂ncât cea mai mare
valoare a unei teme să fie cât mai mică posibil. Fiind date dimensiunile clasei, N şi M , contruiţi
o configuraţie a valorilor temelor fiecarui elev din clasă astfel ı̂ncât profesorul să nu ı̂şi dea seama
că aceştia au copiat.
Date de intrare
Pe prima şi singura linie a datelor de intrare se vor afla 2 numere separate printr-un singur
spaţiu, N şi M cu semnificaţia de mai sus.
Date de ieşire
Datele de ieşire constau ı̂n afişarea configuraţiei temelor fiecărui elev. În fişier se vor afla N
rânduri, iar pe fiecare rând se vor afla M numere naturale separate printr-un spaţiu. Acestea
reprezintă răspunsurile copiilor, corespunzătoare poziţiei lor ı̂n clasă.
CAPITOLUL 7. EJOI 2021 7.3. XCOPY 112
Restricţii
# Punctaj Restricţii
1 7 N 1.
2 9 N, M sunt puteri de 2.
3 14 N este o putere de 2.
4 70 Nicio restricţie suplimentară.
Punctare
Această problemă acceptă şi soluţii parţiale, astfel se va acorda punctaj parţial pentru fiecare
test, ı̂n funcţie de cât de aproape de răspunsul optim este soluţia dată folosind următoarea formulă:
Ø
G
1
S max
1
O
, 0
3
unde:
a S este punctajul testului,
a G este răspunsul dat,
a O este răspunsul optim.
Atenţie! O soluţie care nu respectă toate cerinţele problemei pentru un anumit test (toate
numerele să fie distincte şi oricare două numere adiacente să difere printr-un singur bit) va fi
punctata cu 0 pe acel test.
Example
Explicaţii
În această secţiune, indicele poziţionat in dreapta-jos a numărului reprezintă baza ı̂n care este
scris. Spre exemplu, opt poate fi scris drept 810 10002 .
Unul dintre răspunsurile optime pentru copii sunt date ı̂n urmatorul tabel:
Putem observa că ı̂ntre oricare două bănci adiacente numerele elevilor din acele bănci diferă cu
exact un bit. Valoarea maximă a soluţiei este 10 si este răspunsul optim. Este evident că există
şi alte răspunsuri optime - spre exemplu, soluţia propusa dar oglindită vertical sau orizontal.
Una dintre soluţiile parţiale posibile ı̂n care maximul este 15 este:
Această soluţie ar fi punctată, conform formulei de punctare, cu 59,1% din punctajul testului.
CAPITOLUL 7. EJOI 2021 7.3. XCOPY 113
0 1 3 2 6 7 5 4
8 9 11 10 14 15 13 12
24 25 27 26 30 31 29 28
16 17 19 18 22 23 21 20
with a maximum value of 45 101101. Whereas if we look at the maximum value (5 101 2 ),
we can observe that we can merge the two 5s in the following way: 43 101011. Thus we can
minimize the maximum value of the matrix to 43 instead of 45 and obtain the following matrix:
The merging can be done in various ways, one of which would be using dynamic programming:
dpi,j = the minimum value that can be obtained using the first i bits of the maximum of the
first set and the first j bits of the maximum of the second set.
n n
We can create a Gray code of length 2 starting with any number from 0 to 2 1, using
the previous construction suitably rotated.
Any integer is a sum of distinct powers of 2.
These facts suggest immediately an algorithm: create Gray codes of lengths equal to the powers
of 2 that compose the length of the desired Gray code, and put them together in some way. We
will show how this is done by example, for length 7.
Note that Gray codes for length 1, 2 and 4 respectively are 0, 1, 3, 2, 0, 1 and 0 respectively.
We now ”add in” the high order bit in the second and third Gray codes to get 0, 1, 3, 2, 4, 5, 6.
Now we need to rotate the Gray codes so that they can be adjacent, from right to left. 6 can only
be adjacent to 4, so the array ends with 5, 4, 6. 5 can only be adjacent to 1, so the full array is
3, 2, 0, 1, 5, 4, 6.
Now let’s suppose that there exists a bit such that it is changed both on a row and a column.
That means that there exists a bit k and a row i and column j such that:
M i 1x M ix h 2 , ¾x " r0, 1, ..., M 1x
k
***
CAPITOLUL 7. EJOI 2021 7.4. BINSEARCH 115
7.4 BinSearch
Problema 4 - BinSearch 100 de puncte
Este bine ştiut faptul că dacă p este sortat, atunci codul returnează true dacă şi numai dacă
target apare ı̂n p. Pe de altă parte, acest lucru poate să nu se ı̂ntâmple dacă p nu este sortat.
Vi se dă un număr natural n şi o secvenţă b1 , ..., bn " rtrue, f alsex. Se garantează că există
k
un număr natural k pentru care n 2 1. Trebuie să generaţi o permutare p a elementelor
r1, ..., nx care ı̂ndeplineşte anumite condiţii. Fie S p numărul de indici i " r1, ..., nx pentru care
binary search n, p, i nu returnează bi . Trebuie sa alegeţi p astfel ı̂ncât S p este mic (aşa cum
este detaliat ı̂n secţiunea ”Restricţii”).
(Notă: o permutare a mulţimii of {1, . . . , n} este o secvenţa de n numere naturale care
conţine fiecare numar natural de la 1 la n fix odată.)
Date de intrare
Prima linie conţine T , numărul de teste. Urmează apoi testele.
Prima linie a unui test conţine numărul natural n. Pe cea de-a doua linie se găseşte un şir de
n caractere ce conţine doar caracterele ’0’ şi ’1’. Aceste caractere nu sunt separate prin spaţii.
Dacă cel de-al i-lea caracter este ’1’, atunci bi true, iar dacă este ’0’, atunci bi f alse.
Date de ieşire
Răspunsul pentru un test va fi o permutare p.
Restricţii
Dacă S p & 1 pentru toate testele dintr-un subtask, atunci se primesc 100% din punctele
alocate acelui subtask.
În caz contrar, dacă 0 & S p & *log2 n0 (adică 1 & 2 & n 1) pentru toate testele
S p
dintr-un subtask, atunci se primesc 50% din punctele alocate acelui subtask.
# Punctaj Restricţii
1 3 bi true.
2 4 bi f alse.
3 16 1 & n & 7.
4 25 1 & n & 15.
16
5 22 n 2 1 şi fiecare bi este generat uniform aleator din mulţimea rtrue, f alsex.
6 30 Fără restricţii suplimentare.
CAPITOLUL 7. EJOI 2021 7.4. BINSEARCH 116
Example
Explicaţii
Exemplul 1. În primele două teste avem S p 0.
În cel de-al treilea test, avem S p 1.
Acest lucru se ı̂ntâmplă deoarece binary search n, p, 2 returnează true, deşi b2 f alse.
În cel de-al patrulea test, avem S p 1.
Acest lucru se ı̂ntâmplă deoarece binary search n, p, 4 returnează true, deşi b4 f alse.
Exemplul 2. Avem S p 0 pentru ambele teste.
Place all values bigger than the middle value on positions 1, ..., n2 1 1, in any order.
In particular, note that the decreasing permutation works.
Subtask 3. In this subtask N 7 holds. We can use the fact that 7! 5040 is small. This
allows us to generate all the possible permutations of size n, and for each such permutation we
can run binary search on all values from 1 to n and compare the returned result with the desired
value in b. We calculate S p for all permutations p, and print any permutation p that achieves
S p1.
Subtask 4. This subtask encourages solutions with sub-optimal (but polynomial) time com-
plexities. For example, a poor implementation of the ”Solution 1” presented below might have a
2
time complexity of O n instead of the optimal O n.
Subtask 5. In this subtask, the sequence b is guaranteed to be generated randomly. This
allows us to design solutions which use different facts, such as:
The numbers of ones and zeros in b should be approximately equal.
There are not many consecutive equal entries in b.
CAPITOLUL 7. EJOI 2021 7.4. BINSEARCH 117
Subtask 6. The problem admits a wide variety of full solutions which promote different types
of thinking. We present only a few of them.
Solution 1. We try to place, in turn, each possible value on the middle position. Let X be
our current try. Our aim is to find p for which bi binary search n, p, i for all values i j X.
This would give S p 0 if bX 1 and would give S p 1 if bX 0.
We define two sets L and R:
L ri¶bi true, i $ X x < ri¶bi f alse, i % X x
R ri¶bi true, i % X x < ri¶bi f alse, i $ X x
Lemma. If ¶L¶ ¶R¶ n2 1 for some X, then we can find a good permutation.
Proof. One way to build such a permutation is:
First place the values in L in increasing order
Then place the values in R in increasing order
– Suppose ¶A¶ % ¶B ¶. Suppose there are 2 1 elements overall. Let A contain the first
k
k
2 1 elements of A in increasing order. Then output A in increasing order first, followed
by solve A A, B . For example if A r1, 3, 5, 6, 7x, B r2, 4x, then A r1, 3, 5, 6x
and our output starts with 1, 3, 5, 6 followed by the result of solve A A r7x, B
r2, 4x.
CAPITOLUL 7. EJOI 2021 7.5. DUNGEONS 118
As an example, suppose A r3, 4x, B r1, 2, 5, 6, 7x. Then X r1x, Y r7x, b 2, and
2 b $ min A 3. Thus the array begins with 7, 2, 1, 3 followed by the result of ({4}, {5, 6}),
which can be 5, 4, 6 for instance. Thus the result is 7, 2, 1, 3, 5, 4, 6, with S p 1.
***
7.5 Dungeons
Problema 5 - Dungeons 100 de puncte
Dungeon Crawl: Paper Soup tocmai a devenit cel mai popular joc, iar tu eşti pe cale să ı̂l
ı̂ncerci. Jocul se desfăşoară pe un teren dreptunghiular cu N linii şi M coloane, unde fiecare
celulă este de unul dintre cele cinci tipuri descrise mai jos:
celulă liberă ’.’;
perete ’#’;
celulă cu monedă ’o’;
celulă cu mină explozivă ’X’;
celulă de start ’S’;
Se garantează că pe prima, respectiv ultima linie şi coloană se află pereţi (de precizat că este
imposibilă deplasarea prin pereţi). Terenul poate conţine una sau mai multe celule de start. În
momentul ı̂n care jocul ı̂ncepe, jucătorul va fi poziţionat iniţial ı̂ntr-una dintre celulele de start,
marcate cu ’S’. Deoarece jocul se desfăşoară ı̂ntr-un sistem de peşteri cu vizibilitate redusă (vezi
numele jocului), jucătorul nu poate vedea toată harta, ci doar o zona de vizibilitate restrânsă,
reprezentată de un pătrat de 3 3 centrat ı̂n poziţia sa curentă. Mai mult, ı̂n această zonă de
vizibilitate minele şi celulele de start apar drept celule libere (sunt invizibile pentru jucător).
La fiecare pas, jucătorul poate să se mişte pe direcţiile nord, sud, est sau vest. Dacă acesta
ajunge pe o poziţie cu o monedă, colectează moneda, iar aceasta dispare de pe hartă. Dacă acesta
CAPITOLUL 7. EJOI 2021 7.5. DUNGEONS 119
ajunge pe o poziţie cu mină, sistemul de peşteri se prăbuşeste, jucătorul pierde toate monezile
colectate până ı̂n acel moment, iar jocul se termină.
Din fericire, urmărind diverse ghiduri pe internet ai aflat harta exactă a terenului, ı̂nsă nu ştii
ı̂n care dintre punctele de start vei fi repartizat - este garantat ı̂nsă că vei porni dintr-o celulă de
start. Considerând că vei adopta cea mai bună strategie, care este numărul maxim de monezi pe
care ı̂l poţi obţine garantat, indiferent de unde vei fi poziţionat la ı̂nceput?
Date de intrare
Pe prima linie ı̂n fişierul de intrare se vor găsi valorile N şi M : dimensiunile terenului pe care
se va desfăşura jocul, conform ghidurilor de pe internet. Următoarele N linii conţin fiecare câte
un şir de caractere de lungime M , reprezentând harta, conform codificării descrise ı̂n enunţ.
Date de ieşire
În fişierul de ieşire se va afişa un singur număr natural, numărul maxim de monezi care se
poate obţine garantat pe acel teren.
Restricţii
# Punctaj Restricţii
1 3 S 1. Nu există mine. Cu excepţia primei
şi ultimei linii şi coloane, nu există pereţi.
2 7 N 3
3 12 S 1
4 23 S 2
5 41 1 & N, M & 250, 1 & S & 12
6 14 Nicio
restricţie su-
plimentară
Example
7 18 6
##################
#....#...........#
#.o...SX.......o.#
#.o...X..X.....o.#
#.o.....XS.....o.#
#.........#......#
##################
7 18 1
##################
#......X..S....oo#
##################
#..o..S.X......o.#
##########X#######
#o.....S...X.....#
##################
Explicaţii
Exemplul 1 Există o singură poziţie de start, deci ştim exact de unde va porni jucătorul. În
acest caz, jucătorul poate colecta toate monezile.
Exemplul 2 Sunt două poziţii de start, iar jucătorul poate deduce unde este poziţionat pe
baza zonei de vizibilitate (@ este poziţia jucătorului):
### ###
#@o o@#
### ###
Numărul maxim de monezi pe care le poate colecta jucătorul dacă porneşte din partea stângă
este 1, respectiv 2 dacă porneşte din partea dreaptă. Deci, pe cel mai rău caz, putem colecta o
monedă.
Exemplul 3 ı̂n orice direcţie s-ar mişca iniţial jucătorul, pe caz nefavorabil se va afla o mină
ı̂n direcţia respectivă. Zona de vizibilitate iniţială este:
...
.@.
...
Exemplul 4 Jucătorul ı̂şi poate da seama ı̂n care celulă a fost plasat iniţial, analizând zona
de vizibilitate. Mai exact, acesta se uită dacă iniţial vede un perete ı̂n stânga-sus sau dreapta-jos;
astfel, ştie exact cum să se poziţioneze pentru a evita minele. Zonele de vizibilitate iniţiale aferente
celor două poziţii sunt:
#.. ...
.@. .@.
... ..#
Exemplul 5 Jucătorul se mută 2 paşi la stânga. Dacă vede o monedă la stânga, deduce că
este ı̂n zona din mijloc, o culege şi termină jocul. Dacă nu, ştie că nu este ı̂n zona din mijloc, aşa
că se mută la dreapta 4 paşi.
Observând mai apoi dacă există spaţiu liber ı̂n dreapta-sus (minele sunt văzute drept spaţii
libere), poate deduce dacă se află ı̂n zona de sus sau zona de jos. În ambele cazuri, este liber să
colecteze moneda/monezile corespunzătoare. În cel mai nefavorabil caz, ı̂nsă, va putea colecta o
singură monedă.
Se poate observa că jucătorul nu se putea muta iniţial spre dreapta, deoarece ar fi riscat să
atingă mina din centru pe caz nefavorabil.
CAPITOLUL 7. EJOI 2021 7.5. DUNGEONS 121
Consider the current set of starting positions that we could have started at S.
Visit all possible squares that do not require us to visit a relative position that could corre-
spond to a bomb for any of the starting positions in S.
Check if we see any wall or coin that only appears in some proper subset of starting positions
S L S.
If such a position exists, continue the search from that subset.
Otherwise give up with the coins we can collect at this point.
How can we simulate this algorithm in our case? It is not difficult to make a version that does
O N M S complexity for each starting set (simply do a breadth first search, checking if a position
is visitable, or respectively is a wall or a coin that only appears for some starting positions, by
iterating over the current starting positions).
To optimise this to use O N M time for each set of starting positions that we check, store
the map ”relative to each starting position” in a bit mask. Thus we will have several matrices
wall/bomb/coin that, at position i, j will contain a bit mask that have bit k equal to 1 if and
only if position i, j relative to starting position k contains a wall/bomb/coin. This allows us to
check
(a) if a certain relative position contains a bomb for a subset of starting positions, and
(b) if a certain relative position contains a wall/coin in some starting positions but not others.
These can be done by representing the set of starting positions with a bit mask, and the using
a bitwise ”and” operation.
Then for (a) we check if the result is nonzero, and for (b) we check if it is neither zero or equal
to the bit mask that represents the set of starting positions.
Thus with this approach we can find, in O N M , for any set of starting positions:
The number of coins we can safely collect.
If any wall or coin is visible for only some subset of starting positions.
What that subset of starting positions is.
Now suppose f S gives us the result for some set of starting positions S. The full result will
be f r1, ..., S x. To compute f S use the following algorithm:
It can be proved that this does at most S matrix traversals. Thus the final complexity is
O N M S .
CAPITOLUL 7. EJOI 2021 7.6. WATERFRONT 122
***
7.6 Waterfront
Problema 6 - Waterfront 100 de puncte
Pe faleza râului Prahova primarul oraşului Ploieşti a plantat un şir de N arbuşti ornamentali
de diverse soiuri, fiecare arbust i având iniţial ı̂nălţimea heighti, 1 & i & N . În funcţie de solul
ı̂n care este plantat şi de vreme, arbustul i creşte zilnic cu ı̂nălţimea dailyGrowthi.
În fiecare zi grădinarul primăriei ajustează, prin tăiere cu o foarfecă, ı̂nălţimea arbuştilor.
Totuşi, grădinarul este limitat de detaliile tehnice ale foarfecii. Astfel, acesta poate tăia la o
tăietură exact x centimetri din ı̂nălţimea unui arbust dacă ı̂nălţimea este cel puţin x (de notat
faptul că arbustul poate ajunge la ı̂nălţimea 0 după o tăietură). Pentru a nu se obosi, grădinarul
poate să efectueze ı̂ntr-o zi cel mult k tăieturi. Grădinarul poate să efectueze mai multe tăieturi
asupra unui arbust ı̂ntr-o zi.
Primarul organizează după M zile un eveniment artistic şi doreşte să aflaţi care este ı̂nălţimea
minimă a celui mai ı̂nalt arbust după cele M zile.
Atenţie! În fiecare zi arbustul ı̂ntâi creşte şi apoi se fac tăierile.
Date de intrare
Fişierul de intrare conţine pe prima linie numerele naturale N , M , k şi x. Pe următoarele N
linii se află câte două numere naturale heighti şi dailyGrowthi, separate prin spaţiu.
Date de ieşire
Afişaţi un număr nenegativ reprezentând ı̂nălţimea minimă a celui mai ı̂nalt arbust după cele
M zile.
Restricţii
# Punctaj Restricţii
1 8 N & 100, M 1, k 1, x 1, heighti ' 1, dailyGrowthi 0
2 22 1 & N, M & 500
3 43 1 & N, M & 5 000
4 27 1 & N, M & 10 000
Example
Explicaţii
Grădinarul taie arbuştii ı̂n 3 zile, ı̂n fiecare zi făcând câte 4 tăieturi. La fiecare tăietură poate
elimina câte 3 cm din ı̂nălţimea arbustului. Următorul tabel ilustrează modul optim de efectuare
a tăierilor:
How do we do this? Suppose we consider a artition of indices 1, ..., M where all adjacent
indices i where v i 0 are joined into the same partition. In this case to find the first nonzero
value to the right of index a, we find the set to which a belongs, we find the rightmost index r in
this partition, and:
if v r 0, then by the definition of the partition the next nonzero index if r 1;
otherwise r a and a itself can be decremented.
This partition can be efficiently maintained in log M complexity using a disjoint set disjoint
set.
Optimisation 2. We now optimise the way of choosing the tree to cut. We previously said
that we always choose the tree that is tallest at the end of the M days. In essence this can be
simulated using a priority queue. The keys are the heights at the end of the M days, and the
values are the indices of the trees.
Optimisation 3. The idea from the previous paragraph can be optimised further. Note that
we actually have the following operations on our priority queue:
This type of priority queue can be implemented in constant time for each operation, with
n log n precalculation time. To do this, maintain two data structures, a stack S and a queue Q.
Insert all the key-value pairs into S in increasing order (so that the maximum value is at the
top of the stack). When trying to get the maximum key-value pair, take the maximum of the
key-value pair from among the top of S and the front of Q. To decrement it’s key, remove it from
S or Q respectively, and add it into Q (at the back), with a decremented key. We leave the proof
of correctness as an exercise.
***
8.1 fountain
Problema 1 - Fountain 100 de puncte
O fântână nouă constă din N rezervoare de apă circulare, aliniate pe verticală şi numerotate
de sus ı̂n jos cu numere ı̂ntregi ı̂ncepând cu 1, ca mai jos:
Fiecare rezervor este caracterizat prin diametru, capacitate şi printr-un robinet care poate goli
orice cantitate de apă din el.
Ori de câte ori volumul de apă depăşeşte capacitatea rezervorului, excesul de apă se revarsă
pe la margini şi ajunge mai jos, ı̂n cel mai apropiat rezervor care are diametrul strict mai mare
sau ı̂n canalizare, dacă nu există un astfel de rezervor.
Ai de răspuns la Q ı̂ntrebări independente de tipul următor: care este numărul rezervorului
unde se termină debitul de apă dacă eliberaţi Vi litri de apă din al Ri -lea robinet? Dacă debitul
de apă se termină ı̂n canalizare, răspunsul va fi 0.
Input
Prima linie a intrării standard conţine doi ı̂ntregi: N şi Q.
Următoarele N linii conţin câte doi ı̂ntregi Di şi Ci , respectiv diametrul şi capacitatea celui
de-al i-lea rezervor.
Următoarele Q linii conţin fircare câte doi ı̂ntregi, Ri şi Vi .
Output
110
aur: Alexandru-Raul Todoran, clasa a 9-a, Liceul Teoretic “Aurel Vlaicu”, Orăştie,
. argint: Alexandru Dobleagă, clasa a 8-a, C. N. “I. L. Caragiale” din Ploieşti.
125
CAPITOLUL 8. EJOI 2020 8.1. FOUNTAIN 126
Scrie Q linii, cu câte un ı̂ntreg fiecare, reprezentând răspunsurile la ı̂ntrebări, ı̂n ordinea dată.
Constraints
Subtasks
Example
Input Output
65 5
4 10 0
68 5
35 4
4 14 2
10 9
4 20
1 25
6 30
58
3 13
28
Comment
Primele două ı̂ntrebări sunt ilustrate ı̂n imaginea de mai sus.
Întrucât interogările sunt independente, pentru a treia ı̂ntrebare, la al cincilea rezervor nu se
va revărsa apa.
Timp maxim de executare/test: 1.5 secunde
Memorie: total 512 MB
We will describe how to solve the last subtask which was enough to achieve a full score.
Subtask 3:
The solution consists of three parts: building the graph (which is a tree), preprocessing the tree
and answering the queries.
For each reservoir we determine the next one (i.e. where the water flows into when the given
reservoir overflows). To do this efficiently, we can go from bottom to top and maintain the
stack of the reservoirs in ascending order of their diameters. Each time a new reservoir is
processed we remove smaller or equal reservoirs from the top of the stack and insert the
current reservoir, determining the next reservoir along the way. This can be done in O N .
After that we connect each reservoir to the next one and we end up with a directed tree with
a root in node 0 (that corresponds to the waterways).
CAPITOLUL 8. EJOI 2020 8.1. FOUNTAIN 127
We use the method called ”binary lifting, most commonly used in LCA algorithm, where
k
for each node we determine its 1st ancestor, 2nd ancestor, 4th ancestor, ..., 2 -th ancestor.
Additionally we precompute the total amount of water that the reservoirs up to the corre-
sponding ancestor can hold. Since k is of the order of log N , we will need O N log N time
and O N log N memory for this part.
For each query we keep moving to the farthest precomputed ancestor while the given amount
of water doesn’t exceed the sum of the capacities of the nodes traversed and find the answer.
This step has O Q log N complexity.
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../Fountain-tests/input.3_09",
(char*)"../Fountain-tests/output.3_09",
(char*)"fountain.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
#include <bits/stdc++.h>
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template<class T>
istream &operator>>(istream &is, vector<T> &v)
{
for (T &x : v)
is >> x;
return is;
}
CAPITOLUL 8. EJOI 2020 8.1. FOUNTAIN 128
template<class T>
ostream &operator<<(ostream &os, const vector<T> &v)
{
if (!v.empty())
{
os << v.front();
return os;
}
int d[N];
int f[N][L];
int s[N][L];
int main()
{
if (freopen("../Fountain-tests/input.3_09", "r", stdin) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, q;
cin >> n >> q;
d[n + 1] = numeric_limits<int>::max();
stack<int> stk;
stk.push(n + 1);
f[i][0] = stk.top();
stk.push(i);
}
while (q--)
{
int r, v;
cin >> r >> v;
if (s[r][i] < v)
{
v -= s[r][i];
r = f[r][i];
}
if (r == n + 1)
r = 0;
return 0;
}
#include <cstdio>
#include <stdlib.h> /* exit, EXIT_FAILURE */
int main()
{
if (freopen("../Fountain-tests/input.3_09", "r", stdin) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
++n;
d[n] = 0x7f7f7f7f, c[n] = 1000000000;
fa[i][0] = stk[top];
sum[i][0] = c[i];
stk[++top] = i;
}
printf("%d\n", r == n ? 0 : r);
}
}
CAPITOLUL 8. EJOI 2020 8.1. FOUNTAIN 130
#include <cstdio>
#include <stdlib.h> /* exit, EXIT_FAILURE */
void init()
{
static int stk[N], top;
top = 0;
signed main()
{
if (freopen("../Fountain-tests/input.3_09", "r", stdin) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
init();
while (Q--)
{
int R, V;
scanf("%d%d", &R, &V);
if (sum[R] < V)
{
printf("0\n");
}
else
{
for (int i = logN - 1; ˜i; --i)
if (fa[R][i] && V > sum[R] - sum[fa[R][i]])
V -= sum[R] - sum[fa[R][i]], R = fa[R][i];
if (V > C[R])
R = fa[R][0];
printf("%d\n", R);
}
}
return 0;
CAPITOLUL 8. EJOI 2020 8.1. FOUNTAIN 131
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
if (flag)
x = -x;
}
void init()
{
read(n);
read(q);
b[++top] = i;
}
void solve()
{
int pos, val;
while (q--)
{
read(pos);
read(val);
val -= c[pos];
int main()
{
if (freopen("../Fountain-tests/input.3_09", "r", stdin) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
init();
solve();
return 0;
}
#include <cmath>
#include <iostream>
int main()
{
if (freopen("../Fountain-tests/input.3_09", "r", stdin) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
int n, q;
cin >> n >> q;
d[++n] = INF;
c[n] = INF;
while (l <= r)
{
int mid = (l + r) >> 1;
}
else
l = mid + 1;
}
g[i][0] = c[f[i][0]];
}
while (q--)
{
int r, v;
cin >> r >> v;
v -= c[r];
if (v > 0)
r = f[r][0];
if (r == n)
cout << 0 << endl;
else
cout << r << endl;
}
return 0;
}
#include <cctype>
#include <cstdio>
if (c == ’-’)
{
f = 1;
c = getchar();
}
while (isdigit(c))
{
x = x * 10 + c - ’0’;
c = getchar();
}
return f ? -x : x;
}
int main()
{
if (freopen("../Fountain-tests/input.3_09", "r", stdin) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
n = readint();
q = readint();
st[0] = n;
f[i][0] = st[top];
s[i][0] = c[i];
st[++top] = i;
}
while (q--)
{
int r, v;
r = readint();
v = readint();
return 0;
}
#include <cstdio>
#include <algorithm>
{
char c;
int re;
re = c - 48;
return re;
}
return pos;
}
int main()
{
if (freopen("../Fountain-tests/input.3_09", "r", stdin) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
N = R();
Q = R();
stk[top] = N;
pre[i][0] = stk[top];
sum[i][0] = V[i];
stk[++top] = i;
}
while (Q--)
{
pos = R();
val = R();
ans = find(pos, val);
if (ans < N)
printf("%d\n", ans);
else
puts("0");
}
return 0;
}
#include <cstdio>
void init()
{
static int stk[N], top;
top = 0;
signed main()
{
if (freopen("../Fountain-tests/input.3_09", "r", stdin) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
init();
while (Q--)
{
int R, V;
scanf("%d%d", &R, &V);
if (sum[R] < V)
{
CAPITOLUL 8. EJOI 2020 8.2. TRIANGULATION 138
printf("0\n");
}
else
{
for (int i = logN - 1; ˜i; --i)
if (fa[R][i] && V > sum[R] - sum[fa[R][i]])
V -= sum[R] - sum[fa[R][i]],
R = fa[R][i];
if (V > C[R])
R = fa[R][0];
printf("%d\n", R);
}
}
return 0;
}
8.2 triangulation
Problema 2 - Triangulation 100 de puncte
Anna a desenat un poligon cu n vârfuri numerotate de la 0 la n 1 ı̂n ordinea acelor de
ceasornic. Mai târziu a triangulat poligonul desenând n 3 diagonale care nu se intersectează cu
excepţia posibilă a vârfurilor. O diagonala este o linie dreapta ı̂ntre două vârfuri diferite care nu
au o latura ı̂ntre ele.
Să definim mai ı̂ntâi distanţa de la vârful A la diagonala D. Să
zicem că ı̂ncepem la vârful A şi ne deplasăm la următorul vârf ı̂n
ordinea acelor de ceasornic pâna ajungem la unul dintre vârfurile
lui D.
Numărul de muchii traversate il numim left distance.
Analog, right distance este numărul de muchii traversate
dacă ı̂ncepem de la A şi ne deplasăm ı̂n direcţia opusă acelor
ceasului până ajungem la D. Distanţa de la A la D este maximul
dintre left distance şi right distance.
În exemplul din imagine distanţa de la vârful 0 la diagonala (1, 5) este 2 cu left distance
egal cu 1 şi right distance egal cu 2. Pentru diagonala (0, 5) distanţ de la vârful 0 este 5, cu
left distance=5 şi right distance=2.
Anna vrea sa facă din acest lucru o provocare pentru Jacob. Jacob nu ştie diagonalele desenate.
El ştie doar valoarea lui N , dar o poate ı̂ntreba pe Anna de mai multe ori desepre perechi de vârfuri
şi ea ı̂i va spune dacă se găseşte o muchie ı̂ntre vârfurile acelea. Scopul lui Jacob este să găsească
cea mai apropiata (cu noţiunea de distanţă de mai sus) diagonala desenata faţă de vârful 0. Îl
veţi ajuta să ı̂şi ı̂ndeplinească scopul ı̂ntrebând-o pe Anna un număr limitat de ı̂ntrebări.
Constraints
Implementation Details
Trebuie să implementaţi următoarea funcţie ı̂n submisia voastră:
int solve(int n)
Funcţia ar trebui să returneze diagonala ı̂ntre nişte vârfuri a şi b ca un ı̂ntreg cu valoarea
a nb
Dacă sunt mai multe diagonale cu aceeaşi distanţă minimă, puteţi să returnaţi oricare.
Sample interaction
Urmează un exemplu de input pentru evaluator şi apelurile de funcţii corespunzătoare. Inputul
este cel desenat in imaginea de mai sus.
Singura linie din input corespunde lui n.
Evaluatorul va afişa fiecare apel al lui query la stdout şi trebuie să ı̂i răspundeţi manual cu 1
sau 0.
Scoring
Fie q numărul de interogări ce le faceţi pe un singur test. Totodată fie w f racn n 32.
Dacă faci o interogare invalidă sau ghiciţi răspunsul incorect veţi primi 0% din puncte.
Dacă w $ q veţi primi 0% din puncte pentru test.
wq
Dacă n $ q & w veţi primi 10 60 wn
% din puncte pentru un test.
Dacă q & n veţi primi 100% din puncte pe test.
Subtasks
Va fi un singur subtask iar scorul vostru este suma scorurilor pe testele individuale. Dar, pe
parcursul concursului veţi putea vedea scorurile doar pe jumătate din teste (ce valorează 50 de
puncte). Celelalte scoruri se vor afişa după concurs. Scorul final va fi scorul maxim dintre
toate submisiile.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 512 MB
CAPITOLUL 8. EJOI 2020 8.2. TRIANGULATION 140
// ----------------------------------------------------
//#include "triangulation.h"
#include <bits/stdc++.h>
// ----------------------------------------------------
now = 0;
do
{
++rdis;
fadd(now, n - 1);
} while (now != x && now != y);
// ----------------------------------------------------
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define Fast_IO ios::sync_with_stdio(false);
#define DEBUG fprintf(stderr,"Running on Line %d in Function %s\n",\
__LINE__,__FUNCTION__)
//mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
#define fir first
#define sec second
#define mod 998244353
#define ll long long
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
void print(vector<int> x)
{
for (int i = 0; i < (int)x.size(); i++)
printf("%d%c", x[i], " \n"[i == (int)x.size() - 1]);
}
int solve(int n)
{
if (query(1, n - 1))
return n + n - 1;
vector<int> v;
v.pb(1);
v.pb(n - 1);
int ax = 0, ay = 0, mind = inf;
if (D < mind)
ax = 0, ay = v[i], mind = D;
}
return ax * n + ay;
}
// ----------------------------------------------------
int main()
{
//FILE* fin = fopen("../Triangulation-tests/input.0_2", "r");
//FILE* fin = fopen("../Triangulation-tests/input.1_0", "r");
//FILE* fin = fopen("../Triangulation-tests/input.2_1", "r");
//FILE* fin = fopen("../Triangulation-tests/input.3_2", "r");
//FILE* fin = fopen("../Triangulation-tests/input.4_0", "r");
FILE* fin = fopen("../Triangulation-tests/input.5_29", "r");
int sol=solve(n);
int a=sol/n;
int b=sol%n;
printf("a = %d\n", a);
printf("b = %d\n", b);
int dist=getDis(a,b);
return 0;
}
// Author -- xyr2005
// ----------------------------------------------------
#include <bits/stdc++.h>
//#include "triangulation.h"
// ----------------------------------------------------
// ----------------------------------------------------
std::mt19937 rnd(std::chrono::steady_clock::now().time_since_epoch().count());
while (!isdigit(ch))
f |= ch == 45, ch = getchar();
while (isdigit(ch))
x = (((x << 2) + x) << 1) + (ch & 15), ch = getchar();
f &&(x = -x);
}
char *tar = s;
*tar = ch, ch = getchar();
CAPITOLUL 8. EJOI 2020 8.2. TRIANGULATION 144
return tar - s + 1;
}
int _;
inline int getdis(int x, int y)
{
return max(x == 0 ? y : x, _ - y);
}
int solve(int n)
{
::_ = n;
int ans = inf, res = 0;
int last = 1;
if (tag)
{
if (getdis(0, i) < ans)
{
ans = getdis(0, i);
res = 0 * n + i;
}
last = i;
}
}
int i = n - 1;
return res;
}
// ----------------------------------------------------
int main()
{
//FILE* fin = fopen("../Triangulation-tests/input.0_2", "r");
//FILE* fin = fopen("../Triangulation-tests/input.1_0", "r");
//FILE* fin = fopen("../Triangulation-tests/input.2_1", "r");
//FILE* fin = fopen("../Triangulation-tests/input.3_2", "r");
//FILE* fin = fopen("../Triangulation-tests/input.4_0", "r");
FILE* fin = fopen("../Triangulation-tests/input.5_29", "r");
int sol=solve(n);
int a=sol/n;
int b=sol%n;
printf("a = %d\n", a);
printf("b = %d\n", b);
//int dist=getDis(a,b);
int dist=getdis(a,b);
return 0;
}
#include <utility>
#include <vector>
#include <cstdio>
#include <cstdlib>
now = 0;
do
{
++rdis;
fadd(now, n - 1);
} while (now != x && now != y);
{
if (!(0 <= x && x < n)) return 0;
if (!(0 <= y && y < n)) return 0;
return 1;
}
// ----------------------------------------------------
int solve(int n)
{
vector<int> rec;
rec.push_back(1);
rec.push_back(n - 1);
if (a + 1 == b)
continue;
return ans.second;
}
// ----------------------------------------------------
int main()
{
//FILE* fin = fopen("../Triangulation-tests/input.0_2", "r");
//FILE* fin = fopen("../Triangulation-tests/input.1_0", "r");
//FILE* fin = fopen("../Triangulation-tests/input.2_1", "r");
//FILE* fin = fopen("../Triangulation-tests/input.3_2", "r");
//FILE* fin = fopen("../Triangulation-tests/input.4_0", "r");
FILE* fin = fopen("../Triangulation-tests/input.5_29", "r");
int sol=solve(n);
int a=sol/n;
int b=sol%n;
printf("a = %d\n", a);
CAPITOLUL 8. EJOI 2020 8.2. TRIANGULATION 147
int dist=getDis(a,b);
return 0;
}
// ----------------------------------------------------
#include <bits/stdc++.h>
//#include "triangulation.h"
// ----------------------------------------------------
now = 0;
do
{
++rdis;
fadd(now, n - 1);
} while (now != x && now != y);
// ----------------------------------------------------
int sta[105];
int Min = 200, ans = 0;
int query(int a, int b);
int solve(int n)
{
int top = 0;
sta[++top] = 1;
sta[++top] = n - 1;
return ans;
}
// ----------------------------------------------------
int main()
{
//FILE* fin = fopen("../Triangulation-tests/input.0_2", "r");
//FILE* fin = fopen("../Triangulation-tests/input.1_0", "r");
//FILE* fin = fopen("../Triangulation-tests/input.2_1", "r");
//FILE* fin = fopen("../Triangulation-tests/input.3_2", "r");
//FILE* fin = fopen("../Triangulation-tests/input.4_0", "r");
FILE* fin = fopen("../Triangulation-tests/input.5_29", "r");
int sol=solve(n);
int a=sol/n;
int b=sol%n;
printf("a = %d\n", a);
printf("b = %d\n", b);
int dist=getDis(a,b);
return 0;
}
// ----------------------------------------------------
//#include "triangulation.h"
#include <algorithm>
// ----------------------------------------------------
#include <bits/stdc++.h>
now = 0;
do
{
++rdis;
CAPITOLUL 8. EJOI 2020 8.2. TRIANGULATION 150
fadd(now, n - 1);
} while (now != x && now != y);
// ----------------------------------------------------
int solve(int n)
{
int lst = 1, ans1 = -1, ans2 = -1;
auto val = [&n](int a, int b)
{
return max(a ? a : b, n - b);
};
lst = i;
}
// ----------------------------------------------------
int main()
{
//FILE* fin = fopen("../Triangulation-tests/input.0_2", "r");
//FILE* fin = fopen("../Triangulation-tests/input.1_0", "r");
//FILE* fin = fopen("../Triangulation-tests/input.2_1", "r");
//FILE* fin = fopen("../Triangulation-tests/input.3_2", "r");
//FILE* fin = fopen("../Triangulation-tests/input.4_0", "r");
FILE* fin = fopen("../Triangulation-tests/input.5_29", "r");
int sol=solve(n);
int a=sol/n;
int b=sol%n;
printf("a = %d\n", a);
printf("b = %d\n", b);
int dist=getDis(a,b);
return 0;
}
8.3 exam
Problema 3 - Exam 100 de puncte
N elevi sunt aliniaţi, dând un examen. Sunt numerotaţi de la stânga la dreapta, cu numere
ı̂ntregi ı̂ncepând de la 1. E bine de ştiut cât de bine lucrează fiecare elev: al i-lea elev va face
exact Ai puncte.
Din când ı̂n când proctorul iese din sală pentru a lua o pauză, şi atunci elevii pot trişa: doi
sau mai mulţi elevi consecutivi se pot aduna şi să copieze lucrarea cea mai buna a unora dintre
ei. Drept urmare, scorurile lor devin egale cu scorul maxim din intervalul acela. Trişatul se poate
ı̂ntâmpla un număr oarecare de ori (inclusiv 0).
Pentru a trece examenul elevul al i-lea trebuie sa facă exact Bi puncte. Determinaţi numărul
maxim de elevi care pot să treacă examenul.
Input
Primul rând conţine numărul ı̂ntreg N .
Al doilea rând conţine N numere ı̂ntregi: A1 , A2 , ..., AN .
Al treilea rând conţine N numere ı̂ntregi: B1 , B2 , ..., BN .
Output
Afişaţi un singur număr ı̂ntreg: numărul maxim de elevi.
Constraints
2&N
CAPITOLUL 8. EJOI 2020 8.3. EXAM 152
Subtasks
Example
Input Output
3 2
123
222
4 3
10 1 9 1
10 9 10 9
În primul exemplu primii doi elevi pot trişa dupa care scorurile devin 2, 2, 3 şi amândoi trec
examenul.
În al doilea exemplu elevii 2 şi 3 pot să treacă examenul, dar nu simultan.
Observaţi că acest test nu poate fi prezent ı̂n subtaskurile 2, 3 sau 4.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 512 MB
The works in the final state will appear in the same relative order as they were originally
student X may end up with student’s Y ’s work if and only if in the interval between X and
Y (inclusive) there were no works that were better than X’s work
Single pass in each direction maintaining sorted stack, in O N , similar to the one described
in the task Fountain
Using these precomputed intervals we can answer whether student Y can end up with student
X’s work in O 1 and doing these checks at appropriate times will be needed in both subtasks.
Subtask 4:
We have to find the longest subsequence in B such that corresponding values in A are in
non-decreasing order. This can be done by solving a well known Longest Increasing Subsequence
(LIS) problem with O N log N solution.
Subtask 6:
2
We have to match the most values from B to A in the same order, which can be done in O N
using the standard 2D dynamic programming similar to the one that solves Longest Common
Subsequence (LCS) problem.
#include <set>
#include <cstdio>
#include <algorithm>
std::set<int>set;
struct point
{
int v, ord;
} num[200001];
return tot;
}
int main()
{
if (freopen("../Exam-tests/input.4_e", "r", stdin) == NULL) // 1206
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
scanf("%d", &n);
set.insert(0);
set.insert(n + 1);
if (a[x] == num[i].v)
R[-num[i].ord] = x;
x = *--set.upper_bound(-num[i].ord);
if (a[x] == num[i].v)
L[-num[i].ord] = x;
}
if (L[i])
update(L[i], x1 + 1);
if (R[i])
update(R[i], x2 + 1);
}
printf("%d\n", query(n));
}
#include <algorithm>
#include <cstdio>
#include <set>
#include <vector>
int n;
int A[N], B[N];
int L[N], R[N];
int tr[N];
return v;
}
signed main()
{
if (freopen("../Exam-tests/input.4_e", "r", stdin) == NULL) // 1206
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
scanf("%d", &n);
if (A[l] == it.first)
R[-it.second] = l;
int r = *--rec.upper_bound(-it.second);
if (A[r] == it.first)
L[-it.second] = r;
}
else
rec.insert(it.second);
}
if (L[i])
upd(L[i], l + 1);
if (R[i])
upd(R[i], r + 1);
}
printf("%d\n", get(n));
return 0;
CAPITOLUL 8. EJOI 2020 8.3. EXAM 156
#include <bits/stdc++.h>
struct ddata
{
int val, ty, pos;
struct SGT
{
int tr[maxn << 2];
if (x <= mid)
upd(i << 1, l, mid, x, k);
else
upd(i << 1 | 1, mid + 1, r, x, k);
if (x <= mid)
ans = max(ans, qry(i << 1, l, mid, x, y));
if (y > mid)
ans = max(ans, qry(i << 1 | 1, mid + 1, r, x, y));
return ans;
}
} sgt[2];
CAPITOLUL 8. EJOI 2020 8.3. EXAM 157
int main()
{
if (freopen("../Exam-tests/input.4_e", "r", stdin) == NULL) // 1206
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
cin >> n;
if (p[i].val == a[lpos])
lp[p[i].pos] = lpos;
if (p[i].val == a[rpos])
rp[p[i].pos] = rpos;
}
}
if (lp[i])
sgt[0].upd(1, 1, n, lp[i], Ln + 1);
if (rp[i])
sgt[1].upd(1, 1, n, rp[i], Rn + 1);
}
return 0;
}
#include <bits/stdc++.h>
int x = 0;
return x * flag;
}
if (x < 0)
{
putchar(’-’);
x = -x;
}
while (x)
{
st[++head] = x % 10 + ’0’;
x /= 10;
}
int n;
const int max_n = 1e5 + 5;
int a[max_n], b[max_n];
typedef pair<int, int> P;
CAPITOLUL 8. EJOI 2020 8.3. EXAM 159
return res;
}
set<int> id;
set<int>::iterator it;
int L[max_n], R[max_n];
int main()
{
if (freopen("../Exam-tests/input.4_e", "r", stdin) == NULL) // 1206
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
n = read_int();
it = id.upper_bound(x);
if (L[i])
modify(L[i], l + 1);
if (R[i])
modify(R[i], r + 1);
}
printf("%d", query(n));
return 0;
}
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
#define setIO(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
#define closefile fclose(stdin),fclose(stdout)
#define see(x) cerr<<x<<" "
#define seeln(x) cerr<<x<<endl
#define out(x) cerr<<#x<<" = "<<x<<" "
#define outln(x) cerr<<#x<<" = "<<x<<endl
#define outarr(x,l,r) cerr<<#x"["<<l<<"-"<<r<<"] = "; \
for (int _i=l;_i<=r;++_i) cerr<<x[_i]<<" "; cerr<<endl;
#define m_p make_pair
#define sz(x) (int)x.size()
if (flag)
x = -x;
}
return b > a ? a = b, 1 : 0;
}
set<int> S;
int query(int x)
{
int ans = 0;
return ans;
}
void init()
{
read(n);
S.insert(-inf);
S.insert(inf);
if (x > 0)
S.insert(x);
else
{
x = -x;
l[x] = *(--S.upper_bound(x));
r[x] = *S.lower_bound(x);
void solve()
{
for (int i = 1; i <= n; ++i)
{
int L = 0, R = 0;
if (l[i] != -inf)
L = query(l[i]);
if (r[i] != inf)
R = query(r[i]);
if (r[i] != inf)
update(r[i], R + 1);
if (l[i] != -inf)
update(l[i], L + 1);
}
printf("%d\n", query(n));
}
int main()
{
if (freopen("../Exam-tests/input.4_e", "r", stdin) == NULL) // 1206
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
init();
solve();
return 0;
}
#include <algorithm>
#include <set>
#include <cctype>
#include <cstdio>
if (c == ’-’)
{
f = 1;
c = getchar();
}
while (isdigit(c))
{
x = x * 10 + c - ’0’;
c = getchar();
}
return f ? -x : x;
}
CAPITOLUL 8. EJOI 2020 8.3. EXAM 163
if (vx == vy)
return x > y;
int query(int x)
{
int s = 0;
while (x)
{
s = max(s, c[x]);
x -= lowbit(x);
}
return s;
}
int main()
{
if (freopen("../Exam-tests/input.4_e", "r", stdin) == NULL) // 1206
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
n = readint();
s.insert(0);
s.insert(n + 1);
CAPITOLUL 8. EJOI 2020 8.4. XORSORT 164
if (a[pre[x]] != b[x])
pre[x] = 0;
suc[x] = *s.lower_bound(x);
if (a[suc[x]] != b[x])
suc[x] = n + 1;
}
printf("%d\n", query(n));
return 0;
}
8.4 xorsort
Problema 4 - XOR Sort 100 de puncte
Vi se dă un număr ı̂ntreg S şi un şir A de N numere ı̂ntregi mai mari sau egale cu 0, indexat
de la 1. Aveţi voie să aplicaţi următoarea operaţie pe el: alegeţi un indice i (1 & i & N ), alegeţi
un vecin j (1 & j & N , fie j i 1 sau j i 1) şi ı̂l ı̂nlocuiţi pe Ai cu (Ai h Aj ) unde h este
XOR-ul pe biţi al numerelor. Definim XOR-ul pe biţi la finalul enunţului.
Scopul vostru este să ı̂l sortaţi pe A:
dacă S 1 atunci se cere ca şirul final să fie crescător, i.e. Ai $ Ai1 pentru 1 & i $ N
dacă S 2 atunci se cere ca şirul final să fie nedescrescător, i.e. Ai & Ai1 pentru 1 & i $ N
1&S &2
2 & N & 1000
CAPITOLUL 8. EJOI 2020 8.4. XORSORT 165
0 & Ai $ 220
Subtasks
Example
Input Output
51 3
32841 12
43
54
52 3
44201 32
43
54
Explicaţie la primul output:
[3, 2, 8, 4, 1] -¿ [1, 2, 8, 4, 1] -¿ [1, 2, 8, 12, 1] -¿ [1, 2, 8, 12, 13]
Explicaţie la al doilea output:
[4, 4, 2, 0, 1] -¿ [4, 4, 6, 0, 1] -¿ [4, 4, 6, 6, 1] -¿ [4, 4, 6, 6, 7]
XOR-ul dintre biţii a şi b este 0 dacă a b şi 1 altfel.
XOR-ul pe biţi ı̂ntre numerele ı̂ntregi a şi b este operaţia XOR făcută bit cu bit asupra biţilor
lui a şi b:
75 h 29 = 86
1001011 h 0011101 = 1010110
În C/C++/Java se foloseşte operatorul ˆ pentru a face XOR.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 512 MB
1. Aj h Ai
2. Ai h Aj
3. Aj h Ai
n n1
Since the bubble sort can take at most 2
swaps to sort, our method will finish in at most
n n1
3 & 40 000 operations.
2
Subtask 2 (35 points):
Here, since swapping is not a viable option, it’s likely that we should rearrange the array with
transformed values and then recover original values.
CAPITOLUL 8. EJOI 2020 8.4. XORSORT 166
Recovering the original values is important, because the resulting array should not have equal
members and preserving original array elements is one way to ensure that.
Our approach can be divided into n stages. In each stage, we will swap the largest element to
the end of the unsorted part of the array. Consider the array A a, b, c, d, e, f , where c is the
maximal element.
Firstly, we transform our array to the following one in n 1 operations:
a h b, b h c, c h d, d h e, e h f, f ,
a h c, b h c, c h d, c h e, c h f, c.
Last two steps took maximum of n 1 (when the maximum element is the first one) operations
in total, i.e. each stage can take 2 n 2 operations.
As we can see, all the elements, apart from the last, are the original elements XOR-ed with c.
Now we can move on to the next stage, but we have to pick the maximum from the original
array, not the transformed one. For example, if the second maximum is e, we will move fourth
element of A to fifth position (as c already holds the last) even if some element became bigger
after the previous transformations.
Suppose that A would be increasingly sorted as follows: b, f, a, d, e, c. Then, after completing
all the stages, which takes n n 1 operations, A will be like this:
b h f, f h a, a h d, d h e, e h c, c
(for example, like in the first stage, at the end of the second stage, last (fifth) element would be
e h c, while all the elements before fifth would be XOR-ed with e h c and a h c h e h c a h e, so
we would have a similar situation as at the end of the first stage).
In the final sweep, we can recover original elements of A doing following operations:
we already dragged some maximal bits, which is non-decreasing, thus the array is sorted. In total,
this method takes 2 n 20 operations, which is exactly 40 000 when n 1000.
CAPITOLUL 8. EJOI 2020 8.4. XORSORT 167
int a[MAXN];
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../XorSort-tests/input.3_14",
(char*)"../XorSort-tests/output.3_14",
(char*)"xorsort.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
registerTestlibCmd(argc, argv);
int n = inf.readInt();
int S = inf.readInt();
if (S == 1)
{
for (int i = 1; i < n; i++)
if (!(a[i] < a[i + 1]))
quitf(_wa, "doesn\’t meet requirement. A[%d] = %d, A[%d] = %d",
i, a[i], i + 1, a[i + 1]);
}
else
{
for (int i = 1; i < n; i++)
if (!(a[i] <= a[i + 1]))
quitf(_wa, "doesn\’t meet requirement. A[%d] = %d, A[%d] = %d",
i, a[i], i + 1, a[i + 1]);
}
quitf(_ok, "OK");
return 0;
}
#include <cstdio>
#include <vector>
#include <cstring>
#include <cassert>
int Do[1048576];
dfs(l + 1, r, x, stat);
dfs(l + 1, r, x ˆ a[l], stat | (1 << (l - n - 1)));
}
Xor(r, r - 1);
int main()
{
if (freopen("../XorSort-tests/input.3_14", "r", stdin) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
scanf("%d", a + i);
if (S == 2)
{
for (int i = 19; ˜i; i--)
{
for (int j = 1; j < n; j++)
if (a[j] & (1 << i))
if (!(a[j + 1] & (1 << i)))
Xor(j + 1, j);
printf("%d\n", (int)ope.size());
if (!have)
{
for (int j = now - cnt; j < now; j++)
Xor(j, j + 1), Xor(j + 1, j);
--now;
}
}
printf("%d\n", (int)ope.size());
#include <bits/stdc++.h>
int getSum(int x)
{
int res = 0;
while (x > 0)
{
res += c[x];
x -= x & -x;
}
return res;
}
int n, s;
int a[40005];
int getN()
{
int ans = 0;
{
ans += getSum(a[i] - 1);
add(a[i], 1);
}
return ans;
}
vector<int>v1, v2;
int times = 40000;
if (l >= r)
return ;
int ok = 0;
if (!ok)
{
Do(id - 1, l, r);
return ;
}
Do(id - 1, l, r - 1);
}
int p[40005];
int mxi = l;
int ji = a[mxi] ˆ x;
Do1(l, r - 1, ji);
}
int main()
{
if (freopen("../XorSort-tests/input.3_14", "r", stdin) == NULL)
{
perror("freopen() failed");
return EXIT_FAILURE;
}
// returneaza 0 daca nu exista fisierul de intrare ... !!!
if (s == 2)
Do(19, 1, n);
else
{
for (int i = 1; i < n; i++)
XOR(i, i + 1);
printf("%d\n", (int)v1.size());
return 0;
}
8.5 cards
Problema 5 - Card Trick 100 de puncte
Doi jucători doresc să realizeze un truc folosind un pachet standard cu 52 de cărţi de joc.
Pentru comoditate, valorile cărţilor sunt distincte, cuprinse ı̂ntre 0 şi 51.
Iniţial cărţile sunt aşezate pe o masă, formând un singur rând, cu faţa ı̂n sus (cu valorile
vizibile), ı̂ntr-o anumită ordine necunoscută de cei doi.
CAPITOLUL 8. EJOI 2020 8.5. CARDS 173
Primul jucător merge la masă, priveşte cărţile şi realizează cel mult S interscimbări. Fiecare
interschimbare constă ı̂n alegerea a două cărţi de pe poziţiile i şi j (i şi j pot fi egale) şi duce
cartea de pe poziţia i ı̂n locul celei de pe poziţia j, şi invers.
După aceasta primul jucător pleacă fără a comunică cu primul şi toate cărţile vor fi ı̂ntoarse
(deci nu se mai vede ce conţin), fără să li se schimbe ordinea. Al doilea jucător este invitat la
masă şi este ı̂ntrebat unde se găseşte o anumită carte cu o anume valoare ţintă permiţându-i-se să
ı̂ntoarcă cel mult T cărţi, una câte una. Dacă una dintre cărţile ı̂ntoarse este cea ţintă, atunci cei
doi jucători câştigă. Scopul tău este să scrii două programe care să simuleze acţiunile celor doi şi
să câştige jocul.
Implementation Details
Vi se vor furniza două programe - FirstPlayer şi SecondPlayer, ı̂mpreună cu un exemplu
de evaluator.
În FirstPlayer ai de implementat următoarea funcţie:
S: numărul de interschimbări
T : number de ghiciri permise
target: cartea a cărei valori trebuie descoperită
Sample interaction
Mai jos este un exemplu de input pentru evaluatorul ataşat.
Prima linie trebuie să conţină doi ı̂ntregi: S şi T .
A doua linie trebuie să conţină 52 de numere. Al i-lea reprezintă valoarea cărţii i.
A treia linie conţine un ı̂ntreg ţinta.
CAPITOLUL 8. EJOI 2020 8.5. CARDS 174
Constraints
1&S & 52
1&T & 51
0 & ţinta $ 52
Subtasks
***
8.6 game
Problema 6 - Dots and Boxes 100 de puncte
Tamta şi Anna sunt surori la care le place să joace ”Dots and Boxes”. Jocul ı̂ncepe cu un grid
gol de N 1 pe M 1 puncte (şi un grid corespunzător de N pe M pătraţele).
Jucătorii joaca alternativ adăugând o singură muchie orizontală sau verticală ı̂ntre două puncte
neunite adiacente (două puncte sunt adiacente dacă distanţa dintre ele este 1).
Dacă un jucător completează a patra latură a unui pătrăţel de 1 1 atunci jucătorul câştigă
un punct şi ia o tură ı̂n plus, altfel tura alternează la celălalt jucător. Jocul se termină când nu
se mai pot adăuga muchii.
Trei ture posibile ı̂ntr-un grid cu =2,=3 (liniile punctate sunt mutările jucătorilor):
CAPITOLUL 8. EJOI 2020 8.6. GAME 176
Anna şi Tamta au jucat o vreme şi ai observat că ı̂n starea curentă
fiecare pătrăţel are exact zero sau două laturi neunite şi ca Anna
e la mutare (puteţi vedea un exemplu ı̂n imaginea din dreapta. Observaţi
că imaginea de mai sus nu corespunde acestor restricţii).
Scorul jocului este SA ST unde SA este numărul de puncte ce ı̂l face
Anna de acum ı̂nainte şi ST este numărul de puncte pe care ı̂l face Tamta.
Evident, Anna vrea să maximizeze scorul şi Tamta ı̂ncearcă să ı̂l minimizeze.
Calculaţi scorul final ştiind că amândoi jucătorii joacă optim.
Input
Prima linie conţine două numere ı̂ntregi N şi M care reprezintă numărul de rânduri şi de
coloane ı̂n gridul de pătrăţele.
Fiecare dintre următoarele N 1 linii conţine M cifre, acestea fiind unu sau zero (neseparate
prin spaţii), cel de al j-lea număr ı̂n al i-lea rând fiind unu dacă şi nu mai dacă exista o muchie
orizontală ı̂ntre punctele cu coordonatele i, j şi i, j 1.
Fiecare dintre următoarele N linii conţine M 1 cifre, ı̂n acelaşi format, cel de al j-lea număr ı̂n
al i-lea rând fiind unu dacă şi numai dacă exista o muchie verticală ı̂ntre punctele cu coordonatele
i, j şi i 1, j .
Output
Outputul conţine un singur rând cu un singur număr ı̂ntreg, scorul final.
Constraints
3 & N, M & 20
Fiecare pătrăţel are exact zero sau două laturi neunite.
Subtasks
Definim o componentă ca fiind un set maximal de pătrăţele neluate de
nimeni pe un grid astfel ı̂ncât te poţi deplasă de la oricare pătrăţel la oricare
altul traversând muchii care nu sunt ı̂ncă desenate.
Example
CAPITOLUL 8. EJOI 2020 8.6. GAME 177
Input Output
33 -5
000
111
011
55 6
00100
10100
11010
00100
01000
11100
011111
001011
101011
110111
100111
Primul exemplu, cu una dintre secvenţele optime de mutări, sunt desenate mai jos (numerele
pe muchii reprezintă ordinea mutării, culoarea roşie e folosită de Anna, cea albastră de Tamta).
Al doilea exemplu este cel din imaginile de mai sus.
components in this subtask and one could solve it by solving each state, similar to subtask 2, this
#of components
time the number of states being O 2 .
***
previous level if j is odd and to the right endpoint of the same rod if j is even. At the last level,
there is a hook for hanging a coat on both endpoints of each rod. The hooks are numbered from
n
1 to 2 in the left-to-right order.
For example, the rack for n 3 looks as follows:
Mojca would like to hang all her coats on the rack. Every coat weighs exactly 1 unit. To avoid
breaking the delicate structure, she has to hang them in such an order that the difference between
the total weight wl placed on the left endpoint of any given rod and the total weight wr placed
on the right endpoint of the same rod is either 0 or 1 (wl wr " r0, 1x). (By the laws of physics,
the difference could also be -1, but a right-leaning rack looks really ugly to Mojca.) The rods are
so thin that their weight can be neglected.
Having heard about your problem-solving proficience, Mojca asks you for help. Write a pro-
9
gram that reads the integer n and an integer k and prints the sequential number (modulo 10 7)
of the hook on which Mojca has to hang her k-th coat.
Input
The input consists of a single line, which contains the integers and , separated by a space.
Output
Print the number (modulo ) of the hook to be used in the -th step.
Constraints
n " 1, 10 ,
6
111
aur: Alexandru Luchianov, clasa a 8-a, Liceul Internaţional de Informatică din Bucureşti,
. aur: Luca Perju-Verzotti, clasa a 8-a, Colegiul Naţional de Informatică ”Tudor Vianu” din Bucureşti,
. aur: Alexandru Raul Todoran, clasa a 7-a, Liceul Teoretic ”Aurel Vlaicu” din Orăştie, jud. Hunedoara,
. argint: Mihnea Andreescu, clasa a 8-a, Liceul Teoretic Internaţional de Informatică din Bucureşti.
179
CAPITOLUL 9. EJOI 2019 9.1. HANGING RACK 180
Example 1
Input
32
Output
Comment
In this case, the hooks should be used in the following order: 1, 5, 3, 7, 2, 6, 4, 8. In the second
step, Mojca thus has to hang her coat on the hook with number 5.
Example 2
Input
5 10
Output
19
Comment
Here, the order of hooks is 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, etc.
Let’s look on the level 0. First coat should go in the left subtree, second should go in the right
subtree, and so on. So we can calculate, in which subtree is k-th coat by looking on the parity
of number k. Now we know, which subtree we need, let’s calculate how many coats are in this
subtree. Now have the same task for the subtree, do it recursively. We have n layers of recursion,
and on each step we solve problem in O 1 time, so the total time will be O n.
#include <bits/stdc++.h>
int main()
CAPITOLUL 9. EJOI 2019 9.1. HANGING RACK 181
{
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
long long n, k;
cin>>n>>k;
cout<<rez<<endl;
return 0;
}
ll n,k;
112
https://oj.uz/profile/Sho10
CAPITOLUL 9. EJOI 2019 9.1. HANGING RACK 182
ll pw(ll a,ll b)
{
if(b==0) return 1;
ll n=pw(a,b/2);
if(b%2==1)
{
return (((n*n)%mod)*a)%mod;
}
else
return (n*n)%mod;
}
int32_t main()
{
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
CODE_START;
cin>>n>>k;
ll ans=1,s1=1;
while(k!=1)
{
if(k%2==0)
{
ans=ans+pw(2LL,n-s1);
ans=ans%mod;
s1++;
ll val=k/2;
k=k-val;
}
else
{
s1++;
ll val=k/2;
k=k-val;
}
}
cout<<ans<<endl;
}
#include <bits/stdc++.h>
int i, j, k, m, n;
int a[N];
int pw[1000001];
int main()
{
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
ll k;
CAPITOLUL 9. EJOI 2019 9.1. HANGING RACK 183
pw[0] = 1;
F1(i, n) pw[i] = pw[i - 1] * 2 % MOD;
int ret = 0;
for (int i = n - 1; i >= 0; i--)
{
if (k % 2 == 1)
{
ret = (ret + pw[i]) % MOD;
}
k /= 2;
}
return 0;
}
#include <bits/stdc++.h>
ll expo(ll x, ll n, ll m)
{
if(n==0)return 1;
ll u=expo(x,n/2,m);
u=(u*u)%m;
if(n%2)u=(u*x)%m;
return u;
}
int main ()
{
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
if(n>59)
start=1;
else
{
ll temp=1e18;
ll res=expo(2,n,temp);
if(k<=res)
start=1;
else
{
start=2;
k-=res;
}
}
//cout<<start<<endl;
int mod=1e9+7;
while(k>(ll)1)
{
if(k%2)
{
k/=2;
k++;
CAPITOLUL 9. EJOI 2019 9.1. HANGING RACK 184
}
else
{
k/=2;
start+=expo(2,n,mod);
start%=mod;
}
n--;
}
cout<<start<<endl;
}
#include <bits/stdc++.h>
ll reverse1(ll num,ll n)
{
ll b=0;
for (ll i = n - 1; i >= 0&# i--)
{
if (num % 2 == 1)
{
b=(b+din[i])%MOD;
//cout<<b<<endl;
}
num/=2;
}
return b;
}
int main()
{
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
ll n,k;
cin>>n>>k;
din[0]=1;
for(ll i=1;i<1000001;i++)
{
din[i]=(din[i-1]*2)%MOD;
}
//cout<<’h’;
//k--;
cout<<(reverse1(k-1, n)+1)%MOD<<endl;
return 0;
}
#include <iostream>
#include <vector>
#include <set>
#include <map>
CAPITOLUL 9. EJOI 2019 9.1. HANGING RACK 185
#include <algorithm>
#include <cmath>
int main()
{
//cout<<"INF = "<<INF<<"\n";
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
int n;
ll k;
cin >> n >> k;
k--;
ll res = 1;
ll e;
ll p;
for(e = n - 1, p = 1; e >= 0; e--, p = (p * 2) % MOD)
if(e < 60)
if(k & ((ll)1<<e))
res = (res + p) % MOD;
cout << res << "\n";
}
OBS: 113
Listing 9.1.7: 237607-rack.cpp
// https://oj.uz/submission/237607
#include <bits/stdc++.h>
ll solve(ll n, ll k)
{
if(n==1&&k==1)return 1%MOD;
if(n==1&&k==2)return 2%MOD;
ll ans = fast(2,n-1);
if(k%2==0)
return (solve(n-1,k/2)+ans)%MOD;
else
113
http://www.cplusplus.com/doc/tutorial/operators/
CAPITOLUL 9. EJOI 2019 9.1. HANGING RACK 186
return solve(n-1,(k+1)/2)%MOD;
}
int main()
{
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
ll n,k,ans;
cin>>n>>k;
ans=solve(n,k)%MOD;
if(ans<0) ans+=MOD;
cout<<ans<<’\n’;
return 0;
}
#include <iostream>
if (casacos % 2 == 0)
recursiva(level + 1, casacos / 2);
else
{
ans[level] = true;
recursiva(level + 1, (casacos - 1) / 2);
}
}
int main()
{
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
#include <bits/stdc++.h>
int64_t res = 1;
while (y > 0)
{
if (y % 2 == 1)
{
res = (res * x) % MOD;
}
y >>= 1;
x = (x * x) % MOD;
}
return res;
}
return 1;
}
if (k % 2 == 0)
{
return solve(n - 1, k / 2);
}
else
{
int64_t k2 = 0;
if (k > 1)
{
k2 = k / 2;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int64_t n, k;
cin >> n >> k;
cout << solve(n, k - 1) << endl;
}
114
OBS: int64 t,¡cstdint¿
#include <bits/stdc++.h>
114
http://www.cplusplus.com/reference/cstdint/
CAPITOLUL 9. EJOI 2019 9.1. HANGING RACK 188
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define int long long
#define fio() ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define FOR for(int i=1;i<=n;i++)
#define mid ((start+end)/2)
#define ort ((bas+son)/2)
int n,m,b[li],a[li],k,flag,t;
int cev;
string s;
vector<int> v;
main(void)
{
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
scanf("%lld %lld",&n,&m);
while(m>1)
{
//˜ m--;
v.pb((m%2));
//˜ if(m/2==0)break;
m=(m+1)/2;
}
int bas=1;
int say=n-1;
//˜ reverse(v.begin(),v.end());
for(int i=0;i<(int)v.size();i++)
{
if(v[i]==0) bas=add(bas,fp(2,say));
say--;
//˜ cout<<bas<<" "<<son<<endl;
}
printf("%lld\n",bas%mod);
return 0;
}
// https://oj.uz/submission/242103
#include<bits/stdc++.h>
val *= val;
val %= M;
n /= 2;
}
return res;
}
signed main()
{
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);
int n, k;
cin >> n >> k;
k--;
int ans = 1;
for(int i = 0; i < n; i++)
{
if(k & 1)
{
ans += bin_pow(2, n - i - 1);
ans %= M;
}
k /= 2;
}
#include <bits/stdc++.h>
int bp (int n)
{
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 190
if (!n) return 1;
if (n & 1) return 2ll * bp(n-1) % MOD;
int b = bp(n>>1);
return b * b % MOD;
}
int n, k, ans = 1;
int32_t main ()
{
std::freopen("../rack-tests/input.test_03_05", "r", stdin); // 751564994
//std::freopen("rack.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
return 0;
}
115
OBS: ios base::sync with stdio(0);
9.2 XORanges
Problema 2 - XORanges 100 de puncte
Janez loves oranges! So he made a scanner for oranges. With a cameras and a Raspberry Pi
3b+ computer, he started creating 3D images of oranges. His image processor is not a very good
one, so the only output he gets is a 32-bit integer, which holds information about the holes on the
peel. A 32- bit integer is represented as a sequence of 32 digits (bits) each of which is one or zero. If
we start from 0 we can obtain D by adding for every i-th bit that is equal to one. More formally the
31 30 1 0
number D is represented by the sequence d31 , d30 , ..., d0 when D d31 2 d30 2 ...d1 2 d0 2 .
For example, 13 is represented as 0, ..., 0, 1, 1, 0, 1.
Janez scanned n oranges; however, sometimes he decides to rescan one of the oranges (i-th
orange) during the execution of your program. This means that from this scan on, he uses the
updated value for the i-th orange.
Janez wants to analyse those oranges. He finds exclusive or (XOR) operation very interesting,
so he decides to make some calculations. He selects a range of oranges from l to u (where l & u)
and wants to find out the value of XOR of all elements in that range, all pairs of consecutive
elements in that range, all sequences of 3 consecutive elements and so on up to the sequence of
u l 1 consecutive elements (all elements in the range).
I.e. If l 2 and u 4 and there is an array of scanned values A, program should return the
value of a2 h a3 h a4 h a2 h a3 h a3 h a4 h a2 h a3 h a4 , where h represents the XOR and
ai represents the i-th element in array A.
Let XOR operation be defined as:
115
https://www.geeksforgeeks.org/fast-io-for-competitive-programming/
. https://codeforces.com/blog/entry/18093
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 191
If the i-th bit of the first value is the same as the i-th bit of the second value, the i-th bit of
the result is 0; If the i-th bit of the first value is different as the i-th bit of the second value, the
i-th bit of the result is 1.
x y xhy
0 0 0
0 1 1
1 0 1
1 1 0
Tabelul 9.1: XOR
13 = 0...0 0 1 1 0 1
23 = 0...0 1 0 1 1 1
13 h 23 = 0...0 1 1 0 1 0
Input
In the first line of the input there are 2 positive integers n and q (total number of rescans and
queries - actions).
In the next line, there are n space-separated non-negative integers, which represent values of
the array A (scan results for oranges). Element ai contains the value for i-th orange. Index i
starts with 1.
Actions are described in the next q lines with three space-separated positive integers.
If the action type is 1 (rescan), the first integer equals 1 and is followed by i (index of an
orange that Janez wants to rescan) and j (the result of the rescan of the i-th orange).
If the action type is 2 (query), the first integer equals 2 and is followed by l and u.
Output
You should print exactly one integer for each query with the matching result for the query.
You should print every value in a new line. Note that the i-th line of the output should match
the result of the i-th query.
Constraints
ai & 109
0 $ n, q & 2
5
10
Subtasks
1. [12 points]: 0 $ n, q & 100
2. [18 points]: 0 $ n, q & 500 and there are no rescans (actions of type 1)
3. [25 points]: 0 $ n, q & 5000
Examples
Example 1
Input
3 3
1 2 3
2 1 3
1 1 3
2 1 3
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 192
Output
2
0
Comment
At the begining, A 1, 2, 3. The first query is on the full range. The result of the analysis
is 1 h 2 h 3 h 1 h 2 h 2 h 3 1 h 2 h 3 2.
Then the value of the first orange is updated to 3. This leads to a change on the same query
(on a range 1, 3) 3 h 2 h 3 h 3 h 2 h 2 h 3 3 h 2 h 3 0.
Example 2
Input
5 6
1 2 3 4 5
2 1 3
1 1 3
2 1 5
2 4 4
1 1 1
2 4 4
Output
2
5
4
4
Since x h x 0, after simplification of the final h-sum each element will be presented at most once.
To determine if the element is presented in the final h- sum, we need to calculate the number of
segments it belongs to. If this number is odd, then the element will be in the final h-sum.
The element i of segment l; r belongs to i l 1 r i 1 subsegments. This number is
odd if both i l 1 and r i 1 are odd. If l and r has different parity, then it is impossible,
so the final h-sum will be 0, else i l 1 r i 1 will be odd for i l, l 2, l 4, ..., r. Now we
need data structure to calculate sums like xl h xl 2 h xl 4 h ... h xr. We can use two segment
trees (or Fenwick trees), one for elements with odd indices, another for element with even indices.
So, the queries can be answered in O log n time.
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <unordered_set>
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 193
#include <unordered_map>
#include <queue>
#include <cassert>
#include <string>
#include <cstring>
#include <bitset>
#include <random>
#include <chrono>
int main ()
{
std::freopen("../xoranges-tests/input.s5t5", "r", stdin); // 751564994
std::freopen("xoranges.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
int n, q;
cin >> n >> q;
vi a (n);
FOR (i, 1, n + 1)
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 194
{
cin >> a[i];
update (i, a[i], i & 1);
}
while (q--)
{
int t, lo, hi;
cin >> t >> lo >> hi;
if (t == 1)
{
// Update
update (lo, a[lo], lo & 1);
update (lo, hi, lo & 1);
a[lo] = hi;
}
else
{
// Query
const int T = hi - lo + 1;
if ((T & 1) == 0)
{
cout << 0 << ’\n’;
continue;
}
cout << range_sum (lo, hi, lo & 1) << ’\n’;
}
}
return 0;
}
/*
argc = 4
checker
../xoranges-tests/input.s5t5
../xoranges-tests/output.s5t5
xoranges.out
----------------------
1
Correct
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <cmath>
int n, q;
int v[5 + N];
class AIB
{
private:
int a[5 + N];
int lsb(int i)
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 195
{
return (i & (-i));
}
public:
void Build(int pos, int val)
{
for(int i = pos; i <= n; i += lsb(i))
a[i] = a[i] ˆ val;
}
return s;
}
};
AIB FenwOdd, FenwEven;
int main()
{
std::freopen("../xoranges-tests/input.s5t5", "r", stdin); // 751564994
std::freopen("xoranges.out", "w", stdout);
while(q--)
{
int t, x, y;
scanf("%d%d%d", &t, &x, &y);
if(t == 1)
{
if(x & 1)
FenwOdd.Update(x, y);
else
FenwEven.Update(x, y);
}
else
{
if((x - y + 1) & 1)
{
if(y & 1)
printf("%d\n", FenwOdd.Query(y) ˆ FenwOdd.Query(x-2));
else
printf("%d\n", FenwEven.Query(y) ˆ FenwEven.Query(x-2));
}
else
printf("0\n");
}
}
return 0;
}
#include <bits/stdc++.h>
int i, j, k, m, n;
int a[N];
int h[2][N];
int main()
{
std::freopen("../xoranges-tests/input.s5t5", "r", stdin); // 751564994
std::freopen("xoranges.out", "w", stdout);
int q, t;
cin >> n >> q;
F1(i, n)
{
scanf("%d", &a[i]);
add(i % 2, (i + 1) / 2, a[i]);
}
while (q--)
{
scanf("%d%d%d", &t, &i, &j);
if (t == 1)
{
add(i % 2, (i + 1) / 2, a[i]);
a[i] = j;
add(i % 2, (i + 1) / 2, a[i]);
}
else
{
int len = j - i + 1;
int ret = 0;
if (len % 2)
{
ret = get(j % 2, (j + 1) / 2) ˆ get(i % 2, (i - 1) / 2);
}
printf("%d\n", ret);
}
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 197
return 0;
}
#include <bits/stdc++.h>
#define F first
#define S second
//#define endl ’\n’
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define maxp 22
#define mod (int)1e9+7
#define N (int)1e5*2+1
struct ano
{
int even;
int odd;
};
int arr[N];
ano seg[4*N];
return res;
}
int mid=(s+e)/2;
build(s,mid,idx*2);
build(mid+1,e,idx*2+1);
bool even=true;
if((mid-s+1)%2)
even=false;
seg[idx]=join(seg[idx*2],seg[idx*2+1],even);
// cout<<"up "<<s<<" "<<e<<" "<<seg[idx].odd<<" "<<seg[idx].even<<endl;
}
if(s>k || e<k)
return;
int mid=(s+e)/2;
update(s,mid,idx*2,k,u);
update(mid+1,e,idx*2+1,k,u);
bool even=true;
if((mid-s+1)%2)
even=false;
seg[idx]=join(seg[idx*2],seg[idx*2+1],even);
}
if(s>qe || e<qs)
return {0,-1};
int mid=(s+e)/2;
ano p1,p2;
p1=query(s,mid,idx*2,qs,qe);
p2=query(mid+1,e,idx*2+1,qs,qe);
// cout<<s<<" "<<e<<endl;
// cout<<p1.odd<<" "<<p1.even<<" "<<p2.odd<<" "<<p2.even<<endl;
if(p1.odd==-1)
return p2;
if(p2.odd==-1)
return p1;
bool even=true;
if((min(mid,qe)-max(s,qs)+1)%2)
even=false;
return join(p1,p2,even);
}
int main ()
{
//fastio;
int n,q;
cin>>n>>q;
int i;
for(i=1;i<=n;i++)
cin>>arr[i];
build(1,n,1);
while(q--)
{
int task,x,y;
cin>>task>>x>>y;
if(task==1)
update(1,n,1,x,y);
else
if((x-y+1)%2)
cout<<query(1,n,1,x,y).odd<<endl;
else
cout<<0<<endl;
}
}
// https://oj.uz/submission/237576
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <cmath>
int gi(int i)
{
if(i % 2 == 0)
return i / 2;
return (n + i) / 2;
}
return res;
}
int main()
{
std::freopen("../xoranges-tests/input.s5t5", "r", stdin); // 751564994
std::freopen("xoranges.out", "w", stdout);
while(q--)
{
int tp, a, b;
cin >> tp >> a >> b;
a--;
if(tp == 1)
{
a = gi(a) + n;
st[a] = b;
while(a >= 1)
{
a = a >> 1;
st[a] = st[a<<1] ˆ st[a<<1|1];
}
}
else
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 200
{
b--;
if(a % 2 == b % 2)
{
cout << rxq(gi(a), gi(b) + 1) << "\n";
}
else
{
cout << "0\n";
}
}
}
}
#include <iostream>
int n, q;
ui oranges[200005];
ui st_par[400005];
ui st_impar[400005];
ui query_par(int l, int r)
{
ui res = 0;
if (r & 1)
res ˆ= st_par[--r];
}
return res;
}
ui query_impar(int l, int r)
{
ui res = 0;
if (r & 1)
res ˆ= st_impar[--r];
}
return res;
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 201
int main()
{
std::freopen("../xoranges-tests/input.s5t5", "r", stdin); // 751564994
std::freopen("xoranges.out", "w", stdout);
while (q--)
{
int aux;
cin >> aux;
if (aux == 1)
{
//rescan
int index;
cin >> index;
cin >> oranges[index - 1];
if ((index - 1) % 2 == 0)
update_par(index - 1);
else
update_impar(index - 1);
}
else
{
//query
int l, u;
cin >> l >> u;
if ((u - l + 1) % 2 == 0)
cout << 0 << ’\n’;
else
if ((l - 1) % 2 == 0)
cout << query_par(l - 1, u - 1) << ’\n’;
else
cout << query_impar(l - 1, u - 1) << ’\n’;
}
}
cout.flush();
return 0;
}
#include<bits/stdc++.h>
int t[2][N];
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 202
int n, q, a[N];
signed main()
{
std::freopen("../xoranges-tests/input.s5t5", "r", stdin); // 751564994
std::freopen("xoranges.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> q;
while(q--)
{
int type;
cin >> type;
if(type == 1)
{
int ind, val;
cin >> ind >> val;
ind--;
upd(ind, a[ind] ˆ val);
a[ind] = val;
}
if(type == 2)
{
int l, r;
cin >> l >> r;
l--;
r--;
int ans = 0;
if((l & 1) & (r & 1))
{
ans ˆ= get(1, l, r + 1);
}
return 0;
}
#include <bits/stdc++.h>
int m = (l + r) / 2;
build(2*x+1, l, m);
build(2*x+2, m+1, r);
t1[x] = t1[2*x+1] ˆ t1[2*x+2];
t2[x] = t2[2*x+1] ˆ t2[2*x+2];
}
int m = (l + r) / 2;
if (i > m)
update(2*x+2, m+1, r, i, v);
else
update(2*x+1, l, m, i, v);
int get (int x, int lx, int rx, int l, int r, int type)
{
if (lx > r or rx < l) return 0;
if (lx >= l and rx <= r)
{
if (type == 1)
return t1[x];
else
return t2[x];
}
return g1 ˆ g2;
}
CAPITOLUL 9. EJOI 2019 9.2. XORANGES 204
int32_t main ()
{
std::freopen("../xoranges-tests/input.s5t5", "r", stdin); // 751564994
std::freopen("xoranges.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
build(0, 0, n-1);
while (q --)
{
int t, i, j;
cin >> t >> i >> j;
if (t == 1)
update(0, 0, n-1, i-1, j);
else
if ((j - i) % 2)
cout << "0\n";
else
if (i % 2)
cout << get(0, 0, n-1, i-1, j-1, 2) << endl;
else
cout << get(0, 0, n-1, i-1, j-1, 1) << endl;
}
return 0;
}
ll n,q,a[200005],bit[3][200005];
a[m]=val;
}
for(;pos;pos-=pos&(-pos))
{
resˆ=bit[s1][pos];
}
return res;
}
int32_t main()
{
std::freopen("../xoranges-tests/input.s5t5", "r", stdin); // 751564994
std::freopen("xoranges.out", "w", stdout);
CODE_START;
cin>>n>>q;
for(ll i=1;i<=n;i++)
{
bit[1][i]=0;
bit[0][i]=0;
}
//cout<<"DA"<<endl;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
if(i%2==0)
{
build(1,i,a[i]);
}
else
{
build(0,i,a[i]);
}
}
//cout<<"DA"<<endl;
while(q--)
{
ll t,x,y;
cin>>t>>x>>y;
//cout<<"DA"<<endl;
if(t==1)
{
if(x%2==0)
{
update(1,x,y);
}
else
update(0,x,y);
}
else
{
if((x-y+1)%2==0)
{
cout<<0<<endl;
CAPITOLUL 9. EJOI 2019 9.3. T - COVERING 206
}
else
{
if(y%2==1)
{
cout<<(query(0,y)ˆquery(0,x-2))<<endl;
}
else
cout<<(query(1,y)ˆquery(1,x-2))<<endl;
}
}
}
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../xoranges-tests/input.s5t5",
(char*)"../xoranges-tests/output.s5t5",
(char*)"xoranges.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
116
OBS: #include ”testlib.h”
9.3 T - Covering
Problema 3 - T - Covering 100 de puncte
If you have ever played Tetris, you might know that one of the figures looks as follows:
We will call this figure a T-tetromino; a tetromino is just a fancy word for a connected geometric
figure composed of four cells. The cell marked with will be called the center cell.
Manca draws a rectangular grid with m rows and n columns and writes a number into each
cell. The rows of the table are numbered from 0 to m 1 and the columns are numbered from 0
to n 1.
116
https://github.com/MikeMirzayanov/testlib
CAPITOLUL 9. EJOI 2019 9.3. T - COVERING 207
She also marks some cells as special, e.g., by painting them red. After that, she asks Nika, a
friend of hers, to place T-tetrominoes on the grid in such a way that the following conditions are
met:
The number of T-tetrominoes has to be the same as the number of special cells. For each
Ttetromino, its center cell has to lie on some special cell.
No pair of T-tetrominoes may overlap.
All T-tetrominoes have to completely lie on the grid.
ãáà
Note that there are four possible orientations of each T-tetromino ( , , , and ). â
If the conditions cannot be satisfied, Nika should answer N o; if they can, she has to find such a
placement of T-tetrominoes that the sum of the numbers in the cells covered by the T-tetrominoes
is maximum possible. In this case, she has to tell Manca the maximum sum.
Write a program to help Nika solve the riddle.
Input
Each line contains a sequence of integers separated by a single space.
The first line of the input contains the integers m and n. Each of the following m lines contains
n integers from the interval 0, 1000. The j-th integer in the i-th line represents the number
written in the j-th cell of the i-th row of the grid. The next line contains an integer k " r1, ..., mnx.
This line is followed by k more lines, each of which consists of integers ri " r0, ..., m 1x and
ci " r0, ..., n 1x, which represent the position (the row index and column index, respectively) of
the i-th special cell. The list of special cells does not contain any duplicates.
Output
Print the maximum possible sum of the numbers in the cells covered by the T-tetrominoes, or
No if no valid placement of T-tetrominoes exists.
Constraints
1 & mn & 10
6
Subtasks
5 points: k & 1000; for each pair of distinct special cells i and j, we have ¶ri rj ¶ % 2 or
¶ci cj ¶ % 2.
10 points: k & 1000; for each pair of distinct special cells i and j, it holds that if ¶ri rj ¶ & 2
and ¶ri rj ¶ & 2, then and are adjacent by side, or more formally the following statement is
true (¶ri rj ¶ 1 and ¶ci cj ¶ 0) or (¶ri rj ¶ 0 and ¶ci cj ¶ 1).
10 points: k & 1000; for each pair of distinct special cells i and j, it holds that if ¶ri rj ¶ & 2
and ¶ci cj ¶ & 2 then ¶ri rj ¶ & 1 and ¶ci cj ¶ & 1.
10 points: k & 1000; all special cells lie in the same row.
15 points: k & 10.
20 points: k & 1000.
30 points: no additional constraints.
Example 1
Input
5 6
7 3 8 1 0 9
4 6 2 5 8 3
1 9 7 3 9 5
2 6 8 4 5 7
3 8 2 7 3 6
CAPITOLUL 9. EJOI 2019 9.3. T - COVERING 208
31
1
2 2
3 4
Output
67
Comment
To achieve the maximum sum, Nika may place the tetrominoes as follows:
5 6
7 3 8 1 0 9
4 6 2 5 8 3
1 9 7 3 9 5
2 6 8 4 5 7
3 8 2 7 3 6
31
1
2 2
3 3
Output
No
Let’s look on some small examples first. If we have one special cell, and we can rotate the tetramino
in all 4 directions. Then the answer is sum all neighbouring cells except the cell with minimal
value.
If two special cells share a side, then there is unique way to rotate the tetraminos. If two special
cells share a corner, then there are two ways to rotate the tetraminos, but the set of covered cells
is the same.
If two special cells are 1 cell away from each other, then we have 7 neighbour cells, and we need
to cover 6 of them. It’s easy to see that we can cover any 6 of them, so if we need to maximize
sum, we need to cover all except the minimal one.
Now let’s look on the full task. Let’s build a graph. The vertices are the special cells, and
two special cells are connected if they share side, or corner, or if they are 1 cell away. Let’s find
connected components in this graph. If connected component contains k special cells, then there
are no more than 4n n 1 3n 1 neighbour cells, that can be covered by the tetraminos,
and we need to cover 3n of them. So ow we have three cases:
1. If this number is less than 3n than it is obviously impossible to put all tetraminos.
CAPITOLUL 9. EJOI 2019 9.3. T - COVERING 209
2. If this number is 3n than it can be shown that it is always possible to place all tetraminos.
So we can just add their sum to the answer.
3. If this number is 3n + 1 than it can be shown that for each neighbour cell it is always
possible to place all tetraminos in such a way that all cells except selected one are covered.
So we can just add the sum of all elements except the minimal one to the answer.
#include <bits/stdc++.h>
int i, j, k, m, n;
int a[N];
void nosol()
{
cout << "No" << endl;
exit(0);
}
F0(k, 4)
{
int x2 = x + 2 * DX[k], y2 = y + 2 * DY[k];
if (Empty(x2, y2) && b[x2*n + y2])
{
Fill(x2, y2);
v.push_back(pii(x2, y2));
DFS(x2, y2);
}
}
}
int main()
{
std::freopen("../covering-tests/input.test_07_05", "r", stdin);// 100520160
//std::freopen("covering.out", "w", stdout);
cin >> k;
while (k--)
{
scanf("%d%d", &i, &j);
b[i*n+j] = 1;
}
// find pairs
F0(i, m) F0(j, n)
if (b[i*n + j])
{
for (int dx = -1; dx <= 1; dx++)
{
for (int dy = -1; dy <= 1; dy++)
if (dx || dy)
{
int i2 = i + dx, j2 = j + dy;
if (i2 < 0 || i2 >= m || j2 < 0 || j2 >= n || !b[i2*n + j2])
continue;
if (d[i*n + j] && d[i2*n + j2]) continue;
if (d[i*n + j] || d[i2*n + j2]) nosol();
d[i*n + j] = 1;
d[i2*n + j2] = 1;
F0(k, 5)
if (!Empty(i + DX[k], j + DY[k]))
nosol();
F0(k, 5)
if (!Empty(i2 + DX[k], j2 + DY[k]))
nosol();
F0(k, 5)
if (Empty(i + DX[k], j + DY[k]))
Fill(i + DX[k], j + DY[k]);
F0(k, 5)
if (Empty(i2 + DX[k], j2 + DY[k]))
Fill(i2 + DX[k], j2 + DY[k]);
CAPITOLUL 9. EJOI 2019 9.3. T - COVERING 211
}
}
}
F0(k, 4)
{
int good = 1;
F0(dir, 4) if (dir != k)
{
if (!Empty(i + DX[dir], j + DY[dir]))
{
good = 0;
break;
}
}
found = 1;
break;
}
if (!found) nosol();
}
F0(i, m)
F0(j, n)
if (b[i*n + j] && Empty(i, j))
{
clbest = -1;
cnt = 0;
v.clear();
v.push_back(pii(i, j));
Fill(i, j);
DFS(i, j);
//PR(cnt);
// PR(SZ(v));
return 0;
}
#include <bits/stdc++.h>
void dfs(int v)
{
used[v] = true;
CAPITOLUL 9. EJOI 2019 9.3. T - COVERING 212
if (spec[v])
++ cnt;
else
values.push_back(val[v]);
int32_t main ()
{
std::freopen("../covering-tests/input.test_07_05", "r", stdin); // 100520160
//std::freopen("covering.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int temp = 1;
for (int i = 0; i < m; ++ i)
for (int j = 0; j < n; ++ j)
{
int a;
cin >> a;
val[temp ++] = a;
}
cin >> k;
int t = (x-1)*n + y,
t1 = (x-2)*n + y,
t2 = (x-1)*n + y - 1,
t3 = x*n + y,
t4 = (x-1)*n + y + 1;
ans += val[t];
spec[t] = true;
if (x > 1)
{
g[t].push_back(t1);
g[t1].push_back(t);
}
if (y > 1)
{
g[t].push_back(t2);
g[t2].push_back(t);
}
if (x < m)
{
g[t].push_back(t3);
g[t3].push_back(t);
}
if (y < n)
{
g[t].push_back(t4);
g[t4].push_back(t);
}
}
temp = 1;
for (int i = 0; i < m; ++ i)
for (int j = 0; j < n; ++ j)
{
if (!used[temp])
{
values.clear();
cnt = 0;
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 213
dfs(temp);
sort(values.rbegin(), values.rend());
++ temp;
}
return 0;
}
9.4 Adventure
Problema 4 - Awesome Arrowland Adventure 100 de puncte
European Junior Olympiad in Informatics 2542 is held in Arrowland. Arrowland is shaped
like a grid with m rows (numbered 0 through m 1) and n columns (numbered 0 through n 1),
where each cell represents a city. Let r, c denote the cell in row r and column c. The contestants
are accommodated in the cell 0, 0, and the competition hall is in the cell m 1, n 1.
A strange tourist attraction of Arrowland is that some cities have giant arrows. Even stranger,
these arrows can only be rotated clockwise by 90 degrees at a time. Each arrow initially points
to either North, East, South, or West. Because of the host country’s name, the EJOI organizers
want to make use of the arrows.
The contestants will blindly follow the arrows, regardless of their current position. From each
city, they simply move to the adjacent city pointed to by the arrow. If they enter a city with no
arrow or if they leave Arrowland, they will just stay there and will never reach the competition
hall. Since the EJOI organizers want the contestants to arrive to the hall from their accomodation
(cell 0, 0), they might have to rotate some arrows. Help them determine the minimum number
of rotations required to achieve their goal, or tell them that the contestants cannot reach the hall,
regardless of the arrows’ orientation.
Input
The first line contains two integers, m and n, denoting the number of rows and columns,
respectively. The next m lines each contain n characters denoting the initial direction of the
arrows (N - north, E - east, S - south, W - west, X - no arrow in this cell). The last character
in the last row (i.e., the character corresponding to the competition hall) is guaranteed to be X.
In the input matrix, the directions North, East, South, and West have the same meaning as
they do on a standard map. Therefore, the character N means ”upwards”, E means ”to the
right”, S means ”downwards”, and W means ”to the left”.
Output
Output the minimum number of rotations that EJOI organizers have to perform. Output 1
if their task is impossible.
Constraints
Subtasks
Example 1
Input
3 3
EES
SSW
ESX
Output
Comment
In this case, one possible optimal solution is to change W in the cell 1, 2 to S by rotating
the arrow three times.
Example 2
Input
3 3
EES
SSW
EEX
Output
Comment
Here, the EJOI organizers don’t have to change anything for the contestants to arrive to the
competition hall.
Example 3
Input
3 4
EXES
WSNS
XNNX
Output
Comment
Rotate the arrow in the cell 0, 0 once (to obtain S), the arrow in the cell 1, 0 twice (to
obtain E), and the arrow in the cell 2, 1 once (to obtain E).
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 215
Let’s change the task in the following way. Imagine that students go from cell 0; 0 to cell
m 1; n 1, and they rotate the arrows to match the direction of their movement. It’s easy to
see that in the optimal path they should not visit the same cell more than once, so we can build
the following directed graph: vertices of the graph are the cells, and we add edge from vertex v to
vertex u of weight w, if after w rotations, the arrow in cell v is directed to cell u.
Now we can simply find the shortest path in this graph. We can use Dijkstra algorithm with
priority queue, or even breath-first search, because all weights are small integers.
Time complexity will be O mn log mn or O mn.
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <cassert>
#include <string>
#include <cstring>
#include <bitset>
#include <random>
#include <chrono>
/*
const int dr[] = {+1, -1, +0, +0, +1, -1, +1, -1};
const int dc[] = {+0, +0, +1, -1, +1, -1, -1, +1};
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 216
*/
const int ms[] = {+31, +29, +31, 30, +31, +30, +31, +31, +30, +31, +30, +31};
int main ()
{
std::freopen("../adventure-tests/input.test_04_03", "r", stdin);// 260
//std::freopen("adventure.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
int r, c;
cin >> r >> c;
if (r == 1 && c == 1)
{
cout << 0 << ’\n’;
return 0;
}
dist[0][0] = 0;
while (!pq.empty())
{
int cost = pq.top().f;
int linha = pq.top().s.f;
int coluna = pq.top().s.s;
pq.pop();
if (cost > dist[linha][coluna]) continue;
int cur = Get (g[linha][coluna]);
if (cur == -1) continue;
F0R (i, 4)
{
if (linha + dr[i] < 0 || coluna + dc[i] < 0 ||
linha + dr[i] >= r || coluna + dc[i] >= c) continue;
int w = 0;
while ((cur + w) % 4 != i) ++w;
cout << (dist[r - 1][c - 1] > 1e8 ? -1 : dist[r - 1][c - 1]) << ’\n’;
return 0;
}
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 217
ll n,m;
char c[505][505];
vector<pair<pair<ll,ll>,ll>>v[505][505];
ll viz[505][505];
char directii[]={’N’,’E’,’S’,’W’,’N’,’E’,’S’,’W’};
ll pos=0;
while(directii[pos]!=c[i][j]) ++pos;
ll cnt=-1;
for(ll t=1;t<=4;t++)
{
++cnt;
if(directii[pos]==’E’||directii[pos]==’W’)
{
if(directii[pos]==’E’&&j<m)
{
v[i][j].pb({{i,j+1},cnt});
}
else
if(directii[pos]==’W’&&j>1)
{
v[i][j].pb({{i,j-1},cnt});
}
}
else
{
if(directii[pos]==’N’&&i>1)
{
v[i][j].pb({{i-1,j},cnt});
}
else
if(directii[pos]==’S’&&i<n)
{
v[i][j].pb({{i+1,j},cnt});
}
}
pos++;
}
}
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 218
ll sol()
{
ll x=1,y=1;
viz[1][1]=1;
priority_queue<pair<int,pair<int,int>>,
vector<pair<int,pair<int,int>>>,
greater<pair<int,pair<int,int>>>> q;
for(auto it:v[1][1])
{
q.push({it.s,{it.f.f,it.f.s}});
}
while(q.size()&&(q.top().s.f!=n || q.top().s.s!=m))
{
auto it=q.top();
ll x=it.s.f;
ll y=it.s.s;
if(viz[x][y]==1)
{
q.pop();
continue;
}
q.pop();
ll val=it.f;
for(auto it1:v[x][y])
{
if(viz[it1.f.f][it1.f.s]==0)
{
q.push({val+it1.s,{it1.f.f,it1.f.s}});
}
}
viz[x][y]=1;
}
if(q.empty()==true)
{
return -1;
}
return q.top().f;
}
int32_t main()
{
std::freopen("../adventure-tests/input.test_04_03", "r", stdin);// 260
//std::freopen("adventure.out", "w", stdout);
CODE_START;
cin>>n>>m;
for(ll i=1;i<=n;i++)
for(ll j=1;j<=m;j++)
{
cin>>c[i][j];
edge(i,j);
}
cout<<sol();
}
#include <bits/stdc++.h>
#define F first
#define S second
#define PI (2LL*acos(0))
vll visit,taken;
ll dist[500 * 500 + 5];
vector<vll> adj;
vii adj2LL[500 * 500 + 5];
void dijkstra(ll s)
{
pq.push(ii(0,s));
dist[s] = 0;
while(!pq.empty())
{
ii f = pq.top();
pq.pop();
ll w = f.F;
ll u = f.S;
if(w > dist[u]) {continue;}
for(auto v:adj2LL[u])
{
if(dist[u] + v.S < dist[v.F])
{
dist[v.F] = dist[u] + v.S;
pq.push(ii(dist[v.F],v.F));
}
}
}
}
int main(void)
{
std::freopen("../adventure-tests/input.test_04_03", "r", stdin);// 260
//std::freopen("adventure.out", "w", stdout);
fastio;
ll n,m;
c(n);
c(m);
char arr[n][m];
f(i,0,n)
{
f(j,0,m)
{
c(arr[i][j]);
}
}
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 220
swap(n,m);
f(i,0,m)
{
f(j,0,n)
{
if(arr[i][j] == ’N’)
{
if(i-1 >= 0)
adj2LL[j*m+i].pb(ii(j*m+i-1,0));
if(j-1 >= 0)
adj2LL[j*m+i].pb(ii((j-1) *m + i,3));
}
else
if(arr[i][j] == ’E’)
{
if(i-1 >= 0)
adj2LL[j*m+i].pb(ii(j*m+i-1,3));
if(j-1 >= 0)
adj2LL[j*m+i].pb(ii((j-1) *m + i,2));
}
else
if(arr[i][j] == ’S’)
{
if(i-1 >= 0)
adj2LL[j*m+i].pb(ii(j*m+i-1,2));
if(j-1 >= 0)
adj2LL[j*m+i].pb(ii((j-1) *m + i,1));
}
else
if(arr[i][j] == ’W’)
{
if(i-1 >= 0)
adj2LL[j*m+i].pb(ii(j*m+i-1,1));
if(j-1 >= 0)
adj2LL[j*m+i].pb(ii((j-1) *m + i,0));
}
}
}
f(i,0,n*m+5)
{
dist[i] = INF;
}
dijkstra(0);
ll i = m-1;
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 221
ll j = n-1;
if(dist[j*m + i] >= INF)
{
pl(-1);
return 0;
}
pl(dist[j*m + i]);
}
#include <bits/stdc++.h>
int ind[MAXN][MAXN],dist[MAXN][MAXN],dx[4]={0,1,0,-1},dy[4]={-1,0,1,0},n,m;
void dijkstra()
{
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
dist[i][j]=-1;
priority_queue<pair<int,pair<int,int>>,
vector<pair<int,pair<int,int>> >,
greater<pair<int,pair<int,int> > > > pq;
pq.push(make_pair(0,make_pair(0,0)));
while(!pq.empty())
{
int x=pq.top().second.first,
y=pq.top().second.second,
c=pq.top().first;
pq.pop();
if(x<0 || x>=m || y<0 || y>=n || dist[y][x]!=-1) continue;
dist[y][x]=c;
if(ind[y][x]==-1) continue;
for(int i=0;i<4;i++)
pq.push(make_pair(c+i,
make_pair(x+dx[(ind[y][x]+i)%4],
y+dy[(ind[y][x]+i)%4])));
}
}
int main()
{
std::freopen("../adventure-tests/input.test_04_03", "r", stdin);// 260
//std::freopen("adventure.out", "w", stdout);
cin>>n>>m;
for(int i=0;i<n;i++) for(int j=0;j<m;j++)
{
char c; cin>>c;
if(c==’N’) ind[i][j]=0;
if(c==’E’) ind[i][j]=1;
if(c==’S’) ind[i][j]=2;
if(c==’W’) ind[i][j]=3;
if(c==’X’) ind[i][j]=-1;
}
dijkstra();
cout<<dist[n-1][m-1];
}
\index{dijkstra!priority\_queue}
\index{priority\_queue!top()}
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 222
\index{priority\_queue!pop()}
\index{priority\_queue!make\_pair}
#include <bits/stdc++.h>
int i, j, k, m, n;
int a[N];
string s[N];
int DX[]={-1,0,1,0};
int DY[]={0,1,0,-1};
int d[N][N];
string H="NESW";
int main()
{
std::freopen("../adventure-tests/input.test_04_03", "r", stdin);// 260
//std::freopen("adventure.out", "w", stdout);
set<pair<int, pii>> S;
CL(-1, d);
d[0][0] = 0;
S.insert(make_pair(0, pii(0, 0)));
while (!S.empty())
{
pii p = S.begin()->second;
S.erase(S.begin());
F0(k, 4)
{
int x = p.first + DX[k],
y = p.second + DY[k];
int d0 = H.find(s[p.first][p.second]);
int cost = (k - d0 + 4) % 4 + d[p.first][p.second];
return 0;
}
#include <bits/stdc++.h>
priority_queue<pair<int,int> ,
vector<pair<int,int> >,
greater<pair<int,int> > > q;
int d[250000];
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n>>m;
int i,j;
char c;
for(i=0;i<n*m;i++)
d[i]=1000000;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
cin>>c;
if(c==’X’)
continue;
if(c==’N’)
{
if(i-1>=0)
a[i*m+j].push_back(mp(0,(i-1)*m+j));
if(j+1<m)
a[i*m+j].push_back(mp(1,i*m+j+1));
if(i+1<n)
a[i*m+j].push_back(mp(2,(i+1)*m+j));
if(j-1>=0)
a[i*m+j].push_back(mp(3,i*m+j-1));
}
else
if(c==’E’)
{
if(i-1>=0)
a[i*m+j].push_back(mp(3,(i-1)*m+j));
if(j+1<m)
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 224
a[i*m+j].push_back(mp(0,i*m+j+1));
if(i+1<n)
a[i*m+j].push_back(mp(1,(i+1)*m+j));
if(j-1>=0)
a[i*m+j].push_back(mp(2,i*m+j-1));
}
else
if(c==’S’)
{
if(i-1>=0)
a[i*m+j].push_back(mp(2,(i-1)*m+j));
if(j+1<m)
a[i*m+j].push_back(mp(3,i*m+j+1));
if(i+1<n)
a[i*m+j].push_back(mp(0,(i+1)*m+j));
if(j-1>=0)
a[i*m+j].push_back(mp(1,i*m+j-1));
}
else
{
if(i-1>=0)
a[i*m+j].push_back(mp(1,(i-1)*m+j));
if(j+1<m)
a[i*m+j].push_back(mp(2,i*m+j+1));
if(i+1<n)
a[i*m+j].push_back(mp(3,(i+1)*m+j));
if(j-1>=0)
a[i*m+j].push_back(mp(0,i*m+j-1));
}
}
q.push({0,0});
d[0]=0;
int start,w;
while(!q.empty())
{
start=q.top().second;
w=q.top().first;
q.pop();
if(d[start]<w)
continue;
for(auto x : a[start])
if(d[x.second]>d[start]+x.first)
{
d[x.second]=d[start]+x.first;
q.push(mp(d[x.second],x.second));
}
}
if(d[n*m-1]==1000000)
cout<<-1<<’\n’;
else
cout<<d[n*m-1]<<’\n’;
}
#include <bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define int long long
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 225
#define pb push_back
#define fio() ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define FOR for(int i=1;i<=n;i++)
#define mid ((start+end)/2)
#define ort ((bas+son)/2)
int n,m,b[li],a[li],k,flag,t,vis[505][505],d[505][505];
int cev;
string s[li];
vector<int> v;
pq.pop();
//˜ if(s[satir][sutun]==’X’)continue ;
vis[satir][sutun]=1;
if(s[satir][sutun]==’N’)
{
pq.push(mp(-para,mp(satir-1,sutun)));
pq.push(mp(-(para+1),mp(satir,sutun+1)));
pq.push(mp(-(para+2),mp(satir+1,sutun)));
pq.push(mp(-(para+3),mp(satir,sutun-1)));
}
if(s[satir][sutun]==’E’)
{
pq.push(mp(-para,mp(satir,sutun+1)));
pq.push(mp(-(para+1),mp(satir+1,sutun)));
pq.push(mp(-(para+3),mp(satir-1,sutun)));
pq.push(mp(-(para+2),mp(satir,sutun-1)));
}
if(s[satir][sutun]==’S’)
{
pq.push(mp(-para,mp(satir+1,sutun)));
pq.push(mp(-(para+3),mp(satir,sutun+1)));
pq.push(mp(-(para+2),mp(satir-1,sutun)));
pq.push(mp(-(para+1),mp(satir,sutun-1)));
}
if(s[satir][sutun]==’W’)
{
pq.push(mp(-para,mp(satir,sutun-1)));
pq.push(mp(-(para+2),mp(satir,sutun+1)));
pq.push(mp(-(para+3),mp(satir+1,sutun)));
pq.push(mp(-(para+1),mp(satir-1,sutun)));
}
}
}
main(void)
{
std::freopen("../adventure-tests/input.test_04_03", "r", stdin);// 260
//std::freopen("adventure.out", "w", stdout);
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 226
memset(d,-1,sizeof(d));
scanf("%lld %lld",&n,&m);
FOR
{
cin>>s[i];
}
sp();
printf("%lld\n",d[n][m-1]);
return 0;
}
#include<bits/stdc++.h>
int n, m;
char a[N][N];
vector<pair<pair<int, int>, int>> g[N][N];
int dist[N][N];
int main()
{
std::freopen("../adventure-tests/input.test_04_03", "r", stdin);// 260
//std::freopen("adventure.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);
dist[i][j] = INF;
}
}
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 227
dist[0][0] = 0;
while(!st.empty())
{
auto v = st.begin()->second;
st.erase(st.begin());
for(auto to : g[v.first][v.second])
{
int dst = dist[v.first][v.second] + to.second;
if(dst < dist[to.first.first][to.first.second])
{
st.erase({dist[to.first.first][to.first.second], to.first});
dist[to.first.first][to.first.second] = dst;
st.insert({dist[to.first.first][to.first.second], to.first});
}
}
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <cmath>
int n, m;
class Min_Heap
{
private:
pair <int, int> h[5 + N * N];
int sz;
pos = parent;
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 228
pos = child;
child = pos << 1;
public:
void Clear()
{
sz = 0;
}
void Pop()
{
swap(h[1], h[sz]);
sz--;
Sift_Down(1);
}
int Size()
{
return sz;
}
};
Min_Heap heap;
dp[nodStart] = 0;
heap.Push(make_pair(nodStart, 0));
while(heap.Size())
{
pair <int, int> top = heap.Top();
heap.Pop();
if(viz[top.first] == false)
{
viz[top.first] = true;
for(auto to : g[top.first])
{
if(dp[to.first] > to.second + dp[top.first])
CAPITOLUL 9. EJOI 2019 9.4. ADVENTURE 229
{
dp[to.first] = to.second + dp[top.first];
heap.Push(make_pair(to.first, dp[to.first]));
}
}
}
}
}
int main()
{
std::freopen("../adventure-tests/input.test_04_03", "r", stdin);// 260
//std::freopen("adventure.out", "w", stdout);
if(s[j] == ’N’)
{
if(i > 1) g[idx].push_back(make_pair(idxn, 0));
if(j < m - 1) g[idx].push_back(make_pair(idxe, 1));
if(i < n) g[idx].push_back(make_pair(idxs, 2));
if(j > 0) g[idx].push_back(make_pair(idxw, 3));
}
else
if(s[j] == ’E’)
{
if(i > 1) g[idx].push_back(make_pair(idxn, 3));
if(j < m - 1) g[idx].push_back(make_pair(idxe, 0));
if(i < n) g[idx].push_back(make_pair(idxs, 1));
if(j > 0) g[idx].push_back(make_pair(idxw, 2));
}
else
if(s[j] == ’S’)
{
if(i > 1) g[idx].push_back(make_pair(idxn, 2));
if(j < m - 1) g[idx].push_back(make_pair(idxe, 3));
if(i < n) g[idx].push_back(make_pair(idxs, 0));
if(j > 0) g[idx].push_back(make_pair(idxw, 1));
}
else
if(s[j] == ’W’)
{
if(i > 1) g[idx].push_back(make_pair(idxn, 1));
if(j < m - 1) g[idx].push_back(make_pair(idxe, 2));
if(i < n) g[idx].push_back(make_pair(idxs, 3));
if(j > 0) g[idx].push_back(make_pair(idxw, 0));
}
}
}
Dijkstra(1);
if(dp[n * m] == INF)
cout << -1 << ’\n’;
else
cout << dp[n * m] << ’\n’;
return 0;
}
CAPITOLUL 9. EJOI 2019 9.5. TOWER 230
9.5 Tower
Problema 5 - Tower 100 de puncte
Farmhand Jernej gets bored in the evenings, thus he invented a simple game. He wants to
build a tower from numbers on pieces of paper. He starts with a piece of paper and writes 1 on it.
Jernej can write another number on a piece of paper and place it on top of the tower. The new
value on the top of the tower must be a valid sum of numbers on consecutive papers comprising
the tower.
Let’s say there are currently n pieces of paper comprising the tower. He makes a sum of
numbers in the tower within arbitrary positions l, u, where 1 & l & u & n and puts the sum on
top.
Jernej wants to produce towers with desired numbers on top. Help him find out the required
steps. He also asks you to minimize the number of those steps.
Input
In the first line of input, you will be given a positive integer T (number of different towers
Jernej wants to produce).
In each of the next T lines, there will be one positive integer q, the value Jernej wants to
produce at the end. All games are independent.
Output
For each integer q:
print one line with number s (0 & s & 1000) - required steps to produce the desired value.
In the next lines, there should be 2 space-separated positive integers l and u, range bounds
to produce the desired value.
Constraints
1&T & 1000
1&q & 1018
Subtasks
Grading
There will be 10 test cases with T towers. For each test case, points will be calculated using
the following rules:
If the solution produces the desired value with minimal number of steps for all towers, you
get 10 points for the test case,
CAPITOLUL 9. EJOI 2019 9.5. TOWER 231
otherwise, your solution will be scored as the minimum of the score of all towers, where
towers are scored as 1 minimum steps
solution steps
7 rounded up to 2 decimal places.
If the solution for one of the towers is invalid, the solution gets 0 points.
3
2
3
7
Output
2
1 1
1 2
3
1 1
2 2
1 3
4
1 1
1 2
2 3
1 4
Explanation
In this example T 3.
Jernej wants to find out the required steps to get r2, 3, 7x. The current tower contains only
one piece of paper with number 1.
The first desired value is 2.
In the first step, he can only make a sum of numbers from the range 1, 1, so the number on
the next piece of paper can be only 1.
st
If Jernej wants to produce number 2, he should make a sum on the range 1, 2 (pick the 1
nd
and 2 number). This will sum into 2, which is the desired result.
The second desired value is 3. To produce 3, there are multiple ways. We can also produce 3
the following way:
1 1
1 2
2 3
First, let’s try to build maximal possible number on each step. We will have tower like this: 1,
i1
1, 2, 4, 8, 16, ... . On step i the maximal number we can produce is 2 . So it’s obvious that
number x cannot be produced in less than *log2 0 1 operations. We will show later that this
lower bound is actually achievable. But first let’s discuss partial solution that make about twice
more operations.
Let’s split given number x into sum of powers of two. Now, first spend about log2 n operations
to make all required powers of two, then spend another log2 n operations to copy the required
CAPITOLUL 9. EJOI 2019 9.6. COLOURING 232
powers of two to the end of the list, and finally make operation that calculates sum of these powers
of two.
Now let’s discuss the optimal solution. First, let’s build the following sequence
1, 1, 2, 4, 8, 16, ..., 2 , where 2 is the smallest power of two such that 2 ' x.
k k k
Now let’s try to modify this sequence. We can decrease any element of the sequence by one
by shifting the left border of the segment from 1 to 2.
If we decrease i-th element by 1, then i 1-th element will be decreased by 1, i 2-th by 2,
ki1
i 3-th by 4, and so on. So the k-th element will be decreased by 2 .
k
Now let’s split the difference d 2 x into the sum of powers of two, and decrease the
corresponding elements of the sequence to make the last elements equal to x.
For example, if x 10, then first we make sequence 1, 1, 2, 4, 8, 16. Now we need to decrease
the last number by 6 = 4+2. First, let’s decrease it by 4. This can be done by decreasing the
second number from 2 to 1: 1, 1, 1, 3, 6, 12. Now we need to decrease it by 2. This can be done
by decreasing the third number from 3 to 2: 1, 1, 1, 2, 5, 10
This solution uses exactly *log2 n0 1 operations and it’s time complexity is O log n.
***
9.6 Colouring
Problema 6 - Colouring a rectangle 100 de puncte
Srečko would like to paint a rectangular grid having m rows (numbered from 0 to m 1) and
n columns (numbered from 0 to n 1). Initially, all cells in the grid are white. In each step, he
chooses a diagonal and paints all of its cells using his favourite colour. However, some diagonals
may be more expensive to paint than others, regardless of their length. Given the cost of painting
each of the diagonals, write a program to tell Sreko the minimum total cost of painting all cells
in the grid.
Note that cells can be painted twice.
A rectangular grid with m rows and n columns has 2m 2n 2 diagonals. For instance, if
m 4 and n 3, there are 12 diagonals:
Input
The input consists of three lines.
The first line contains the numbers m and n.
The second line contains m n 1 numbers that specify the costs of painting the diagonals
running in the direction. The i-th number (for i " r1, ..., m n 1x) refers to the diagonal in
which the difference between the row index and the column index is i n. The first number thus
refers to the diagonal that consists only of the cell 0, n 1 (row 0, column n 1), the second
number refers to the diagonal comprising the cells 0, n 2 and 1, n 1, etc. The order of the
diagonals is thus the same as in the first row of the above figure.
CAPITOLUL 9. EJOI 2019 9.6. COLOURING 233
The third line contains m n 1 numbers that specify the costs of painting the diagonals
running in the direction. The i-th number (for i " r1, ..., m n 1x) refers to the diagonal in
which the sum of the row index and the column index is i 1. The first number thus refers to the
diagonal that consists only of the cell 0, 0, the second number refers to the diagonal comprising
the cells 1, 0 and 0, 1, etc. The order of the diagonals is thus the same as in the second row of
the above figure.
Output
Output the minimum cost of painting the grid.
Constraints
1 & m & 2 10
5
1 & n & 2 10
5
9
The costs are integers from the interval 1, 10 .
Subtasks
10 points: m, n & 4.
10 points: m, n & 10.
10 points: m, n & 20.
20 points: m, n & 2000.
1 and n & 2 10 .
5
10 points: m
n & 2 10 .
5
20 points: m
20 points: no additional constraints.
Example 1
Input
2 2
1 3 1
1 3 1
Output
Comment
In this case, the following diagonals have to be painted to minimize the total cost:
4 3
2 3 9 3 4 3
2 3 3 1 2 4
Output
14
CAPITOLUL 9. EJOI 2019 9.6. COLOURING 234
Comment
This time, the following diagonals cover the grid at the minimum total cost:
The costs of painting the selected diagonals are 3, 2, 3, 3, 1, and 2 (in this order).
Timp maxim de executare/test: 2.0 secunde
Memorie: total 100 MB
Let’s look on some diagonal of the first ( ) type. If we don’t paint this diagonal, we are forced to
paint all diagonals of the second ( ) type, that intersect our diagonal. Notice that these diagonals
always form a continuous segment in the list of diagonals.
Now the task can be modified in the following way. There are n m 1 elements ai (corre-
sponding to diagonals of the first type), and n m 1 elements bj (corresponding to diagonals of
the second type). For each i we need either to take element ai , or take all elements bj for all j in
li , ri (values li and ri can be precalculated based on n and m).
Find the minimal cost of taken elements.
This task can be solved by dynamic programming. First, let’s sort elements by li . Now let’s
say di, j is the minimal cost to satisfy elements a0..i 1 in such a way that elements bli ..j
are taken.
The transition is: either take the element ai, or all elements bj..ri .
2
This solution works in O n m time.
It can be improved to O n m log n m by using the segment tree.
#define pi pair
#define rc(s) return cout<<s,0
#define endl ’\n’
#define mod 1000000007
#define PI 3.14159265359
#define CODE_START ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
ll n,m,a[800005];
int32_t main()
{
std::freopen("../colouring-tests/input.70", "r", stdin);// 296294320991251
//std::freopen("colouring.out", "w", stdout);
CODE_START;
cin>>n>>m;
ll ans=0;
for(ll i=0;i<2*n+2*m-2;i++)
cin>>a[i];
for(ll i=0;i<n+m-1;i++)
{
ans=ans+min(a[i],a[2*n+2*m-2-i-1]);
}
cout<<ans<<endl;
}
#include <bits/stdc++.h>
vll visited,dist,taken;
vector<vll> adj;
vector<vii> adj2;
ll bit[N]={0};
ll siz;
ll res = 0;
ll power(ll a,ll b)
{
if(b == 0) return 1;
if(b == 1) return a;
ll ans = power(a,b/2) % MOD;
ans *= ans;
ans %= MOD;
if(b % 2 == 1)ans *= a;
return ans%MOD;
}
ll inverse(ll x)
{
x%=MOD;
return power(x,MOD-2);
}
void BITup(ll k, ll x)
{
while(k <= siz)
{
bit[k]+=x;
k += k & -k;
}
}
ll BITq(ll k)
{
ll s=0;
while(k>=1)
{
s+=bit[k];
k -= k &-k;
}
return s;
}
void dfs(ll v)
{
visited[v] = 1;
for(auto x:adj[v])
{
if(!visited[x])dfs(x);
}
}
void bfs(ll s)
{
visited[s] = 1;
queue<ll>q;
q.push(s);
while(!q.empty())
{
ll u = q.front();
ps(u);
q.pop();
for(auto x:adj[u])
{
if(!visited[x])
{
visited[x] = 1;
q.push(x);
}
}
}
CAPITOLUL 9. EJOI 2019 9.6. COLOURING 237
void dijkstra(ll s)
{
pq.push(ii(0,s));
dist[s] = 0;
while(!pq.empty())
{
ii f = pq.top();
pq.pop();
ll w = f.F;
ll u = f.S;
if(w > dist[u]) {continue;}
for(auto v:adj2[u])
{
if(dist[u] + v.S < dist[v.F])
{
dist[v.F] = dist[u] + v.S;
pq.push(ii(dist[v.F],v.F));
}
}
}
}
ll mst(ll s)
{
taken.assign(N, 0);
prim(s);
ll cost = 0;
while(!pq.empty())
{
ii front = pq.top();
pq.pop();
ll w = front.first;
ll u = front.second;
if(taken[u]==0) cost += w;
prim(u);
}
return cost;
}
int main(void)
{
std::freopen("../colouring-tests/input.70", "r", stdin);// 296294320991251
//std::freopen("colouring.out", "w", stdout);
fastio;
ll m,n;
c(m);
c(n);
ll siz = m+n-1;
ll arr1[siz],arr2[siz];
ll ans = 0;
arrin(arr1,siz);
arrin(arr2,siz);
f(i,0,siz)
CAPITOLUL 9. EJOI 2019 9.6. COLOURING 238
{
ans += min(arr1[i],arr2[siz-i-1]);
}
pl(ans);
}
Această variantă a obţinut numai 10 puncte dar are un mic avantaj: conţine câteva funcţii
care merită atenţia noastră!
#include <bits/stdc++.h>
int main()
{
std::freopen("../colouring-tests/input.70", "r", stdin);// 296294320991251
//std::freopen("colouring.out", "w", stdout);
int n, m;
cin >> n >> m;
Această sursă obţine 100 de puncte dar ... este o simplă ı̂nşiruire a rezultatelor date ı̂n fişierele
de test publicate după EJOI2019!
10.1 Hills
Problema 1 - Hills 100 de puncte
Welcome to Innopolis city. Throughout the whole year, Innopolis citizens suffer from everlast-
ing city construction.
From the window in your room, you see the sequence of n hills, where i-th of them has height
ai . The Innopolis administration wants to build some houses on the hills. However, for the sake of
city appearance, a house can be only built on the hill, which is strictly higher than neighbouring
hills (if they are present). For example, if the sequence of heights is 5, 4, 6, 2, then houses could
be built on hills with heights 5 and 6 only.
The Innopolis administration has an excavator, that can decrease the height of an arbitrary hill
by one in one hour. The excavator can only work on one hill at a time. It is allowed to decrease hills
up to zero height, or even to negative values. Increasing height of any hill is impossible. The city
administration wants to build k houses, so there must be at least k hills that satisfy the condition
above. What is the minimum time required to adjust the hills to achieve the administration’s
plan?
However, the exact value of k is not yet determined, so could you please calculate answers for
all k in range 1 & k & * n2 0? Here * n2 0 denotes n divided by two, rounded up.
Input
The first line of input contains the only integer n (1 & n & 5000)—the number of the hills in
the sequence.
Second line contains n integers ai (1 & ai & 100 000)—the heights of the hills in the sequence.
Output
Print exactly * n2 0 numbers separated by spaces. The i-th printed number should be equal to
the minimum number of hours required to level hills so it becomes possible to build i houses.
Constraints
***
Subtasks
241
CAPITOLUL 10. EJOI 2018 10.1. HILLS 242
Examples
standard input standard output
5 122
11111
3 02
123
5 013
12322
Comment/Note
In the first example, to get at least one hill suitable for construction, one can decrease the
second hill by one in one hour, then the sequence of heights becomes 1, 0, 1, 1, 1 and the first hill
becomes suitable for construction.
In the first example, to get at least two or at least three suitable hills, one can decrease the
second and the fourth hills, then the sequence of heights becomes 1, 0, 1, 0, 1, and hills 1, 3, 5
become suitable for construction.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 512 MB
https://codeforces.com/blog/entry/60920
https://codeforces.com/topic/61265/en10
The problem’s short statement is: ”we allowed to decrease any element and should create at
least k local maximums, count the minimum number of operations for all k”.
Notice, that any set of positions, where no positions are adjacent could be made to be local
maximums - we just need to decrease the neighbouring hills to some value.
Let’s introduce the following dynamic programming:
dp[prefix][local maxs] - the minimum cost if we analyze only given prefix, have the specified
number of local maximums (”good hills to build on”) and we make a local maximum in the last
hill of this prefix.
2 4
The dumb implementation of this leads to O n states and O n time - in each state we can
brute force the previous position of local maximum (n) and then calculate the cost of patching
the segment from previous local maximum to current one.
3
A more attentive look says that it is, in fact O n solution - on the segment only first and
last elements need to be decreased (possibly first and last elements are same).
2
To get the full solution in O n we need to optimize dp a little bit. As we noticed in the
previous paragraph, there is one extreme situation, when the first and elements are same, let’s
handle this transition by hand in O 1 for each state.
Otherwise, funny fact, the cost of the segment strictly between local maximums is the cost of
it’s left part plus it’cost of it’s right part. Seems like something we can decompose, right?
Since our goal is to update state pref ix, local now the right part is fixed constant for all
such transitions. And we need to select minimum value of
dpilocal 1 cost i, i 1 where i & pref ix 3.
This can be done by calculating a supplementary dp during the primarily dp calculation - for
example we can calculate
f pref j mindpij cost i, i 1 for i & pref .
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::cerr;
using std::vector;
using std::map;
using std::array;
using std::set;
using std::string;
using std::pair;
using std::make_pair;
using std::min;
using std::abs;
using std::max;
using std::unique;
using std::sort;
using std::generate;
using std::reverse;
using std::min_element;
using std::max_element;
#ifdef LOCAL
#define LASSERT(X) assert(X)
#else
#define LASSERT(X) {}
#endif
#define pb push_back
#define eb emplace_back
int main()
{
std::freopen("../tests/76", "r", stdin);// ...
std::freopen("hills.out", "w", stdout);
std::iostream::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
// code here.
int n = input<int>();
CAPITOLUL 10. EJOI 2018 10.1. HILLS 244
vector<int> a(n);
input_seq(ALL(a));
dp[0][0][0][0] = 0;
auto go = [&](int a, int b, int c, int d, int f)
{
dp[a][b][c][d] = min(dp[a][b][c][d], f);
};
return 0;
}
#include <bits/stdc++.h>
CAPITOLUL 10. EJOI 2018 10.1. HILLS 245
using std::cin;
using std::cout;
using std::cerr;
using std::vector;
using std::map;
using std::array;
using std::set;
using std::string;
using std::pair;
using std::make_pair;
using std::min;
using std::abs;
using std::max;
using std::unique;
using std::sort;
using std::generate;
using std::reverse;
using std::min_element;
using std::max_element;
#ifdef LOCAL
#define LASSERT(X) assert(X)
#else
#define LASSERT(X) {}
#endif
#define pb push_back
#define eb emplace_back
// (prefix, local)
int dp[max_n][max_n];
int f[max_n][max_n];
int main()
{
std::freopen("../tests/76", "r", stdin);// ...
std::freopen("hills.out", "w", stdout);
std::iostream::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
// code here.
int n = input<int>();
vector<int> a(n);
input_seq(ALL(a));
CAPITOLUL 10. EJOI 2018 10.1. HILLS 246
if (dp[i][j] != TYPEMAX(int))
f[i][j]=min(f[i][j],dp[i][j]+max(0, get(i+1)-(get(i)-1)));
}
}
int cost = 0;
if (i != n - 1)
cost = max(0, get(i + 1) - (get(i) - 1));
return 0;
}
int main()
{
std::freopen("../tests/76", "r", stdin);// ...
std::freopen("hills.out", "w", stdout);
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
int m = (n + 1) / 2;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
for (int i = 0; i <= n + 1; i++)
{
for (int j = 0; j <= m + 1; j++)
{
for (int k = 0; k < 3; k++)
{
dp[i][j][k] = INF;
}
}
}
dp[0][0][2] = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j <= m; j++)
{
for (int k = 0; k < 3; k++)
{
if (dp[i][j][k] == INF) continue;
int val = a[i];
if (k == 1)
{
val = min(val, a[i - 1] - 1);
}
{
// i + 1 is not a local maximum
int gok = min(k + 1, 2);
if (k != 0)
{
dp[i+1][j][gok] = min(dp[i+1][j][gok], dp[i][j][k]);
}
else
{
dp[i+1][j][gok] = min(dp[i+1][j][gok],
dp[i][j][k] + cost(a[i],
a[i + 1]));
}
}
{
// i + 1 is a local maximum
if (k != 0)
{
dp[i+1][j+1][0] = min(dp[i+1][j+1][0],
dp[i][j][k] + cost(a[i+1],
val));
}
}
}
}
}
CAPITOLUL 10. EJOI 2018 10.1. HILLS 248
mt19937 rnd(228);
int dp[N][N][2][2];
int arr[N];
int n;
int main()
{
std::freopen("../tests/76", "r", stdin);// ...
std::freopen("hills.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> arr[i];
CAPITOLUL 10. EJOI 2018 10.1. HILLS 249
}
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= n; j++)
{
for (int a = 0; a < 2; a++)
{
for (int b = 0; b < 2; b++)
{
dp[i][j][a][b] = 1e9;
}
}
}
}
dp[0][0][0][0] = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
for (int a = 0; a < 2; a++)
{
for (int b = 0; b < 2; b++)
{
dp[i+1][j][b][0] = min(dp[i+1][j][b][0], dp[i][j][a][b]);
if (!b)
{
int cst = cost(i, i - 1) + cost(i, i + 1);
if (!a)
{
dp[i+1][j+1][b][1] = min(dp[i+1][j+1][b][1],
dp[i][j][a][b]+cst);
}
else
{
dp[i+1][j+1][b][1] = min(dp[i+1][j+1][b][1],
dp[i][j][a][b]+cst-min(cost(i,i-1),
cost(i-2,i-1)));
}
}
}
}
}
}
int n, a[M], k;
int dp[two][N][M];
int main()
{
std::freopen("../tests/76", "r", stdin);// ...
std::freopen("hills.out", "w", stdout);
ios::sync_with_stdio(0);
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
k = (n + 1) / 2;
for (int i = 0; i <= k; i++)
for (int j = 0; j <= n; j++)
dp[0][i][j] = BIG, dp[1][i][j] = BIG;
dp[0][0][0] = 0;
for (int i = 1; i <= n; i++)
for (int x = 0; x <= (i + 1) / 2; x++)
{
if (i == 1)
{
dp[0][x][i] = 0;
dp[1][x][i] = 0;
if (x == 1) dp[0][1][1] = BIG;
continue;
}
void test_case()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &h[i]);
dp[0][0][0] = 0;
dp[1][0][0] = 0;
dp[1][1][1] = 0;
for(int i = 2; i <= n; ++i)
{
for(int j = 0, c = (i + 1) / 2; j <= c; ++j)
dp[i][j][0] = min(dp[i - 1][j][0],
dp[i - 1][j][1] + max(0, h[i] - (h[i-1]-1)));
for(int j = 1, c = (i + 1) / 2; j <= c; ++j)
dp[i][j][1] = min(dp[i-2][j-1][0] + max(0, h[i-1]-(h[i]-1)),
dp[i-2][j-1][1] + max(0, max(h[i-1]-(h[i]-1),
h[i-1]-(h[i-2]-1))));
}
int main()
{
std::freopen("../tests/76", "r", stdin);
std::freopen("hills.out", "w", stdout);
int t = 1;
for(int ti = 1; ti <= t; ++ti)
{
//printf("Case #%d: ", ti);
test_case();
}
}
int A[5001],dp[5001][2501][2],a,i,j;
int main()
{
std::freopen("../tests/76", "r", stdin);
std::freopen("hills.out", "w", stdout);
for(i=1;i<=a;i++)
{
scanf("%d",&A[i]),dp[i][0][0]=0;
if(i!=1)
for(j=1;j<=(i+1)>>1;j++)
dp[i][j][0]=min(dp[i-1][j][0],dp[i-1][j][1]+max(0,A[i]-A[i-1]+1)),
dp[i][j][1]=min(dp[i-2][j-1][0]+max(0,A[i-1]-A[i]+1),
dp[i-2][j-1][1]+max(0,A[i-1]-min(A[i],A[i-2])+1));
}
for(i=1;i<=(a+1)>>1;i++)
printf("%d ",min(dp[a][i][0],dp[a][i][1]));
}
// https://codeforces.com/contest/1013/submission/81469343
// https://codeforces.com/contest/1013/status/E
#define N 5005
int n,a[N],dp[N][N/2][2];
int main()
{
std::freopen("../tests/76", "r", stdin);
std::freopen("hills.out", "w", stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
memset(dp,127,sizeof(dp));
dp[0][0][0]=dp[1][1][1]=dp[1][0][0]=0;
for(int i=2;i<=n;i++)
{
dp[i][0][0]=0;
for (int j=1;j<=(n+1)>>1;j++)
{
dp[i][j][0]=min(dp[i-1][j][0],
dp[i-1][j][1]+max(0,a[i]-a[i-1]+1));
dp[i][j][1]=min(dp[i-2][j-1][1]+max(0,a[i-1]-min(a[i],a[i-2])+1),
dp[i-2][j-1][0]+max(0,a[i-1]-a[i]+1));
}
}
#include <bits/stdc++.h>
#define debug(x) cerr << #x << ": " << x << endl
#define debug2(x, y) debug(x), debug(y)
#define repn(i, a, b) for(int i = (int)(a); i < (int)(b); i++)
#define rep(i, a) for(int i = 0; i < (int)(a); i++)
#define all(v) v.begin(), v.end()
#define mp make_pair
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define fi first
#define se second
#define sq(x) ((x) * (x))
template<class T>
T gcd(T a, T b)
{
return ((b == 0) ? a : gcd(b, a % b));
CAPITOLUL 10. EJOI 2018 10.1. HILLS 253
int dp[mxN][mxN];
int mn[mxN];
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
vi a(n);
rep(i, n) cin >> a[i];
if(n == 1)
{
cout << 0 << endl;
return 0;
}
if(i > 1)
{
repn(j, 1, ((n + 1) / 2) + 1)
{
dp[i][j] = min(mn[j - 1] +
max(0, a[i - 1] - a[i] + 1) +
(i < (n-1) ? max(a[i+1]-a[i]+1, 0) : 0),
dp[i][j]);
}
repn(j, 1, ((n + 1) / 2) + 1)
{
if(i > 1) mn[j] = min(mn[j], dp[i - 2][j]);
}
}
}
vi ans(((n + 1) / 2) + 1, 1e9);
rep(i, n)
{
repn(j, 1, ((n + 1) / 2) + 1)
{
ans[j] = min(ans[j], dp[i][j]);
}
}
return 0;
}
/*
CAPITOLUL 10. EJOI 2018 10.1. HILLS 254
int main()
{
std::freopen("../tests/76", "r", stdin);
std::freopen("hills.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &ai[i]);
dp[0][0][0] = 0;
for (int i = 1; i <= n; i++)
{
dp[i][0][0] = 0;
for (int j = 1; j <= (i + 1) >> 1; j++)
{
if (ai[i] > ai[i - 1])
dp[i][j][1] = min(dp[i][j][1], dp[i - 1][j - 1][0]);
if (i != 1)
{
if (ai[i] > ai[i - 2] - 1)
dp[i][j][1] = min(dp[i][j][1], dp[i - 1][j - 1][2]);
else
dp[i][j][1] = min(dp[i][j][1],
dp[i-1][j-1][2]+ai[i-2]-1-ai[i]+1);
}
if (ai[i] <= ai[i - 1])
dp[i][j][1] = min(dp[i][j][1],
dp[i - 1][j - 1][0] + ai[i-1]-ai[i]+1);
// choose;
dp[i][j][0] = min(dp[i][j][0],
min(dp[i-1][j][2], dp[i-1][j][0]));
if (ai[i] < ai[i - 1])
dp[i][j][0] = min(dp[i][j][0], dp[i - 1][j][1]);
if (ai[i] >= ai[i - 1])
dp[i][j][2] = min(dp[i][j][2],
min(dp[i-1][j][1],
dp[i-1][j][0]) + ai[i] - ai[i-1] + 1);
}
}
return 0;
}
int main()
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 255
char* argv[] =
{
(char*)"checker",
(char*)"../tests/76",
(char*)"../tests/76.a",
(char*)"hills.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
10.2 Passports
Problema 2 - Passports 100 de puncte
Gleb is a famous competitive programming teacher from Innopolis. He is planning a trip to
N programming camps in the nearest future. Each camp will be held in a different country. For
each of them, Gleb needs to apply for a visa.
For each of these trips Gleb knows three integers: the number of the first day of the trip si ,
the length of the trip in days leni , and the number of days ti this country’s consulate will take to
process a visa application and stick a visa in a passport. Gleb has P (1 & P & 2) valid passports
and is able to decide which visa he wants to put in which passport.
For each trip, Gleb will have a flight to that country early in the morning of the day si and
will return back late in the evening of the day si leni 1.
To apply for a visa on the day d, Gleb needs to be in Innopolis in the middle of this day. So
he can’t apply for a visa while he is on a trip, including the first and the last days. If a trip starts
the next day after the end of the other one, Gleb can’t apply for a visa between them as well. The
earliest Gleb can apply for a visa is day 1.
After applying for a visa of country i on day d, Gleb will get his passport back in the middle
of the day d ti . Consulates use delivery services, so Gleb can get his passport back even if he
is not in Innopolis on this day. Gleb can apply for another visa on the same day he received his
passport back, if he is in Innopolis this day.
Gleb will not be able to start his trip on day si if he doesn’t has a passport with a visa for
the corresponding country in the morning of day si . In particular, the passport should not be in
another country’s consulate for visa processing.
Help Gleb to decide which visas he needs to receive in which passport, and when he should
apply for each visa.
Input
In the first line of the input there are two integers N (1 & N & 22) and P (1 & P & 2)—the
number of trips and the number of passports Gleb has, respectively.
The next N lines describe Gleb’s trips. Each line contains three positive integers si , leni , ti
(1 & si , leni , ti & 10 )—the first day of the trip, the length of the trip and number of days the
9
consulate of this country needs to process a visa application. It is guaranteed that no two trips
intersect.
Output
If it is impossible to get all visas on time, just print “NO” (quotes for clarity). Otherwise,
print “YES” and N lines describing trips. For each trip, first print number of the passport Gleb
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 256
should put this country’s visa in, and then print number of the day he should apply for it. Print
trips in the same order as they appear in the input. Days are numbered from 1, starting with
tomorrow—the first day you can apply for a visa. Passports are numbered from 1 to P .
Constraints
***
Subtasks
Examples
standard input standard output
21 YES
311 11
611 14
31 YES
13 2 2 1 10
731 11
19 3 4 12
72 YES
15 1 1 2 13
14 1 1 11
18 1 1 1 16
21 1 1 1 19
946 12
22 2 5 2 16
543 21
31 NO
731
13 2 3
19 3 4
Comment backslash Note
Examples with answer “YES” are depicted below.
Each cell of the stripe represents a single day. Rectangles represent trips, each trip starts in
the morning and ends in the evening. Rectangles with angled corners represent visa applications.
Each application starts in the middle of a day and ends ti days after. The trip and the visa
application for the same country have the same color.
In examples with two passports, visa applications and trips depicted above the time stripe are
made using the first passport, visa applications and trips depicted below the time stripe are made
using the second passport.
Example 1:
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 257
✶ ✷ ✸ ✹ ✺ ✻ ✼
Example 2:
✶ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ )✁ ✂✄ ☎✆ ✝✞ ✟✠ ✡☛ ☞✌ ✍✎ ✏✑ ✒✓ ✔✕ ✖✗ ✘✙
Example 3:
♠♥♦♣ ✉
✶ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ )✁ ✂✄ ☎✆ ✝✞ ✟✠ ✡☛ ☞✌ ✍✎ ✏✑ ✒✓ ✔✕ ✖✗ ✘✙ ✚✛ ✜✢
https://codeforces.com/blog/entry/60920
https://codeforces.com/topic/61265/en10
Let’s solve the P 1 case first. We’ll use dynamic programming on subsets. Let’s try to
add visas to subset in order of application. Notice that if we only have one passport, every visa
processing segment should lie between some two consecutive trips. For convenience, let’s find all
these segments beforehand.
Define dpA as the minimum day, before which all visas from set A can be acquired. Try all
possible i as a visa which Gleb will apply for next. Now we have to find minimum possible day
of application d, such that d ' dpA, segment d, d ti does not intersect with any trip, and
d ti $ si . Such d can be found in O n by a linear search over precalculated free segment. Relax
the value of with d ti . If dpr1..nx $ then there is a solution that can be restored using
n 2
standard techniques. Total time complexity is O 2 n , that can be too slow for n 22.
Let’s generalize this solution for P 2. Still, Gleb can apply for a visa only when he is in
Innopolis. However, the last day of visa processing can be during some trip, but only if all trips
between the day of visa application and the day of visa acquisition use another passport.
We will slightly change the definition of dpA: now this value is equal to the minimum possible
day, by which it’s possible to finish processing all visas from set A with one passport, assuming
all trips not from A use another passport.
By this definition, calculation of DP transition is a little bit different: when trying to add
visa i we have to find minimum d, such that d ' dpA, during day d Gleb is in Innopolis, and
segment d, d ti does not intersect with half-closed intervals sj , sj lenj for all. This can be
n 2
implemented similarly to the first part in O n. Total running time is O 2 n , that can pass
system tests with some optimizations.
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 258
n
We’ll optimize the solution down to O 2 n. To do that, we process all transition from set A
in O n total time. Sort all visas in order of increasing ti . Then the optimal visa application day
d will be increasing if visa processing time ti increases. Now we can apply two pointers technique
n
to get O n total processing time for one set and O 2 n for all sets.
After calculating dpA for all subsets, we have to try all partitions of r1..nx into two sets A
and B and check if both A and B can be done with one passport each. This is equivalent to
dpA $ . If there are two such sets that dpA $ and dpB $ , then we have
found the answer, otherwise there is no answer.
struct trip
{
int l;
int len;
int t;
int id;
};
int main()
{
std::freopen("../tests/157", "r", stdin);
std::freopen("passports.out", "w", stdout);
int n, p;
scanf("%d%d", &n, &p);
vector<trip> trips(n);
while (true)
{
while (ptr != lorder.end() && ptr->l + ptr->len <= c) ptr++;
while (ptr_same != lorder.end() &&
(ptr_same->l < c || ((i & (1 << ptr_same->id)) == 0)))
ptr_same++;
if (ptr != lorder.end() && ptr->l <= c)
{
c = ptr->l + ptr->len;
//printf("need wait till %d for end of trip %d\n", /
// c, ptr->id);
continue;
}
break;
}
if (p == 1)
{
if (dp[(1 << n) - 1] != INF)
{
restore((1 << n) - 1, 1);
}
}
else
{
for (int i = 0; i < (1 << n) - 1; i++)
{
if (dp[i] != INF && dp[(1 << n) - 1 - i] != INF)
{
restore(i, 1);
restore((1 << n) - 1 - i, 2);
break;
}
}
}
if (anst[0] == -1)
{
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 260
printf("NO\n");
}
else
{
printf("YES\n");
for (int i = 0; i < n; i++)
{
printf("%d %d\n", ansp[i], anst[i]);
}
}
return 0;
}
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <limits>
#include <functional>
int main()
{
std::freopen("../tests/157", "r", stdin);
std::freopen("passports.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);
int n, p;
cin >> n >> p;
vector<int> s(n);
vector<int> len(n);
vector<int> t(n);
vector<int> os(n);
vector<int> ot(n);
sort(os.begin(), os.end(),
[&](const int& a, const int& b) { return s[a] < s[b];});
sort(ot.begin(), ot.end(),
[&](const int& a, const int& b) { return t[a] < t[b]; });
vector<int> dp(1 << n, INF); // dp[a]: minumum day to complete all trips
// and visas in the bitmask a
vector< pair<int, int> > save(1 << n); // table to recover the solution
dp[0] = 1;
for (int mask = 0; mask < (1 << n); mask++)
{
if (dp[mask] < INF)
{
int i = 0;
int val = dp[mask];
for (auto& j : ot)
{
if (mask & (1 << j)) { continue; }
while (i < n && val + t[j] >= s[os[i]])
{
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 261
if (val + t[j] < s[j] && dp[mask + (1 << j)] > val + t[j])
{
dp[mask + (1 << j)] = val + t[j];
save[mask + (1 << j)] = {j, val};
}
}
}
}
vector<int> which(n);
vector<int> day(n);
if (p == 1)
{
if (dp[(1 << n) - 1] == INF)
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
assign((1 << n) - 1, 1);
for (int i = 0; i < n; i++)
{
cout << which[i] << ’ ’ << day[i] << endl;
}
}
}
else
{
int sec = -1;
for (int mask = 0; mask < (1 << n); mask++)
{
if (dp[mask] < INF && dp[((1 << n) - 1) ˆ mask] < INF)
{
sec = mask;
break;
}
}
if (sec == -1)
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
assign(sec, 1);
assign(((1 << n) - 1) ˆ sec, 2);
for (int i = 0; i < n; i++)
{
cout << which[i] << ’ ’ << day[i] << endl;
}
}
}
return 0;
}
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 262
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <bitset>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
#include <iomanip>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define fe first
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ]; \
void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;} \
void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
#define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ]; \
void ad_de(int a,int b,int c){++M; nxt[M]=fst[a]; fst[a]=M; \
vb[M]=b; vc[M]=c;} \
void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
#define es(x,e) (int e=fst[x];e;e=nxt[e])
#define esb(x,e,b) (int e=fst[x],b=vb[e];e;e=nxt[e],b=vb[e])
#define SZ 666666
int n,p,s[SZ],len[SZ],t[SZ],id[SZ];
int f[1<<22]; pii so[1<<22],rs[SZ];
vector<int> ve,v2;
int main()
{
std::freopen("../tests/157", "r", stdin);
std::freopen("passports.out", "w", stdout);
scanf("%d%d",&n,&p);
for(int i=0;i<n;++i)
scanf("%d%d%d",s+i,len+i,t+i),
ve.pb(i),v2.pb(i);
sort(ve.begin(),ve.end(),by_s);
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 263
sort(v2.begin(),v2.end(),by_t);
f[0]=1;
for(int i=0;i<(1<<n);++i) if(f[i]!=inf)
{
int _=0,g=f[i];
for(auto t:v2) if(!(i&(1<<t)))
{
for(;_<int(ve.size());++_)
{
int j=ve[_];
if(g+::t[t]<s[j]) break;
if(i&(1<<j))
{
if(g<s[j]+len[j]) g=s[j]+len[j];
}
else
if(g>=s[j]&&g<s[j]+len[j]) g=s[j]+len[j];
}
if(g+::t[t]>=s[t]) continue;
int w=g+::t[t];
if(w>=f[iˆ(1<<t)]) continue;
f[iˆ(1<<t)]=w;
so[iˆ(1<<t)]=pii(g,t);
}
}
if(p==1)
{
if(f[(1<<n)-1]>=inf)
{
puts("NO");
return 0;
}
puts("YES");
prt((1<<n)-1,1);
for(int i=0;i<n;++i)
printf("%d %d\n",rs[i].fi,rs[i].se);
return 0;
}
int g=-1;
for(int i=0;i<(1<<n);++i)
if(f[i]<inf&&f[((1<<n)-1)ˆi]<inf) g=i;
if(g==-1)
{
puts("NO");
return 0;
}
puts("YES");
prt(g,1);
prt(((1<<n)-1)ˆg,2);
for(int i=0;i<n;++i)
printf("%d %d\n",rs[i].fi,rs[i].se);
}
#include<bits/stdc++.h>
template<typename T>
inline void read(T &x)
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 264
{
x=0;
bool f=0;
char ch=getchar();
for(; ch<’0’||ch>’9’; ch=getchar())
f|=ch==’-’; // f |= (ch==’-’);
x=f?-x:x;
}
int n,S,p,f[1<<22];
struct node
{
int l,r,t,id;
} a[25],b[25];
struct From
{
int id,st;
} from[1<<22],ans[25];
void solve1()
{
if(f[S-1]==inf){ puts("NO"); return; }
puts("YES"),putcol(S-1,1);
for(int i=0;i<n;i++)
printf("%d %d\n", ans[i].id, ans[i].st);
}
void solve2()
{
int s=0;
for(;s<S;s++)
if(f[s]<inf && f[(S-1)ˆs]<inf) break;
if(s==S){puts("NO");return;}
for(int i=0;i<n;i++)
printf("%d %d\n", ans[i].id, ans[i].st);
}
int main()
{
std::freopen("../tests/157", "r", stdin);
std::freopen("passports.out", "w", stdout);
read(n),
read(p),
S=1<<n;
for(int i=1;i<=n;i++)
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 265
{
read(a[i].l),
read(a[i].r),
read(a[i].t);
a[i].r+=a[i].l-1,
a[i].id=i-1,
b[i]=a[i];
}
sort(a+1,a+1+n,cmp1),
sort(b+1,b+1+n,cmp2);
f[0]=1;
for(int s=0,i,j,T;s<S;s++)
if(f[s]<inf)
{
for(i=1,j=1,T=f[s];i<=n;i++)
if(!(s&(1<<b[i].id)))
{
for(;j<=n&&T+b[i].t>=a[j].l;j++)
{
((s&(1<<a[j].id))||T>=a[j].l) ? updmax(T,a[j].r+1) : (void)0;
}
return 0;
}
OBS1: (x¡¡1LL)+(x¡¡3LL) este echivalent cu x*2 + x*8 = x*10 care permite ”alocarea
unui unui spaţiu pentru o cifră”!
OBS2: return x¿y ? x=y,1 : 0; returnează 1 dacă x¿y, altfel returnează 0. În plus, dacă x¿y
se face şi atribuirea x=y. (http://www.cplusplus.com/doc/tutorial/operators/
”... When the set of expressions has to be evaluated for a value, only the right-most expression is
considered.”)
OBS3: (void)0; este un fel de ”instrucţiune vidă”. (https://stackoverflow.com/ques
tions/2198950/why-is-void-0-a-no-operation-in-c-and-c ”... (void)0 (+;) is
a valid, but ’does-nothing’ C++ expression, that’s everything. It doesn’t translate to the no-op
instruction of the target architecture, it’s just an empty statement as placeholder whenever the
language expects a complete statement ...”)
#include<bits/stdc++.h>
char st;
{
return s[a]<s[b];
}
int i=g[S][0];
cho[i]=id;
date[i]=g[S][1];
dfs(Sˆ1<<i,id);
}
int main()
{
std::freopen("../tests/157", "r", stdin);
std::freopen("passports.out", "w", stdout);
scanf("%d%d",&n,&p);
up=1<<n;
for(int i=0;i<n;i++)
scanf("%d%d%d",&s[i],&len[i],&t[i]),
id[0][i]=id[1][i]=i;
sort(id[0],id[0]+n,cmp1);
sort(id[1],id[1]+n,cmp2);
f[0]=1;
for(int S=0; S<up; S++)
if(f[S]ˆINF)
{
int ptr=0,val=f[S];
//"val apply date (noon)
for(int k=0,i=id[1][k]; k<n; k++,i=id[1][k])
if((!(S>>i&1)))
{
while(ptr<n&&val+t[i]>=s[id[0][ptr]])
{
//"apply visa i using this passort
int j=id[0][ptr++];
if((S>>j&1)||val>=s[j])
//"need this passort for trip j
//" or at least after trip j
chkmax(val,s[j]+len[j]);
}
if(val+t[i]<min(f[S|1<<i],s[i]))
{
chkmin(f[S|1<<i],val+t[i]);
g[S|1<<i][0]=i;
g[S|1<<i][1]=val;
}
}
}
if(p==1)
{
if(f[up-1]==INF) return puts("NO");
puts("YES");
dfs(up-1,1);
for(int i=0;i<n;i++) printf("1 %d\n",date[i]);
}
else
{
int S=0;
for(int i=1;i<up;i++)
if(f[i]ˆINF&&f[up-1-i]ˆINF) {S=i;break;}
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 267
puts("YES");
dfs(S,1);
dfs(up-1-S,2);
for(int i=0;i<n;i++) printf("%d %d\n",cho[i],date[i]);
}
return 0;
}
#include<bits/stdc++.h>
int n,P;
int Srt[maxN],Len[maxN],Nt[maxN];
int Is[maxN],It[maxN];
int F[pw(maxN)+10],From[pw(maxN)+10];
pair<int,int> Ans[maxN];
int main()
{
std::freopen("../tests/157", "r", stdin);
std::freopen("passports.out", "w", stdout);
scanf("%d%d",&n,&P);
int N=1<<n;
for (int i=1;i<N;i++) F[i]=inf;
F[0]=1;
for (int i=0;i<n;i++)
scanf("%d%d%d",&Srt[i],&Len[i],&Nt[i]),
Is[i]=It[i]=i;
sort(&Is[0],&Is[n],cmps);
sort(&It[0],&It[n],cmpt);
above|=pw(Is[lip]);
++lip;
}
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 268
if (F[S|pw(It[i])]>limt+Nt[It[i]])
F[S|pw(It[i])]=limt+Nt[It[i]],
From[S|pw(It[i])]=It[i];
}
}
if (P==1)
{
if (F[N-1]==inf) puts("NO");
else
{
int S=N-1;
while (S)
Ans[From[S]].second=F[S]-Nt[From[S]],
Sˆ=pw(From[S]);
puts("YES");
for (int i=0;i<n;i++)
printf("1 %d\n",Ans[i].second);
}
}
else
{
for (int S=0;S<N;S++)
if (F[S]!=inf&&F[Sˆ(N-1)]!=inf)
{
int T=S;
while (T)
Ans[From[T]]=make_pair(1,F[T]-Nt[From[T]]),
Tˆ=pw(From[T]);
T=Sˆ(N-1);
while (T)
Ans[From[T]]=make_pair(2,F[T]-Nt[From[T]]),
Tˆ=pw(From[T]);
puts("YES");
for (int i=0;i<n;i++)
printf("%d %d\n",Ans[i].first,Ans[i].second);
return 0;
}
puts("NO");
}
return 0;
}
#include<bits/stdc++.h>
struct zt
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 269
{
int ss,ii;
} frm[1<<22],ans[25];
struct node
{
int l,r,t,id;
} a[25],b[25];
int N,P,S,f[1<<22];
void SLV1()
{
if(f[S]==inf)
{
puts("NO"); exit(0);
}
puts("YES");
dfs(S,1);
for(int i=1;i<=N;i++)
{
printf("%d %d\n",ans[i].ii,ans[i].ss);
}
}
void SLV2()
{
int s1 = 0; int s2 = -233;
for(;s1<=S;s1++)
{
if(f[s1]<inf&&f[Sˆs1]<inf)
{
s2 = ( S ˆ s1 );
break;
}
}
if(s2==-233)
{
puts("NO"); exit(0);
}
puts("YES");
dfs(s1,1); dfs(s2,2);
for(int i=1;i<=N;i++)
{
printf("%d %d\n",ans[i].ii,ans[i].ss);
}
}
int main()
{
std::freopen("../tests/157", "r", stdin);
std::freopen("passports.out", "w", stdout);
scanf("%d%d",&N,&P);
for(int i=1;i<=N;i++)
{
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 270
scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].t);
a[i].id = i; a[i].r += a[i].l-1;
b[i] = a[i];
}
sort(a+1,a+1+N,cmp1);
sort(b+1,b+1+N,cmp2);
S = (1<<N)-1;
memset(f,0x3f,sizeof f);
f[0] = 1;
for(int s=0;s<S;s++)
{
if(f[s]!=inf)
{
int tim = f[s];
int pit = 1;
for(int i=1;i<=N;i++)
{
// cerr<<i<<pit<<endl;
if( (s>>(b[i].id-1))&1 ) continue;
for(;pit<=N&&tim+b[i].t>=a[pit].l;pit++)
{
if(tim>=a[pit].l||( (s>>(a[pit].id-1))&1 ))
tim = max(tim,a[pit].r+1);
}
if(tim+b[i].t<b[i].l)
{
if(f[s|(1<<(b[i].id-1))] > tim+b[i].t )
{
f[s|(1<<(b[i].id-1))] = tim + b[i].t;
frm[s|(1<<(b[i].id-1))] = (zt) {tim,b[i].id};
}
}
}
}
}
if(P==1)
SLV1();
else
SLV2();
}
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define SZ(x) ((int)x.size())
#define ALL(x) x.begin(),x.end()
#define L(i,u) for (register int i=head[u]; i; i=nxt[i])
#define rep(i,a,b) for (register int i=(a); i<=(b); i++)
#define per(i,a,b) for (register int i=(a); i>=(b); i--)
int f=1;
while (!isdigit(c))
{
if (c==’-’) f=-1;
c=getchar();
}
while (isdigit(c))
{
x=x*10+c-’0’;
c=getchar();
}
x*=f;
}
inline ui R()
{
static ui seed=416;
return seedˆ=seed>>5, seedˆ=seed<<17, seedˆ=seed>>13;
}
int n,tp,t[N],bg[N],f[1<<22|3],rec[1<<22|3];
Pii ans[N];
struct seg
{
int l,r,t,idx;
} a[N];
read(n);
read(tp);
rep(i,1,n)
read(a[i].l),
read(a[i].r),
a[i].r+=a[i].l-1,
a[i].idx=i,
read(a[i].t),
t[i]=a[i].t,
bg[i]=a[i].l;
rep(i,1,n) id[i]=i;
rep(i,1,n-1)
if(a[i].r>=a[i+1].l) GG();
int all=(1<<n)-1;
rep(s,0,all) f[s]=inf;
f[0]=1;
CAPITOLUL 10. EJOI 2018 10.2. PASSPORTS 272
rep(s,0,all-1)
if(f[s]<inf)
{
int x=f[s],p=1,p2=1;
static Pii seg[N];
int sz=0;
rep(i,1,n)
if(s>>a[i].idx-1&1)
seg[++sz]=mp(a[i].l,a[i].r);
rep(j,1,n)
if((˜s>>id[j]-1&1))
{
while(1)
{
int orix=x,orip=p,orip2=p2;
while(p<=sz&&seg[p].se<x) p++;
if(p<=sz&&x+t[id[j]]>=seg[p].fi) x=seg[p].se+1,p++;
while(p2<=n&&a[p2].r<x) p2++;
if(p2<=n&&x>=a[p2].l&&x<=a[p2].r) x=a[p2].r+1;
if(orix==x&&orip==p&&orip2==p2) break;
}
if(f[s|1<<id[j]-1]>x+t[id[j]]&&x+t[id[j]]<bg[id[j]])
f[s|1<<id[j]-1]=x+t[id[j]],rec[s|1<<id[j]-1]=id[j];
}
// rep(i,1,n)if(x>=a[i].l&&x<=a[i].r)x=a[i].r+1;
// rep(i,1,n)if((˜s>>i-1&1)&&f[s|1<<i-1]>x+t[i]-1)
// f[s|1<<i-1]=x+t[i]-1,rec[s|1<<i-1]=i;
}
// cerr<<f[30]<<’:’<<f[30ˆall]<<endl;
if(tp==1)
{
if(f[all]>=inf)GG();
recover(all,1);
}
else
{
bool ok=0;
rep(s,0,all)
if(!ok&&f[s]<inf&&f[sˆall]<inf)
{
recover(s,1);recover(sˆall,2);ok=1;
}
if(!ok)GG();
}
puts("YES");rep(i,1,n)printf("%d %d\n",ans[i].fi,ans[i].se);
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/157",
(char*)"../tests/157.a",
(char*)"passports.out",
};
cout<<"argc = "<<argc<<"\n";
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 273
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
10.3 AB-Strings
Problema 3 - AB-Strings 100 de puncte
There are two strings s and t, consisting only of letters a and b. You can make the following
operation several times: choose a prefix of s, a prefix of t and swap them. Prefixes can be empty,
also a prefix can coincide with a whole string.
Your task is to find a sequence of operations after which one of the strings consists only of a
letters and the other consists only of b letters. The number of operations should be minimized,
but solutions that find non-optimal sequences will still get some points. Read the scoring section
for more detailed information.
Input
The first line contains a string s (1 & ¶s¶ & 2 10 ).
5
Here ¶s¶ and ¶t¶ denote the lengths of s and t, respectively. It is guaranteed that at least one
of the strings contains at least one a letter and at least one of the strings contains at least one b
letter.
Output
The first line should contain a single integer n (0 & n & 5 10 )—the number of operations.
5
Each of the next n lines should contain two space-separated integers ai , bi —the lengths of
prefixes of s and t to swap, respectively.
If there are multiple possible solutions, you can print any of them.
Constraints
***
Subtasks
Let n be the length of your sequence, and m be the length of some optimal sequence.
If for all tests of the group n m, you will get 100% of the score of this group.
If for all tests of the group n & m 2, you will get 70% of the score of this group (rounded
down to the nearest integer).
If for all tests of the group n & 2m 2, you will get 50% of the score of this group (rounded
down to the nearest integer).
If for all tests of the group n & 5 10 , you will get 30% of the score of this group (rounded
5
If for at least one test you output n % 5 10 , you will get WA and 0 points for this group.
5
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 274
Examples
standard input standard output
bab 2
bb 10
13
bbbb 0
aaa
Comment ¯ Note
In the first example, you can solve the problem in two operations:
1. Swap the prefix of the first string with length 1 and the prefix of the second string with
length 0. After this swap, you’ll have strings ab and bbb.
2. Swap the prefix of the first string with length 1 and the prefix of the second string with
length 3. After this swap, you’ll have strings bbbb and a.
In the second example, the strings are already appropriate, so no operations are needed.
https://codeforces.com/blog/entry/60920
https://codeforces.com/topic/61265/en10
The solution is basically like following:
Note that we can compress equal adjacent letters.
Now we can do a dynamic programming with params (first letter of s, length of s, first letter
of t, length of t).
However, the amount of transactions and even states is too large. But we can write a slow,
but surely correct solution, and examine the transactions, which are made in dp.
Basically, the most typical transaction is to just make a swap of first group in s with first group
in t. However there special cases, like when the first letters are the same or when the lengths are
very small.
Running a slow dynamic programming helps to get all the cases for the solution.
Formally, the correctness of this algorithm can be proven by induction and the large cases
analyses, which we skip for clarity.
Another approach is to consider different first operations, and then go a greedy after it algo-
rithm. See the second solution for the details. We don’t prove it.
The first solution: 40971595
(https://codeforces.com/contest/1012/submission/40971595)
and the second solution: 40971634
(https://codeforces.com/contest/1012/submission/40971634).
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 275
string s, t;
make(s, a);
make(t, b);
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
answer.pb(mp(sum1, sum2));
while (cura.size())
{
b.pb(cura.back());
cura.pop_back();
}
while (curb.size())
{
a.pb(curb.back());
curb.pop_back();
}
}
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 277
return answer;
}
int main()
{
std::freopen("../tests/146", "r", stdin);
std::freopen("ab-strings.out", "w", stdout);
getline(cin, s);
getline(cin, t);
printf("%d\n", (int)ans1.size());
for (auto u : ans1)
{
printf("%d %d\n", u.first, u.second);
}
return 0;
}
a.pb(mp(cur, cnt));
}
string s, t;
answer.pb(mp(sum1, sum2));
while (cura.size())
{
b.pb(cura.back());
cura.pop_back();
}
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 280
while (curb.size())
{
a.pb(curb.back());
curb.pop_back();
}
}
return answer;
}
int main()
{
std::freopen("../tests/146", "r", stdin);
std::freopen("ab-strings.out", "w", stdout);
printf("%d\n", (int)ans1.size());
for (auto u : ans1)
{
printf("%d %d\n", u.first, u.second);
}
return 0;
}
}
reverse(result.begin(), result.end());
return result;
}
int main()
{
std::freopen("../tests/146", "r", stdin);
std::freopen("ab-strings.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
string s, t;
cin >> s >> t;
auto x = convert(s);
auto y = convert(t);
bool swapped = false;
vector<pair<int, int>> answer;
char a = x.back().first;
char b = y.back().first;
if (a != b)
{
if (lb <= 2)
{
if (la <= 3)
{
query(1, 1);
}
else
{
query(3, 1);
}
}
else
{
query(1, 1);
}
}
else
{
if (lb == 1)
{
if (la <= 3)
{
query(1, 0);
}
else
{
query(3, 0);
}
}
else
if (lb == 2)
{
if (la == 2)
{
query(1, 0);
}
else
{
query(2, 1);
}
}
else
{
query(3, 2);
}
}
}
return 0;
}
\end{lstlistng}
%---------------------------------------------------------------------------
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 283
\hspace{0.33cm}
\subsection{*Rezolvare detaliat\u a}
\vspace{3mm}
%=================================================================
\section{Chemistry}
Innopolis University scientists continue to investigate the periodic table. There are $n
\cdot m$
known elements and they form a periodic table, a rectangle with $n$ rows and $m$
columns. Each element can be described by its coordinates $(r, c)$ ($1 \le r \le n$
, $1 \le c \le m$) in the table. Recently scientists discovered that for every four
different elements in this table that form a rectangle with sides parallel to
sides of the table, if they have samples of three of four elements, they can
produce a sample of the fourth element using nuclear fusion. So if we have elements
in positions $(r_1, c_1)$, $(r_1, c_2)$, $(r_2, c_1)$, where $r_1 \neq r_2$ and
$c_1 \neq c_2$, then we can produce element $(r_2, c_2)$.
\begin{figure}[H]
\centering
%\begin{center}
\includegraphics[width=0.63\textwidth]{img/ejoi2018_chemistry4.eps}
%\end{center}
%\caption{***}
\end{figure}
Original samples of elements as well as newly crafted elements can be used again in
future fusions.
Innopolis University scientists already have samples of $q$ elements. They want to
obtain samples of all $n \cdot m$ elements. To achieve that, they will purchase some
samples from other laboratories and then produce all remaining elements using
arbitrary number of nuclear fusions in some order. Help them find the minimal number
of elements they need to purchase.
\vspace{2mm}
\noindent
{\bf Input}
\vspace{2mm}
First line contains three integers $n$, $m$, $q$ ($1 \le n, m \le 200\,000$; $0 \le q \
le \min(n \cdot m, 200\,000)$)---chemical table dimensions and the number of
elements scientists already have. Following $q$ lines contain two integers $r_i$,
$c_i$ ($1 \le r_i \le n$, $1 \le c_i \le m$) each---descriptions of the elements
that scientists already have. All elements in the input are different.
\vspace{2mm}
\noindent
{\bf Output}
\vspace{2mm}
\vspace{2mm}
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 284
\noindent
{\bf Constraints}
\vspace{2mm}
\begin{itemize}
\item ***
\end{itemize}
\vspace{2mm}
\noindent
{\bf Subtasks}
\vspace{2mm}
\medskip
\begin{center}
\begingroup
\renewcommand{\arraystretch}{1.5}
\begin{tabular}{|c|c|c|c|c|c|}
\hline
& & \multicolumn{3}{|c|}{Constraints} & \\
\cline{3-5}
\raisebox{2.25ex}[0cm][0cm]{Subtask}
& \raisebox{2.25ex}[0cm][0cm]{Score}
& $n$ & $m$ & $q$
& \raisebox{2.25ex}[0cm][0cm]{\parbox{3cm}{\centering Dependencies}}
\\
\hline
0 & 0 & --- & --- & --- & --- \\
\hline
1 & 10 & $n = 2$ & $m = 2$ & $0 \le q \le 4$ & --- \\
\hline
2 & 8 & $n = 1$ & $1 \le m \le 20$ & $0 \le q \le 20$ & --- \\
\hline
3 & 9 & $n = 2$ & $1 \le m \le 20$ & $0 \le q \le 40$ & 1 \\
\hline
4 & 8 & $1 \le n \le 20$ & $1 \le m \le 20$ & $q = 0$ & --- \\
\hline
5 & 20 & $1 \le n \le 20$ & $1 \le m \le 20$ & $0 \le q \le 400$ & 1---4 \\
\hline
6 & 10 & $1 \le n \le 100$ & $1 \le m \le 100$ & $0 \le q \le 10\,000$ & 1---5 \\
\hline
7 & 10 & $1 \le n \le 250$ & $1 \le m \le 250$ & $0 \le q \le 62\,500$ & 1---6 \\
\hline
8 & 10 & $1 \le n \le 10\,000$ & $1 \le m \le 10\,000$ & $0 \le q \le 100\,000$ & 1---7
\\
\hline
9 & 15 & $1 \le n \le 200\,000$ & $1 \le m \le 200\,000$ & $0 \le q \le 200\,000$ &
1---8 \\
\hline
\end{tabular}
\endgroup
\end{center}
% ---------------------------------------------
\vspace{2mm}
\noindent
{\bf Examples}
\vspace{2mm}
\begin{tabular}{|p{30mm}|p{30mm}|}
\hline
standard input & standard output \\ \hline
2 2 3 \newline
1 2 \newline
2 2 \newline
2 1
&
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 285
0 \\
\hline
1 5 3 \newline
1 3 \newline
1 1 \newline
1 5
&
2 \\
\hline
4 3 6 \newline
1 2 \newline
1 3 \newline
2 2 \newline
2 3 \newline
3 1 \newline
3 3
&
1 \\
\hline
\end{tabular}
\vspace{3mm}
\noindent
{\bf Comment $\backslash$ Note}
\vspace{2mm}
The first picture for each example describes the initial set of element samples
available.
Black crosses represent elements available in the lab initially.
\textbf{Test 1}
We can use nuclear fusion and get the element from other three samples, so we don’t need
to purchase anything.
\begin{figure}[H]
\centering
%\begin{center}
\includegraphics[width=0.45\textwidth]{img/ejoi2018_chemistry1.eps}
%\end{center}
%\caption{***}
\end{figure}
\textbf{Test 2}
We cannot use any nuclear fusion at all as there is only one row, so we have to purchase
all missing elements.
\begin{figure}[H]
\centering
%\begin{center}
\includegraphics[width=0.63\textwidth]{img/ejoi2018_chemistry2.eps}
%\end{center}
%\caption{***}
\end{figure}
\textbf{Test 3}
Note that after purchasing one element it’s still not possible to produce the middle
element in the top row (marked as 4).
So we produce the element in the left-bottom corner first (marked as 1), and then use it
in future fusions.
\begin{figure}[H]
\centering
%\begin{center}
\includegraphics[width=0.5\textwidth]{img/ejoi2018_chemistry3.eps}
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 286
%\end{center}
%\caption{***}
\end{figure}
% ---------------------------------------------
\vspace{3mm}
\vspace{2mm}
% ---------------------------------------------
\vspace{3mm}
\subsection{Indica\c tii de rezolvare} % Chemical table
\vspace{3mm}
\url{https://codeforces.com/blog/entry/60920}
\noindent
\url{https://codeforces.com/topic/61265/en10}
\vspace{2mm}
One of the way to solve this problem is to interprete the cells in $2d$ matrix as an
edge in the {\it bipartite graph}\index{graph!bipartite}, that is a cell $(i, j )$
is an edge between $i$ of the left part and $j$ of the right part.
Note, that each fusion operation (we have edges $(r_1, c _ 1 )$, $(r_1, c _ 2 )$, $(r_2,
c _ 1 )$ and get edge $(r_2, c _ 2 )$) doesn’t change the {\it connected components}\
index{connected component} of the graph.
Moreover, we can prove, that we can obtain each edge in the connected component by
fusion.
Let’s examine example {\it edge}\index{edge} $(x, y )$, and some {\it path}\index{path}
between $x$ and $y$ (since they lay in one connected component). Since the graph is
bipartite, the length of this path must be odd, and it is $\ g e q 3 $ , otherwise the
edge already exists.
So we have this path. Take first three edges and make the corresponding fusion, replace
this three edges with the brand new fused edge. The length of the path decreased by
2. Repeat until the path is a mere edge.
This way, the number of edges to add (cells to buy) is just number of connected
components minus one.
\hspace{0.33cm}
\subsection{Coduri surs\u a} % ************************************
\hspace{0.99cm}
\begin{lstlisting}[language=C++,numbers=none,commentstyle=\color{purple}, caption={\
hspace{2mm} chemistry\_ad.cpp}]
#include <bits/stdc++.h> // execution time : 0.750 s
#define se second
#define fi first
#define forn(i, n) for (int i = 0; i < n; i++)
#define sz(a) (int)a.size()
#define mp make_pair
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
iostream::sync_with_stdio(0), cin.tie(0);
if (q == 0)
{
ans.push_back(mp(0, 0));
nms[0].push_back(0);
nmr[0].push_back(0);
}
forn (i, n)
{
if (use[i] == 0 && sz(nms[i]))
{
qq.push_back(mp(i, nms[i][0]));
queue<int> vv;
vv.push(i);
use[i] = 1;
while (!vv.empty())
{
int nu = vv.front();
vv.pop();
for (int q : nms[nu])
{
if (use2[q] == 0)
{
for (int c : nmr[q])
{
if (use[c] == 0)
{
use[c] = 1;
vv.push(c);
}
}
use2[q] = 1;
}
}
}
}
else
{
if (use[i] == 0)
cq.push_back(i);
}
}
forn (i, m)
{
if (use2[i] == 0)
{
pq.push_back(i);
}
}
ans.push_back(mp(cq[i], qq[0].se));
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::cerr;
using std::vector;
using std::map;
using std::array;
using std::set;
using std::string;
using std::pair;
using std::make_pair;
using std::min;
using std::abs;
using std::max;
using std::unique;
using std::sort;
using std::generate;
using std::reverse;
using std::min_element;
using std::max_element;
#ifdef LOCAL
#define LASSERT(X) assert(X)
#else
#define LASSERT(X) {}
#endif
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 289
int n = input<int>();
int m = input<int>();
graph[a].push_back(n + b);
graph[n + b].push_back(a);
}
vector<int> g[MX];
bool was[MX];
void dfs(int v)
{
was[v] = true;
for (int to : g[v])
{
if (!was[to])
{
dfs(to);
}
}
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m, q;
cin >> n >> m >> q;
if (q == 0)
{
cout << n + m - 1 << "\n";
/*for (int i = 1; i <= n; i++) {
cout << i << " 1\n";
}
for (int i = 2; i <= m; i++) {
cout << "1 " << i << "\n";
}*/
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 290
return 0;
}
dfs(anyv);
return 0;
}
vector<int> v[M];
vector<int> c[M];
bool used[M];
int n, m, q, r;
void dfs(int p)
{
used[p] = true;
c[r].push_back(p);
for (int i : v[p])
if (!used[i])
dfs(i);
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
ios::sync_with_stdio(0);
cin >> n >> m >> q;
for (int i = 0; i < q; i++)
{
int s, f;
cin >> s >> f;
s--, f--;
f += n;
v[s].push_back(f);
v[f].push_back(s);
}
memset(used, 0, sizeof(used));
r = 0;
for (int i = 0; i < (n + m); i++)
if (!used[i])
{
dfs(i);
r++;
}
return 0;
}
#include <map>
#include <cassert>
#include <queue>
#include <ctime>
#include <string>
#include <cstring>
#define mp make_pair
#define pb push_back
#define NAME ""
#define y1 y1_423
#define list lista
bool used[nmax];
vector<int> a[nmax];
vector<pair<int, int> > ans;
void dfs(int v)
{
used[v] = true;
for (int u : a[v])
{
if (!used[u])
{
dfs(u);
}
}
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
int n, m, q;
cin >> n >> m >> q;
for (int i = 0; i < q; i++)
{
int x, y;
scanf("%d%d", &x, &y);
x--, y--;
a[x].pb(y + n);
a[y + n].pb(x);
}
dfs(n);
printf("%d\n", (int)ans.size());
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 293
bool vis[400005];
vector<int> G[400005];
void dfs(int u)
{
vis[u] = 1;
for(auto v : G[u])
{
if(!vis[v])
dfs(v);
}
}
void test_case()
{
int n, m, q;
scanf("%d%d%d", &n, &m, &q);
while(q--)
{
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(n + v);
G[n + v].push_back(u);
}
int cnt = 0;
for(int i = 1; i <= n + m; ++i)
{
if(!vis[i])
{
dfs(i);
++cnt;
}
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
int t = 1;
for(int ti = 1; ti <= t; ++ti)
{
//printf("Case #%d: ", ti);
test_case();
}
}
int A[400001];
int Fx(int x)
{
return A[x]==x?x:A[x]=Fx(A[x]);
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
int a,b,c,i,x,y,w=0;
cin>>a>>b>>c;
for(i=1;i<=a+b;i++) A[i]=i;
for(i=1;i<=c;i++)
{
scanf("%d%d",&x,&y),
x=Fx(x),
y=Fx(y+a);
if(x!=y) A[x]=y;
}
for(i=1;i<=a+b;i++)
if(A[i]==i) w++;
cout<<w-1;
}
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
int n, m, q;
scanf("%d%d%d", &n, &m, &q);
int r, c;
for (int i = 1; i <= q; ++i)
{
scanf("%d%d", &r, &c);
c += n;
p[find(r)] = find(c);
}
int res = 0;
for (int i = 1; i <= n + m; ++i)
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 295
{
if (p[i] == i)
++res;
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cmath>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define ull unsigned long long
#define PI acos(-1)
#define pb(x) push_back(x)
#define il inline
#define re register
#define IO ios::sync_with_stdio(0);cin.tie(0);
//#define ls (o<<1)
//#define rs (o<<1|1)
#define pii pair<int,int>
int n, r, m;
int fa[maxn<<1];
int getfa(int x)
{
return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
IO;
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 296
int t;
cin >> n >> m >> t;
int u,v;
for (int i = 1; i <= n + m; i++)
fa[i] = i;
int ans = 0;
int root = getfa(1);
for (int i = 2; i <= n + m; i++)
{
if (getfa(i) != root)
ans ++, fa[getfa(i)] = root;
}
return 0;
}
int parent[500008];
vector< pair<int,int > > v(500008);
int n,m,q;
int find_set(int v)
{
if(v==parent[v])
return v;
return parent[v]=find_set(parent[v]);
}
}
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin.tie(0);
cin>>n>>m>>q;
for(int i=1;i<=q;i++)
{
int x,y;
cin>>x>>y;
v.push_back({x,y+n});
}
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 297
for(int i=1;i<=n+m;i++)
{
parent[i]=i;
}
for(int i=0;i<v.size();i++)
{
int x=v[i].first;
int y=v[i].second;
if(find_set(x)==find_set(y)) continue;
union_sets(x,y);
}
int ans=0;
for(int i=1;i<=n+m;i++)
{
if(find_set(i)==i)ans++;
}
cout<<ans-1<<endl;
return 0;
}
ll n, m, q;
vector<pll> a;
vector<pll> ps[maxn];
vector<ll> cnt(maxn, 0);
vector<ll> par;
vector<ll> sz;
ll get_par(ll v)
{
if(par[v] == v) return v;
return (par[v] = get_par(par[v]));
}
void join(ll v, ll u)
{
v = get_par(v);
u = get_par(u);
if(v == u) return;
if(sz[v] < sz[u])
{
swap(v, u);
}
par[u] = v;
sz[v] += sz[u];
}
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 298
void solve()
{
cin >> n >> m >> q;
for(ll i = 0; i < q; i++)
{
ll row, col;
cin >> row >> col;
row--;
col--;
a.pb({row, col});
ps[row].pb({col, i});
cnt[col]++;
}
set<ll> roots;
ll notusedx = 0;
ll notusedy = 0;
for(ll i = 0; i < m; i++)
{
if(cnt[i] > 0) roots.insert(get_par(i));
if(cnt[i] == 0) notusedx++;
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
return 0;
}
template<typename T>
void out(T x) { cout << x << endl; exit(0); }
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 299
#define watch(x) cout << (#x) << " is " << (x) << endl
struct dsu0
{
vector<int> par, siz;
int n;
int cc;
int largest;
void init(int n)
{
assert(n>0);
this->n=n;
cc=n;
par.resize(n+10);
siz.resize(n+10);
for (int i=0; i<n; i++)
par[i]=i,siz[i]=1;
largest=1;
}
int parent(int x)
{
assert(x>=0 && x<n);
return par[x]==x ? x : par[x]=parent(par[x]);
}
cc--;
if (siz[x]<siz[y]) swap(x,y);
siz[x]+=siz[y];
par[y]=x;
largest=max(largest,siz[x]);
}
};
int n,m,q;
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
cin>>n>>m>>q;
dsu0 dsu;
dsu.init(n+m);
while (q--)
{
int x,y;
cin>>x>>y;
--x;
--y;
dsu.join(x,y+n);
}
cout<<dsu.cc-1<<endl;
return 0;
}
// https://codeforces.com/contest/1012/submission/87201594
// https://codeforces.com/contest/1012/status/page/2?order=BY_JUDGED_DESC
int n, m, q;
vector<int> v[400050];
bool visited[400050];
void dfs(int e)
{
visited[e] = 1;
for(int i = 0; i < v[e].size(); i++)
if (!visited[v[e][i]]) dfs(v[e][i]);
}
int main(void)
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);
int cnt = 0;
cin>>n>>m>>q;
while(q--)
{
int a, b;
cin>>a>>b;
v[a].push_back(b+n);
v[b+n].push_back(a);
}
cout<<cnt-1;
return 0;
}
//TO_STRING
template <typename A, typename B>
string to_string(pair<A, B> p);
string s;
s += ch;
return s;
}
string to_string(bool b)
{
return (b ? "true" : "false");
}
string to_string(vector<bool> v)
{
bool first = true;
string res = "{";
for (int i = 0; i < static_cast<int>(v.size()); i++)
{
if (!first)
{
res += ", ";
}
first = false;
res += to_string(v[i]);
}
res += "}";
return res;
}
return res;
}
first = false;
res += to_string(x);
}
res += "}";
return res;
}
to_string(get<2>(p)) + ")";
}
//DEBUG
void debug_out() { cerr << endl; }
void no()
{
cout << "NO\n";
exit(0);
}
void solve()
{
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 303
int n, m, q;
cin >> n >> m >> q;
int N = n + m;
vvi edges(N + 1);
rep(i, 0, q)
{
int a, b;
cin >> a >> b;
b += n;
edges[a].pb(b);
edges[b].pb(a);
}
vb vis(N + 1);
int compo = 0;
rep(i, 1, N + 1)
{
if (!vis[i])
{
++compo;
dfs(i, vis, edges);
}
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t = 1;
// cin >> t;
return false;
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
while(cin>>n>>m)
{
par.resize(n+m+1);
iota(all(par),0);
int q;
cin>>q;
forn(i,q)
{
int x, y;
cin>>x>>y;
make_set(x,n+y);
}
int comps = 0;
for(int i=1; i<=n+m; ++i)
{
if(par[i]==i) ++comps;
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 305
cout<<comps-1<<"\n";
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
#include <functional>
#include <stack>
#include <cmath>
#include <cstring>
#include <random>
#include <chrono>
#include <memory>
#include <cassert>
#include <numeric>
#include <array>
#define int long long
#define pii pair<int, int>
#define pic pair<int, char>
#define pdd pair<double, double>
#define x first
#define y second
#define ll long long
#define ull unsigned long long
#define endl "\n"
#define all(a) (a).begin(), (a).end()
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
int n, m, q;
vector<int> g[N * 2];
bool used[2 * N];
void dfs(int v)
{
used[v] = true;
int32_t main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 306
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
while (q--)
{
int v, u;
cin >> v >> u;
g[v].push_back(u + N);
g[u + N].push_back(v);
}
int ans = 0;
118
mt19937
int n, m, q;
int fa[maxn * 2];
int Getfather(int x)
{
if(fa[x] != x) fa[x] = Getfather(fa[x]);
return fa[x];
}
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
while(q--)
{
int x, y;
118
http://www.cplusplus.com/reference/random/mt19937/
CAPITOLUL 10. EJOI 2018 10.3. AB-STRINGS 307
int fx = Getfather(x),
fy = Getfather(y);
int ans = 0;
for(int i = 1; i <= n + m; ++i)
if(fa[i] == i) ++ans;
int main()
{
std::freopen("../tests/167", "r", stdin);
std::freopen("chemistry.out", "w", stdout);
int ans = 0;
for (int i = 1; i <= n + m; i++)
if (color[i] == 0)
dfs(i, ++ans);
int main()
//int main(int argc, char * argv[])
{
setName("compare ordered sequences of signed int%d numbers", \
8 * sizeof(long long));
int argc=4;
char* argv[] =
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 308
{
(char*)"checker",
(char*)"../tests/167",
(char*)"chemistry.out",
(char*)"../tests/167.a",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
registerTestlibCmd(argc, argv);
int n = 0;
string firstElems;
if (j != p)
quitf(_wa, "%d%s numbers differ - expected: ’%s’, found: ’%s’", n,\
englishEnding(n).c_str(), vtos(j).c_str(), vtos(p).c_str());
else
if (n <= 5)
{
if (firstElems.length() > 0)
firstElems += " ";
firstElems += vtos(j);
}
}
if (n <= 5)
quitf(_ok, "%d number(s): \"%s\"", n, compress(firstElems).c_str());
else
quitf(_ok, "%d numbers", n);
}
4 1
6 3
2 5
Your goal is to relabel vertices in such a way that the number of bad edges is as small as
possible. For example, if you relabel vertices of the tree shown above in the following way, there
will be only one bad edge 3, 6:
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 309
1 2
6 3
5 4
The less bad edges your tree will have the more points you will get.
This is an output-only problem. There are 10 input files available in the PCMS.
You need to run your program locally and only submit the answer file for each input
file.
Input
Each input file contains several test cases.
The first line of the input file contains the number of test cases in this input file.
The first line of test case description contains a single integer n, the number of the vertices in
the tree.
Each of the following n 1 lines contains two integers u and v (1 & u, v & n), vertices connected
by the edge.
All trees in a single file have the same number of vertices.
Output
For each test case print one line containing exactly n different integers from 1 to n — labels
assigned to vertices 1, 2, . . . , n.
Constraints
***
Subtasks
For each input file, let the total number of edges in all test cases of this input file be M , the
X
total number of bad edges in your solution be X, and R M
. Your score for the input file is
calculated as following:
Example
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 310
4 1
5
2 1
1
2 4
4 6
6 2
7 5 7
7
5 3 3 3
Input files 2 and 3 contain 100 random trees on 10 and 30 vertices respectively.
Input files 4 to 8 contain various randomly generated trees with some special structure (e.g.
trees with many leaves, binary trees etc). Distribution of different kinds of trees is roughly
the same for all inputs.
Input files 9 and 10 contain randomly generated trees of 50 000 and 100 000 vertices respec-
tively.
Initially, label of vertices of all trees in all input files are random.
Timp maxim de executare/test: 10.0 secunde
Memorie: total 256 MB
***
largest.first += 1;
largest = max(largest, rs);
}
return largest;
}
int v = path.back();
used_this[v] = cur_t;
for (int u: graph[v])
if (not used[u] and used_this[u] != cur_t)
{
path.push_back(u);
path.pop_back();
}
return false;
}
void solve()
{
int n;
cin >> n;
vector<vector<int>> graph(n);
for (int i = 1; i != n; ++i)
{
int v = input<int>() - 1;
int u = input<int>() - 1;
graph[v].push_back(u);
graph[u].push_back(v);
}
vector<char> used(n);
vector<int> used_this(n);
int cur_t = 0;
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 312
vector<int> perm(n);
int p_free = 1;
while (true)
{
int i;
for (i = 0; i != n and used[i]; ++i) {}
if (i == n)
break;
int main()
{
std::freopen("../tests/11", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
std::minstd_rand rnd(31031999);
void solve()
{
int n = input<int>();
vector<vector<int>> graph(n);
for (int i = 1; i != n; ++i)
{
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 313
int v = input<int>() - 1;
int u = input<int>() - 1;
graph[v].push_back(u);
graph[u].push_back(v);
}
int sc = 0;
for (int v = 0; v != n; ++v)
for (int u: graph[v])
if (std::__gcd(perm[v], perm[u]) > 1)
sc += 1;
int main()
{
std::freopen("../tests/11", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
119
minstd rand
120
shuffle
121
uniform int distribution
122
gcd
Listing 10.4.3: full random.cpp
#include <bits/stdc++.h> // execution time : 0.813 s
int n;
vi e[maxn];
int l[maxn];
int sc;
void scan()
{
cin >> n;
forn(i, n) e[i].clear();
forn(i, n-1)
{
int u, v;
cin >> u >> v;
--u, --v;
e[u].emplace_back(v);
e[v].emplace_back(u);
}
forn(i, n) sort(all(e[i]));
forn(i, n) l[i] = i+1;
}
bool pr[maxn];
void erath()
{
pr[0] = pr[1] = false;
for (int i = 2; i < maxn; ++i) if (!pr[i])
{
if ((i64)i*i > maxn) break;
for (int j = i*i; j < maxn; j += i) pr[j] = true;
}
}
mt19937 rr;
// mt19937 rr{random_device{}()};
int getScore()
{
int sc = 0;
forn(v, n)
for (int to: e[v])
if (to < v && gcd(l[v], l[to]) > 1)
++sc;
return sc;
}
bool iter()
{
int x = rr() % n;
int y = x;
while (y == x) y = rr() % n;
{
sc = nxt;
return true;
}
else
{
swap(l[x], l[y]);
}
return false;
}
ld perTest;
ld limit;
bool TL()
{
static int iter = 0;
if (++iter == 100)
{
iter = 0;
if (1.0 * clock() / CLOCKS_PER_SEC > limit)
{
return true;
}
}
return false;
}
int T;
void solve()
{
shuffle(l, l+n, rr);
forn(i, n) cout << l[i] << " ";
cout << endl;
}
int main()
{
std::freopen("../tests/11", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
erath();
int t;
cin >> t;
T = t;
forn(i, t)
{
scan();
limit = 1.0 * clock() / CLOCKS_PER_SEC + perTest;
solve();
}
// fill();
#ifdef LOCAL
cerr << "Time elapsed: " << clock() / 1000 << " ms" << endl;
#endif
return 0;
}
123
emplace back
#define fi first
#define se second
#define all(x) (x).begin(), (x).end()
int n;
vi e[maxn];
int l[maxn];
int sc;
void scan()
{
cin >> n;
forn(i, n) e[i].clear();
forn(i, n-1)
{
int u, v;
cin >> u >> v;
--u, --v;
e[u].emplace_back(v);
e[v].emplace_back(u);
}
forn(i, n) sort(all(e[i]));
forn(i, n) l[i] = i+1;
}
bool pr[maxn];
void erath()
{
pr[0] = pr[1] = false;
for (int i = 2; i < maxn; ++i)
if (!pr[i])
{
if ((i64)i*i > maxn) break;
for (int j = i*i; j < maxn; j += i)
pr[j] = true;
}
}
mt19937 rr;
// mt19937 rr{random_device{}()};
int getScore()
{
int sc = 0;
forn(v, n)
for (int to: e[v])
if (to < v && gcd(l[v], l[to]) > 1)
++sc;
return sc;
}
bool iter()
{
int x = rr() % n;
int y = x;
while (y == x) y = rr() % n;
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 317
ld perTest;
ld limit;
bool TL()
{
static int iter = 0;
if (++iter == 100)
{
iter = 0;
if (1.0 * clock() / CLOCKS_PER_SEC > limit)
{
return true;
}
}
return false;
}
int T;
void solve()
{
shuffle(l, l+n, rr);
pair<int, vi> best(getScore(), vi(l, l+n));
while (!TL())
{
shuffle(l, l+n, rr);
best = min(best, pair<int, vi>{getScore(), vi(l, l+n)});
}
forn(i, n)
cout << l[i] << " ";
cout << endl;
}
int main()
{
std::freopen("../tests/11", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
erath();
int t;
cin >> t;
T = t;
perTest = 7.0 / T;
forn(i, t)
{
scan();
limit = 1.0 * clock() / CLOCKS_PER_SEC + perTest;
solve();
}
// fill();
#ifdef LOCAL
cerr << "Time elapsed: " << clock() / 1000 << " ms" << endl;
#endif
return 0;
}
using std::vector;
using std::map;
using std::set;
using std::string;
using std::pair;
using std::cin;
using std::cout;
using std::cerr;
// @author: pashka
vector<vector<int>> g;
vector<int> p;
vector<int> d[2];
int rand()
{
seed = 1726391263971263 * seed + 1729316729316293162;
seed ˆ= seed >> 24;
return (int) (seed & 0x7fffffff);
}
int main()
{
std::freopen("../tests/11", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
std::ios::sync_with_stdio(false);
int tn;
cin >> tn;
for (int tt = 0; tt < tn; tt++)
{
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 319
int n;
cin >> n;
g.clear();
g.resize(n);
for (int i = 0; i < n - 1; i++)
{
int x, y;
cin >> x >> y;
x--;
y--;
g[x].push_back(y);
g[y].push_back(x);
}
d[0].clear();
d[1].clear();
int j = 0;
p.clear();
p.resize(n);
for (int i = 2; i <= n; i += 2)
{
p[d[0][j++]] = i;
}
for (int i = 1; i <= n; i += 2)
{
p[d[0][j++]] = i;
}
if (w[x] > 0)
bd.insert({w[x], x});
}
int c = 0;
while (bd.size() > 0)
{
c++;
if (c > 100 * n)
{
break;
}
//if (c % 100 == 0)
//{
// cerr << bd.size() << "\n";
//}
int x = bd.rbegin()->second;
int xx = rand() % n;
while ((xx == x) || (p[x] % 2 != p[xx] % 2))
{
xx = rand() % n;
}
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 320
std::swap(p[x], p[xx]);
for (int v : {x, xx})
{
for (int u : g[v])
{
if (gcd(p[v], p[u]) > 1)
{
bd.erase({w[v], v});
bd.erase({w[u], u});
w[v]++;
w[u]++;
bd.insert({w[v], v});
bd.insert({w[u], u});
}
}
}
}
return 0;
}
124
insert
swap(a, b);
}
return a;
}
int n;
vi e[maxn];
int l[maxn];
int sc;
void scan()
{
cin >> n;
forn(i, n) e[i].clear();
forn(i, n-1)
{
int u, v;
cin >> u >> v;
--u, --v;
e[u].emplace_back(v);
e[v].emplace_back(u);
}
forn(i, n) sort(all(e[i]));
forn(i, n) l[i] = i+1;
}
bool pr[maxn];
void erath()
{
pr[0] = pr[1] = false;
for (int i = 2; i < maxn; ++i) if (!pr[i])
{
if ((i64)i*i > maxn) break;
for (int j = i*i; j < maxn; j += i) pr[j] = true;
}
}
mt19937 rr;
// mt19937 rr{random_device{}()};
int getScore()
{
int sc = 0;
forn(v, n) for (int to: e[v]) if (to < v && gcd(l[v], l[to]) > 1) ++sc;
return sc;
}
bool iter()
{
int x = rr() % n;
int y = x;
while (y == x) y = rr() % n;
ld perTest;
ld limit;
bool TL()
{
static int iter = 0;
if (++iter == 100)
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 322
{
iter = 0;
if (1.0 * clock() / CLOCKS_PER_SEC > limit)
{
return true;
}
}
return false;
}
int T;
void solve()
{
// shuffle(l, l+n, rr);
forn(i, n) cout << l[i] << " "; cout << endl;
}
int main()
{
std::freopen("../tests/11", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
erath();
int t;
cin >> t;
T = t;
forn(i, t)
{
scan();
limit = 1.0 * clock() / CLOCKS_PER_SEC + perTest;
solve();
}
// fill();
#ifdef LOCAL
cerr << "Time elapsed: " << clock() / 1000 << " ms" << endl;
#endif
return 0;
}
using std::vector;
using std::map;
using std::set;
using std::string;
using std::pair;
using std::cin;
using std::cout;
using std::cerr;
// @author: pashka
vector<vector<int>> g;
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 323
vector<int> p;
vector<int> d[2];
int rand()
{
seed = 1726391263971263 * seed + 1729316729316293162;
seed ˆ= seed >> 24;
return (int) (seed & 0x7fffffff);
}
int main()
{
std::freopen("../tests/11", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
std::ios::sync_with_stdio(false);
int tn;
cin >> tn;
for (int tt = 0; tt < tn; tt++)
{
int n;
cin >> n;
g.clear();
g.resize(n);
for (int i = 0; i < n - 1; i++)
{
int x, y;
cin >> x >> y;
x--;
y--;
g[x].push_back(y);
g[y].push_back(x);
}
while (true)
{
d[0].clear();
d[1].clear();
dfs(rand() % n, -1, 0);
if (d[0].size() < d[1].size())
{
swap(d[0], d[1]);
}
d[0].insert(d[0].end(), d[1].begin(), d[1].end());
// cerr << d[0].size() << " " << d[1].size() << "\n";
int j = 0;
p.clear();
p.resize(n);
for (int i = 2; i <= n; i += 2)
{
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 324
p[d[0][j++]] = i;
}
for (int i = 1; i <= n; i += 2)
{
p[d[0][j++]] = i;
}
int c = 0;
while (bd.size() > 0)
{
c++;
if (c > 500 * n)
{
break;
}
if (c % 100 == 0)
{
// cerr << bd.size() << "\n";
}
int x = bd.rbegin()->second;
int xx = rand() % n;
while ((xx == x) || (p[x] % 2 != p[xx] % 2))
{
xx = rand() % n;
}
std::swap(p[x], p[xx]);
if (!bd.empty())
{
cerr << "retry\n";
continue;
}
return 0;
}
int n;
vi e[maxn];
int l[maxn];
int sc;
void scan()
{
cin >> n;
forn(i, n) e[i].clear();
forn(i, n-1)
{
int u, v;
cin >> u >> v;
--u, --v;
e[u].emplace_back(v);
e[v].emplace_back(u);
}
forn(i, n) sort(all(e[i]));
forn(i, n) l[i] = i+1;
}
bool pr[maxn];
void erath()
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 326
{
pr[0] = pr[1] = false;
for (int i = 2; i < maxn; ++i) if (!pr[i])
{
if ((i64)i*i > maxn) break;
for (int j = i*i; j < maxn; j += i) pr[j] = true;
}
}
mt19937 rr;
// mt19937 rr{random_device{}()};
set<pii> bad;
vector<pii> badq;
void fillbad()
{
forn(v, n) for (int to: e[v]) if (to < v && gcd(l[v], l[to]) > 1)
{
bad.emplace(to, v);
badq.emplace_back(to, v);
}
}
bool iter2()
{
if (bad.empty())
{
assert(sc == 0);
return true;
}
int id = rr() % badq.size();
while (!bad.count(badq[id]))
{
swap(badq[id], badq.back());
badq.pop_back();
id = rr() % badq.size();
}
int x;
if (rr() % 2) x = badq[id].first;
else x = badq[id].second;
int y = x;
while (gcd(l[y], l[v]) > 1) y = rr() % n;
int cur = 0;
for (int to: e[x]) cur += gcd(l[x], l[to]) > 1;
for (int to: e[y]) cur += gcd(l[y], l[to]) > 1;
if (binary_search(all(e[x]), y)) cur -= gcd(l[x], l[y]) > 1;
int nxt = 0;
for (int to: e[x]) nxt += gcd(l[y], l[to]) > 1;
for (int to: e[y]) nxt += gcd(l[x], l[to]) > 1;
if (binary_search(all(e[x]), y)) nxt -= gcd(l[x], l[y]) > 1;
sc += nxt - cur;
for (int t: e[x]) if (gcd(l[x], l[t]) > 1)
bad.erase({min(t, x), max(t, x)});
swap(l[x], l[y]);
return true;
}
bool iter()
{
int x = rr() % n;
int y = x;
while (y == x) y = rr() % n;
int cur = 0;
for (int to: e[x]) cur += gcd(l[x], l[to]) > 1;
for (int to: e[y]) cur += gcd(l[y], l[to]) > 1;
if (binary_search(all(e[x]), y)) cur -= gcd(l[x], l[y]) > 1;
int nxt = 0;
for (int to: e[x]) nxt += gcd(l[y], l[to]) > 1;
for (int to: e[y]) nxt += gcd(l[x], l[to]) > 1;
if (binary_search(all(e[x]), y)) nxt -= gcd(l[x], l[y]) > 1;
int getScore()
{
int sc = 0;
forn(v, n) for (int to: e[v]) if (to < v && gcd(l[v], l[to]) > 1) ++sc;
return sc;
}
bool inq[maxn];
void fill()
{
memset(l, 0, sizeof l);
vi q;
forn(i, n) if (e[i].size() == 1) q.push_back(i), inq[i] = true;
shuffle(all(q), rr);
set<int> rem;
vi extra{1};
fore(i, 2, n)
{
if (!pr[i] && i > n/2) extra.push_back(i);
else rem.insert(i);
}
forn(i, n)
{
int v = q[i];
assert(l[v] == 0);
for (int to: e[v])
if (!inq[to])
q.push_back(to), inq[to] = true;
if (rem.empty())
{
l[v] = *extra.begin();
extra.erase(extra.begin());
continue;
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 328
if (ok)
{
l[v] = x;
rem.erase(x);
done = true;
break;
}
}
if (done) break;
}
if (!done)
{
if (!extra.empty())
{
l[v] = *extra.begin();
extra.erase(extra.begin());
}
else
{
l[v] = *rem.begin();
rem.erase(rem.begin());
}
}
}
// forn(i, n) cout << l[i] << " "; cout << endl;
cerr << getScore() << endl;
// cerr << rem.size() << endl;
// cerr << set<int>(l, l+n).size() << endl;
}
int T;
void solve()
{
// fill();
// return;
shuffle(l, l+n, rr);
sc = getScore();
// fillbad();
// cerr << "n = " << n << endl;
// cerr << "start sc: " << sc << endl;
forn(i, 1000 / T)
//forn(i, 10000000 / T) // depaseste timpul !
{
if (iter())
{
// cerr << i << " " << sc << endl;
}
// if (iter2())
//{
// cerr << i << " " << sc << endl;
// }
if (sc == 0) break;
}
// cerr << "end sc: " << sc << endl;
// cerr << endl;
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 329
forn(i, n)
cout << l[i] << " "; cout << endl;
// cout << sc << endl;
}
int main()
{
std::freopen("../tests/11", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
erath();
int t;
cin >> t;
T = t;
forn(i, t)
{
scan();
solve();
}
// fill();
return 0;
}
int n;
vi e[maxn];
int l[maxn];
int sc;
void scan()
{
cin >> n;
forn(i, n) e[i].clear();
forn(i, n-1)
{
int u, v;
cin >> u >> v;
--u, --v;
e[u].emplace_back(v);
e[v].emplace_back(u);
}
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 330
forn(i, n) sort(all(e[i]));
forn(i, n) l[i] = i+1;
}
bool pr[maxn];
void erath()
{
pr[0] = pr[1] = false;
for (int i = 2; i < maxn; ++i) if (!pr[i])
{
if ((i64)i*i > maxn) break;
for (int j = i*i; j < maxn; j += i) pr[j] = true;
}
}
mt19937 rr;
// mt19937 rr{random_device{}()};
int getScore()
{
int sc = 0;
forn(v, n)
for (int to: e[v])
if (to < v && gcd(l[v], l[to]) > 1)
++sc;
return sc;
}
bool iter()
{
int x = rr() % n;
int y = x;
while (y == x) y = rr() % n;
ld perTest;
ld limit;
bool TL()
{
static int iter = 0;
if (++iter == 100)
{
iter = 0;
if (1.0 * clock() / CLOCKS_PER_SEC > limit)
{
return true;
}
}
return false;
}
int T;
void solve()
{
shuffle(l, l+n, rr);
sc = getScore();
while (!TL())
{
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 331
iter();
if (sc == 0) break;
}
forn(i, n)
cout << l[i] << " ";
cout << endl;
}
int main()
{
std::freopen("../tests/11", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
erath();
int t;
cin >> t;
T = t;
perTest = 7.0 / T;
forn(i, t)
{
scan();
limit = 1.0 * clock() / CLOCKS_PER_SEC + perTest;
solve();
}
// fill();
return 0;
}
mt19937 rnd(42);
int n;
vector<int> g[N];
int best_ans;
vector<int> ans;
{
if (u != f)
{
dfs(u, res, ptr, v);
}
}
}
void upd_dfs(int v)
{
for (int i = 0; i < n; i++)
{
shuffle(g[i].begin(), g[i].end(), rnd);
}
int ptr = 1;
vector<int> res(n);
dfs(v, res, ptr);
upd(res);
}
void upd_deg()
{
vector<int> divisors(n + 1);
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= n; j += i)
{
divisors[j]++;
}
}
sort(ord.begin(), ord.end(),
[&] (int x, int y)
{
return make_pair(divisors[x], x) > make_pair(divisors[y], y);
});
sort(vert.begin(), vert.end(),
[&] (int x, int y)
{
return (int) g[x].size() > (int) g[y].size();
});
vector<int> res(n);
for (int v : vert)
{
res[v] = ord.back();
ord.pop_back();
}
upd(res);
}
void solve()
{
cin >> n;
for (int i = 0; i <= n; i++)
{
g[i].clear();
}
ans.resize(n);
for (int i = 0; i < n; i++)
{
ans[i] = i + 1;
}
shuffle(ans.begin(), ans.end(), rnd);
best_ans = N;
upd(ans);
upd_dfs(0);
for (int iter = 0; iter < min(n, 300); iter++)
{
upd_dfs(rnd() % n);
}
upd_deg();
int main()
{
std::freopen("../tests/11", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
int main()
//int main(int argc, char *argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/11",
(char*)"../tests/11.a",
CAPITOLUL 10. EJOI 2018 10.4. PRIME TREE 334
(char*)"prime-tree.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
registerTestlibCmd(argc, argv);
#ifdef PCMS2
// PCMS on EJOI needed some extra info in the input for partial scoring \
with groups
inf.readWord();
#endif
int tn = inf.readInt();
int m = 0;
int x = 0;
vector<int> l(n);
map<int, int> occurred;
forn(i, n)
{
l[i] = ouf.readInt(1, n, format("test #%d, label of vertex #%d", tt + 1, i +
1));
if (occurred.count(l[i]))
{
quitf(_wa, "test #%d: label %d is duplicated on vertexes %d and %d",
tt + 1, l[i] + 1, occurred[l[i]] + 1, i + 1);
}
occurred[l[i]] = i;
}
forn(i, n-1)
{
x += gcd(l[u[i]], l[v[i]]) != 1;
}
m += n - 1;
}
{
quitp(grade.second, "X=%d, M=%d, R=%.4f", x, m, score);
}
}
}
assert(false);
}
Output
If it’s impossible to sort the array using cycles of total length not exceeding s, print a single
number “-1” (quotes for clarity).
Otherwise, print a single number q— the minimum number of operations required to sort the
array.
On the next 2q lines print descriptions of operations in the order they are applied to the array.
The description of i-th operation begins with a single line containing one integer k (1 & k & n)—
the length of the cycle (that is, the number of selected indices). The next line should contain k
distinct integers i1 , i2 , . . . , ik (1 & ij & n)—the indices of the cycle.
The sum of lengths of these cycles should be less than or equal to s, and the array should be
sorted after applying these q operations.
If there are several possible answers with the optimal q, print any of them.
Constraints
***
Subtasks
Subtask 1 (5 points) n, s & 2 and all elements of the array are either 1 or 2.
Subtask 2 (5 points) n & 5.
Subtask 3 (5 points) All elements of the array are either 1 or 2.
Subtask 4 (10 points) Array contains numbers from 1 to n only, each number appears
exactly once, s 2 n.
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 336
Subtask 5 (10 points) Array contains numbers from 1 to n only, each number appears
exactly once, n & 1000.
Subtask 6 (15 points) Array contains numbers from 1 to n only, each number appears
exactly once.
Example
standard input standard output
55 1
32311 5
14235
4 3 -1
2 143
2 0 0
2 2
6 9 2
6 54321 6
1 62534
3
3 21
68 3
654321 2
3 4
4
1 625
2
2 1
Comment ¯ Note
In the first example, it’s also possible to sort the array with two operations of total length 5:
first apply the cycle 1 4 1 (of length 2), then apply the cycle 2 3 t 2 (of length
3). However, it would be wrong answer as you’re asked to use the minimal possible number of
operations, which is 1 in that case.
In the second example, it’s possible to the sort the array with two cycles of total length 4
(1 2 1 and 3 4 3). However, it’s impossible to achieve the same using shorter cycles,
which is required by s 3.
In the third example, the array is already sorted, so no operations are needed. Total length of
empty set of cycles is considered to be zero.
Notice that examples 1 and 3 contain duplicate numbers, so they do not satisfy requirements
for subtasks 4, 5 and 6. Examples 2, 4, and 5 satisfy requirements for subtasks 5 and 6.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 512 MB
https://codeforces.com/blog/entry/60920
https://codeforces.com/topic/61265/en10
Let’s solve an array if a is permutation and the sum of cycle sizes is unlimited.
125
It’s known that each permutation is composition of some non-intersecting cycles.
If permutation is sorted answer is 0.
125
https://en.wikipedia.org/wiki/Cyclic_permutation
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 337
If permutation is 1 cycle and some fixed indexes answer is 1, you should take this cycle to get
this answer.
If permutation is composition of ' 2 cycles answer should be ' 2, because it’s impossible to
use 1 cycle. In this case it’s possible to make the answer with 2 cycles.
Let’s define inversed permutation for our permutation as composition of this cycles p11
p12 ... p1k1 p11 , ..., pm1 pm2 ... pmkm pm1 (all cycles, except cycles with
length 1).
We can sort permutations using this 2 cycles: p11 p12 ... p1k1 p21 ... pm1
pm2 ... pmkm p11 (all cycles, written in a row) and pm1 p m11 ...p11 pm1 (first
elements of cycles in inversed order).
This solution used sum of cycle sizes t m, there t - number of non-fixed elements and m -
number of cycles with size 1.
Now let’s solve problem for permutation, if we can use sum of cycle sizes & s.
Each solution should use sum of cycle sizes ' t, because we should shift each non-fixed element.
So if s $ t answer is 1.
Let’s call each cycle from m cycles bad, if each of it’s element shifted exactly 1 time in the
answer. It can be proved, that each bad cycle should be used in the answer.
Let’s define x as number of bad cycles and y number of other cycles. So x y m.
Sum of cycles in the answer ' t y.
So, t y & s ==¿ y & s t ==¿ x my ' m t s.
Number of cycles in the answer ' x min y, 2.
It’s true, because each of x bad cycles are in answer and other y cycles can be sorted using
' min y, 2 cycles. We should take x as maximal as possible, because if we increase x by 1
sum min y, 2 x won’t increase. Minimal x, that we can use is max 0, m t s. So we get
y m max 0, m t s m min s t m, 0 min s t, 0 s t (because s ' t).
So answer in this case if max 0, m t s min s t, 2.
We can build it, if we use x max 0, m t s any of m cycles, and for other y s t cycles
do same construction as in previous case.
Let’s solve problem for array.
Let’s define b as sorted array a and t as count of 1 & i & n, such that ai j bi .
Our solution will sort some permutation p, such that api bi , for all i.
Answer for permutation is max 0, m t s min s t, 2.
In this formula s and t are fixed. So to minimize the answer we should minimize m. So we
should sort array using array with as minimal as possible number of cycles. To do it let’s build
directed graph: vertexes is number in array, let’s add edge from ai to bi for all i, such that ai j bi .
It’s easy to see, that we should take euler cycle in each component of this graph and build
permutation with this cycles to make number of cycles in permutation as minimal as possible.
To code this solution without building graph let’s take first any sorting permutation. After
that, we can merge cycles. If ai aj and i and j in different cycles of permutation, we can merge
this cycles using swap pi , pj .
126
So let’s merge all possible cycles using DSU for components.
Time complexity: O n log n.
Jury’s solution (by isaf27): 40973023
(https://codeforces.com/contest/1012/submission/40973023)
#define se second
#define fi first
#define forn(i, n) for (int i = 0; i < n; i++)
#define sz(a) (int)a.size()
#define mp make_pair
126
https://cp-algorithms.com/data_structures/disjoint_set_union.html
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 338
int main()
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
iostream::sync_with_stdio(0);
sort(pq.begin(), pq.end());
int m = -1;
forn (i, n)
{
if (i == 0 || pq[i].fi != pq[i - 1].fi)
{
m++;
}
a[pq[i].se] = m;
b.push_back(m);
}
forn (i, n)
{
if (a[i] != b[i])
{
e[a[i]].push_back(b[i]);
ce[a[i]].push_back(i);
}
}
int csum = 0;
forn (i, m + 1)
{
if (use[i] == 0 && sz(e[i]))
{
vv.push_back(vector<int> (0));
dfs(i, -1);
csum += sz(vv.back());
}
}
if (ct > 1)
{
int sm1 = 0;
forn (i, ct)
{
sm1 += sz(vv[i]);
}
cout << sm1 << "\n";
vector<int> cpq;
forn (i, ct)
{
for (int v : vv[i])
cout << v + 1 << " ";
cpq.push_back(vv[i][0]);
}
cout << "\n";
cout << sz(cpq) << "\n";
reverse(cpq.begin(), cpq.end());
for (int v : cpq) cout << v + 1 << " ";
}
if (ct > 1)
for (int j = ct; j < sz(vv); j++)
{
cout << sz(vv[j]) << "\n";
for (int q : vv[j]) cout << q + 1 << " ";
cout << "\n";
}
else
for (int j = 0; j < sz(vv); j++)
{
cout << sz(vv[j]) << "\n";
for (int q : vv[j]) cout << q + 1 << " ";
cout << "\n";
}
return 0;
}
if (sz(vv) == 0)
{
cout << "0";
return 0;
}
if (sz(vv) == 1)
{
cout << "1\n";
}
else
cout << "2\n";
if (sz(vv) > 1)
{
cout << "\n" << sz(vv) << "\n";
vector<int> cpq;
forn (j, sz(vv)) cpq.push_back(vv[j][0]);
reverse(cpq.begin(), cpq.end());
for (int v : cpq) cout << v + 1 << " ";
}
}
int a[MX];
int b[MX];
int val[MX];
bool was[MX];
bool bad[MX];
vector<int> gr[MX];
class TDisjointSetsUnion
{
public:
TDisjointSetsUnion(size_t size)
: parent(size, size)
, rank(size, 1)
{
}
{
throw std::out_of_range("DSU error!");
}
u = GetParent(u);
v = GetParent(v);
if (u == v)
{
return;
}
if (rank[u] < rank[v])
{
std::swap(u, v); // smaller-to-larger heuristics
}
rank[u] += rank[v];
parent[v] = u;
}
private:
mutable std::vector<size_t> parent;
std::vector<size_t> rank;
int main()
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, k;
cin >> n >> k;
vector<pair<int, int> > perestanovocka;
vector<int> comp;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
comp.push_back(a[i]);
b[i] = a[i];
}
sort(b + 1, b + 1 + n);
vector<int> BADS;
for (int i = 1; i <= n; i++)
{
if (a[i] != b[i])
{
BADS.push_back(i);
bad[i] = true;
}
}
if (is_sorted(a + 1, a + 1 + n))
{
cout << 0 << "\n";
return 0;
}
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 342
sort(comp.begin(), comp.end());
sort(perestanovocka.begin(), perestanovocka.end());
if (last == -1)
{
cyc.push_back(pos);
}
else
if (!dsu.AreInSameSet(last, pos))
{
cyc.push_back(pos);
dsu.Join(last, pos);
}
last = pos;
}
applyCyc(cyc);
}
int more = k;
for (const auto& cyc : cycs)
{
more -= cyc.size();
}
if (more < 0)
{
cout << -1 << "\n";
return 0;
}
cycs = findCycs(n);
return 0;
}
mt19937 rnd(228);
while (!u[x])
{
p.push_back(x);
u[x] = 1;
x = a[x];
}
b.push_back(p);
}
int sum = 0;
for (auto c : b)
{
sum += c.size();
}
if (sum > s)
{
return 1e9;
}
s -= sum;
int hv = 0;
for (int i = 3; i <= (int) b.size(); i++)
{
if (s >= i)
{
hv = i;
}
}
if (hv == 0)
{
return b.size();
}
else
{
return 2 + (int) b.size() - hv;
}
}
{
cout << b.size() << ’\n’;
for (auto c : b)
{
cout << c.size() << ’\n’;
for (int x : c)
{
cout << x + 1 << ’ ’;
}
cout << ’\n’;
}
}
else
{
cout << 2 + (int) b.size() - hv << ’\n’;
for (int i = hv; i < (int) b.size(); i++)
{
cout << b[i].size() << ’\n’;
for (int x : b[i])
{
cout << x + 1 << ’ ’;
}
cout << ’\n’;
}
int s = 0;
for (int i = 0; i < hv; i++) s += (int) b[i].size();
cout << s << ’\n’;
for (int i = 0; i < hv; i++)
{
for (int x : b[i])
{
cout << x + 1 << ’ ’;
}
cout << ’\n’;
}
cout << hv << ’\n’;
for (int i = hv - 1; i >= 0; i--)
{
cout << b[i][0] + 1 << ’ ’;
}
cout << ’\n’;
}
}
int par[N];
int get(int v)
{
if (v == par[v])
{
return v;
}
else
{
return par[v] = get(par[v]);
}
}
void dfs(int v)
{
vis[v] = true;
while (!g[v].empty())
{
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 346
int to = g[v].back().first;
int ind = g[v].back().second;
g[v].pop_back();
if (u[ind])
{
continue;
}
else
{
u[ind] = 1;
dfs(to);
}
}
cyc.push_back(v);
}
int main()
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
int n, s;
cin >> n >> s;
vector <int> a(n), h(n), ind(n);
vector <int> p;
for (int i = 0; i < n; i++)
{
par[i] = i;
cin >> a[i];
ind[i] = i;
p.push_back(a[i]);
}
sort(p.begin(), p.end());
p.resize(unique(p.begin(), p.end()) - p.begin());
sort(ind.begin(), ind.end(), [&] (int x, int y)
{
return a[x] < a[y];
});
for (int i = 0; i < n; i++)
{
a[i] = lower_bound(p.begin(), p.end(), a[i]) - p.begin();
}
vector <int> perm(n);
map <pair <int, int>, vector <int> > v;
for (int i = 0; i < n; i++)
{
int x = a[i], y = a[ind[i]];
if (x != y)
{
g[y].push_back({x, i});
v[{x, y}].push_back(i);
}
else
{
perm[i] = i;
}
}
for (int i = 0; i < (int) p.size(); i++)
{
if (!vis[i])
{
cyc.clear();
dfs(i);
cyc.pop_back();
vector <int> ret;
for (int i = 0; i < (int) cyc.size(); i++)
{
int x = cyc[i], y = cyc[(i + 1) % ((int) cyc.size())];
ret.push_back(v[{x, y}].back());
v[{x, y}].pop_back();
}
for (int i = 0; i < (int) ret.size(); i++)
{
int j = (i - 1 + (int) ret.size()) % ((int) ret.size());
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 347
perm[ret[i]] = ret[j];
}
}
}
print(n, s, perm);
}
int t;
bool used[M];
vector<int> c[M];
void dfs(int x)
{
used[x] = true;
c[t].push_back(x);
if (!used[p[x]]) dfs(p[x]);
}
int main()
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
ios::sync_with_stdio(0);
cin >> n >> s;
for (int i = 0; i < n; i++)
{
cin >> a[i];
b[i] = make_pair(a[i], i);
}
sort(b, b + n);
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 348
int t;
bool used[M];
vector<int> c[M];
void dfs(int x)
{
used[x] = true;
c[t].push_back(x);
if (!used[p[x]]) dfs(p[x]);
}
int main()
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
int ls = -1;
for (int i = 0; i < n; i++)
{
if (p[b[i].second] == b[i].second) continue;
if (ls >= 0 && a[ls] == a[b[i].second])
{
int x = ls;
int y = b[i].second;
if (is_connect(x, y)) continue;
merge_set(x, y);
swap(p[x], p[y]);
}
ls = b[i].second;
}
t = 0;
for (int i = 0; i < n; i++)
if (!used[i] && p[i] != i)
{
dfs(i);
t++;
}
int kol = 0;
for (int i = 0; i < t; i++)
kol += (int)c[i].size();
if (kol > s)
{
cout << "-1";
return 0;
}
s -= kol;
s = min(s, t);
if (s <= 1)
{
cout << t << endl;
for (int i = 0; i < t; i++)
{
cout << c[i].size() << endl;
for (int x : c[i])
cout << (x + 1) << " ";
cout << endl;
}
return 0;
}
cout << (t - s + 2) << endl;
for (int i = 0; i < t - s; i++)
{
cout << c[i + s].size() << endl;
for (int x : c[i + s])
cout << (x + 1) << " ";
cout << endl;
kol -= (int)c[i + s].size();
}
cout << kol << endl;
for (int i = 0; i < s; i++)
for (int x : c[i])
cout << (x + 1) << " ";
cout << endl;
cout << s << endl;
for (int i = s - 1; i >= 0; i--)
cout << (c[i][0] + 1) << " ";
cout << endl;
return 0;
}
int t;
bool used[M];
vector<int> c[M];
void dfs(int x)
{
used[x] = true;
c[t].push_back(x);
if (!used[p[x]]) dfs(p[x]);
}
int main()
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
ios::sync_with_stdio(0);
sort(b, b + n);
init();
for (int i = 0; i < n; i++) merge_set(p[i], i);
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 352
int ls = -1;
for (int i = 0; i < n; i++)
{
if (p[b[i].second] == b[i].second) continue;
if (ls >= 0 && a[ls] == a[b[i].second])
{
int x = ls;
int y = b[i].second;
if (is_connect(x, y)) continue;
merge_set(x, y);
swap(p[x], p[y]);
}
ls = b[i].second;
}
t = 0;
for (int i = 0; i < n; i++)
if (!used[i] && p[i] != i)
{
dfs(i);
t++;
}
int kol = 0;
for (int i = 0; i < t; i++)
kol += (int)c[i].size();
if (kol > s)
{
cout << "-1";
return 0;
}
s -= kol;
s = min(s, t);
if (s <= 1)
{
cout << t << "\n";
for (int i = 0; i < t; i++)
{
cout << c[i].size() << "\n";
for (int x : c[i])
cout << (x + 1) << " ";
cout << "\n";
}
return 0;
}
cout << (t - s + 2) << "\n";
for (int i = 0; i < t - s; i++)
{
cout << c[i + s].size() << "\n";
for (int x : c[i + s])
cout << (x + 1) << " ";
cout << "\n";
kol -= (int)c[i + s].size();
}
return 0;
}
// https://codeforces.com/contest/1012/submission/41148878
// https://codeforces.com/contest/1012/status/E
int get(int x)
{
return f[x]?f[x]=get(f[x]):x;
}
int main()
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
n=read(),
s=read();
fo(i,1,n)
a[i]=read(),
b[i]=make_pair(a[i],i);
sort(b+1,b+1+n);
fo(i,1,n) p[b[i].second]=i;
fo(i,1,n)
if (a[i]==b[i].first&&p[i]!=i)
{
p[b[i].second]=p[i];
b[p[i]].second=b[i].second;
p[i]=i,b[i].second=i;
}
fo(i,1,n)
if (p[i]!=i) merge(p[i],i);
int x=0;
fo(i,1,n)
{
int y=b[i].second;
if (p[y]==y) continue;
if (a[x]==a[y])
{
if (get(x)==get(y)) continue;
merge(x,y);
swap(p[x],p[y]);
}
x=y;
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 354
fo(i,1,n)
if (p[i]!=i&&!bz[i])
{
cnt++,x=i;
for(;!bz[x];x=p[x])
sum++,
bz[x]=1,
an[cnt].push_back(x);
}
if (s<sum)
return puts("-1"),0; // ... !!!
s-=sum;
s=min(s,cnt);
if (s<=2)
{
printf("%d\n",cnt);
fo(i,1,cnt)
{
printf("%d\n",an[i].size());
for(j=0;j<an[i].size();j++)
printf("%d ",an[i][j]);
puts("");
}
return 0;
}
printf("%d\n",cnt-s+2);
fo(i,1,cnt-s)
{
printf("%d\n",an[i].size());
for(j=0;j<an[i].size();j++)
printf("%d ",an[i][j]);
sum-=an[i].size();
puts("");
}
printf("%d\n",sum);
fo(i,cnt-s+1,cnt)
for(j=0;j<an[i].size();j++)
printf("%d ",an[i][j]);
puts("");
printf("%d\n",s);
fd(i,cnt,cnt-s+1)
printf("%d ",an[i][0]);
puts("");
}
namespace IO
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 355
{
const uint32 Buffsize=1<<15,Output=1<<23;
static char Ch[Buffsize],*S=Ch,*T=Ch;
for(tp=0;x;x/=10)
sta[++tp]=x%10;
for(;tp;*nowps++=sta[tp--]ˆ48);
*nowps++ = ch;
}
}
namespace DSU
{
static int fa[MAXN];
return u==fa[u]?u:fa[u]=Find(fa[u]);
}
write(sm);
}
else
if(!fg)
{
int x=u;
do
{
++tt;
x=nx[x];
} while(uˆx);
return;
}
int x=u;
do
{
write(x,’ ’);
x=nx[x];
}while(uˆx);
}
Rep(i,1,n)
ps[a[i].id]=i;
static int u;
Rep(i,1,n)
if(nx[i]==i)
{
u=i;
while(1)
{
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 357
nx[u]=ps[u];
if(ps[u]==i)break;
u=ps[u];
DSU::merge(u,i);
}
if(nx[i]==i)
DSU::fa[i]=0,++s;
}
while(j<n&&a[j+1].x==a[i].x)
{
++j;
if(DSU::Find(a[j].id)==u||!DSU::fa[a[j].id])
continue;
swap(nx[a[i].id],nx[a[j].id]);
DSU::merge(a[i].id,a[j].id);
}
}
if(s<0)
return(void)puts("-1");
Rep(i,1,n)
if(DSU::fa[i]==i)
nm[++tmp]=i;
write((s<=1||tmp<=1)?tmp:max(tmp+2-s,2));
if(s<=1||tmp<=1)
Rep(i,1,tmp)
dfs(nm[i]),
*nowps++=’\n’;
else
{
u=min(s,tmp);
Rep(i,1,u)
dfs(nm[i],0);
write(tt);
Rep(i,1,u)
dfs(nm[i],-1);
*nowps++ = ’\n’;
write(u);
Repe(i,u,1)
write(nm[i],i==1?’\n’:’ ’);
Rep(i,u+1,tmp)
dfs(nm[i]),
*nowps++ = ’\n’;
}
flush();
}
int main()
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
init();
solve();
return 0;
}
// https://codeforces.com/contest/1012/status/E
char buf[25];
const int maxn=200010;
struct node
{
int w,id;
} c[maxn],d[maxn];
vector<int>v[maxn];
int a[maxn],b[maxn],f[maxn],q[maxn];
bool p[maxn];
int n,m,s,ans;
int read()
{
int x=0,f=0;
char ch=getchar();
while(ch<’0’||ch>’9’)
{
if(ch==’-’) f=1;
ch=getchar();
}
while(ch>=’0’&&ch<=’9’)
{
x=(x<<1)+(x<<3)+(chˆ48);
ch=getchar();
}
return f?-x:x;
}
void write(int x)
{
if(!x){ putchar(’0’); return;}
if(x<0){putchar(’-’); x=-x;}
int cnt=0;
while(x)
{
buf[++cnt]=’0’+x%10;
x/=10;
}
drp(i,cnt,1)
putchar(buf[i]);
}
int find(int x)
{
if(f[x]!=x)
f[x]=find(f[x]);
return f[x];
}
int main()
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 359
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
n=read();
s=read();
rep(i,1,n)
{
a[i]=b[i]=read();
}
sort(b+1,b+1+n);
rep(i,1,n)
if(a[i]!=b[i])
{
++m;
c[m]=d[m]=(node){a[i],i};
}
if(m>s)
{
puts("-1");
return 0;
}
sort(d+1,d+1+m,cmp);
rep(i,1,m)
f[c[i].id]=c[i].id;
rep(i,1,m)
unions(d[i].id,c[i].id);
rep(i,2,m)
if(d[i].w==d[i-1].w&&find(d[i].id)!=find(d[i-1].id))
{
swap(d[i],d[i-1]);
unions(d[i].id,d[i-1].id);
}
rep(i,1,m)
q[d[i].id]=c[i].id,
p[d[i].id]=true;
rep(i,1,m)
{
int x=c[i].id;
if(p[x])
{
++ans;
while(p[x])
{
p[x]=false;
v[ans].push_back(x);
x=q[x];
}
}
}
int num=min(ans,s-m);
if(num>2)
{
write(ans-(num-2));
putchar(’\n’);
int sum=0;
rep(i,1,num) sum+=v[i].size();
write(sum);
putchar(’\n’);
rep(i,1,num)
{
rep(j,0,v[i].size()-1)
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 360
{
write(v[i][j]);
if(i!=num||j!=v[i].size()-1)
putchar(’ ’);
else
putchar(’\n’);
}
}
write(num);putchar(’\n’);
drp(i,num,1)
{
write(v[i][0]);
if(i!=1)
putchar(’ ’);
else
putchar(’\n’);
}
rep(i,num+1,ans)
{
write(v[i].size());
putchar(’\n’);
rep(j,0,v[i].size()-1)
{
write(v[i][j]);
if(j!=v[i].size()-1)
putchar(’ ’);
else
putchar(’\n’);
}
}
}
else
{
write(ans);
putchar(’\n’);
rep(i,1,ans)
{
write(v[i].size());
putchar(’\n’);
rep(j,0,v[i].size()-1)
{
write(v[i][j]);
if(j!=v[i].size()-1)
putchar(’ ’);
else
putchar(’\n’);
}
}
}
return 0;
}
using std::vector;
int nxt(int x)
{
while (nt[x]<t[x+1] && a[nt[x]]==x) nt[x]++;
return nt[x];
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 361
void dfs(int x)
{
while (nxt(x)<t[x+1])
{
int tt=nt[x];
dfs(a[nt[x]++]);
ans[now].push_back(tt);
}
}
void out(int i)
{
for (auto j:ans[i]) printf("%d ",j);
puts("");
}
int main()
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
scanf("%d%d",&n,&s);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),
b[i]=a[i];
std::sort(b+1,b+n+1);
t[cnt+1]=n+1;
for (int i=1;i<=cnt;i++)
if (nxt(i)<t[i+1])
{
++now;
dfs(i);
s-=ans[now].size();
std::reverse(ans[now].begin(),ans[now].end());
}
if (s<0)
{
puts("-1");
return 0;
}
s=std::min(s,now);
if (s<2)
{
printf("%d\n",now);
for (int i=1;i<=now;i++)
{
printf("%d\n",ans[i].size());
out(i);
}
}
else
{
printf("%d\n",now-s+2);
int sum=0;
for (int i=1;i<=s;i++)
sum+=ans[i].size();
printf("%d\n",sum);
const ll MAXN=2e5+51;
vector<pii>g[MAXN];
vector<ll>res[MAXN];
ll n,m,len,p,tot,zkdxl,rr,cnt;
ll x[MAXN],y[MAXN],z[MAXN],vis[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!=’-’)
{
ch=getchar();
}
if(ch==’-’)
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-’0’);
ch=getchar();
}
return num*neg;
}
dfs(bk.first),
res[tot].push_back(bk.second);
}
}
int main()
{
std::freopen("../tests/180", "r", stdin);
std::freopen("prime-tree.out", "w", stdout);
n=read(),
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 363
m=read();
sort(y+1,y+n+1);
len=unique(y+1,y+n+1)-y-1;
if(p>m)
{
return puts("-1"),0;
}
if(!p)
{
return puts("0"),0;
}
if(tot<=1||m-p<=1)
{
printf("%d\n",tot);
for(register int i=1;i<=tot;i++)
{
printf("%d\n",res[i].size());
for(register int j:res[i])
{
printf("%d ",j);
}
puts("");
}
return 0;
}
rr=min(m-p,tot),
printf("%d\n%d\n",zkdxl=tot+2-rr,rr);
reverse(res+1,res+rr+1),printf("%d\n",cnt);
CAPITOLUL 10. EJOI 2018 10.5. CYCLE SORT 364
puts("");
for(register int i=rr+1;i<=tot;i++)
{
printf("%d\n",res[i].size());
for(register int j:res[i])
{
printf("%d ",j);
}
puts("");
}
}
int n, s;
vector<int> a_original;
vector<int> b = a_original;
int sum = 0;
for (int op_id = 0; op_id < q; op_id++)
{
int k = stream.readInt(1, n, format("k[%d]", op_id + 1).c_str());
sum += k;
if (sum > s)
{
stream.quitf(_wa,
"sum of length of cycles should be <= %d, \
but it’s %d after cycle #%d",
s, sum, op_id + 1);
}
vector<int> id;
set<int> id_occurred;
for (int x = 0; x < k; x++)
{
int p = stream.readInt(1, n, format("p[%d][%d]", \
op_id + 1, x + 1).c_str());
p--;
if (id_occurred.count(p))
{
stream.quitf(_wa,
"p[%d][%d]=%d occurs twice in the cycle", \
op_id + 1, x + 1, p + 1);
}
id_occurred.insert(p);
id.push_back(p);
}
void readinput()
{
n = inf.readInt();
s = inf.readInt();
a_original.resize(n);
for (int &x : a_original) x = inf.readInt();
}
int main()
//int main(int argc, char* argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/180",
(char*)"../tests/180.a",
(char*)"prime-tree.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
registerTestlibCmd(argc, argv);
readinput();
if (jans >= 0)
{
if (pans >= 0)
{
if (pans == jans) quitf(_ok, \
"OK, answer exists, pans = jans = %d", pans);
else
if (pans > jans) quitf(_wa, \
"jury found better answer, jans = %d < pans = %d",jans,pans);
else
if (pans < jans) quitf(_fail, \
"participant found better answer, jans = %d > pans = %d", \
jans, pans);
}
else
if (pans == -1)
quitf(_wa, "participant didn’t find answer, but answer exists");
}
else
{
if (pans >= 0)
quitf(_fail, "answer exists, but jury didn’t find");
else
quitf(_ok, "OK, no solution");
}
return 0;
}
11.1 Magic
Problema 1 - Magic 100 de puncte
Now is the English lesson in grade 9 with Mr. Daskalov. Our main character - Deni - is very
weak in English and she counts the number of flies in the room. This proves to be very boring
activity, so she looks at the board where the teacher has written some text. She ignores the spaces
between the words so the whole text seems to her as one big sequence of English letters with
length N . Let us denote the number of different characters in this sequence with K. Deni starts
to take up different substrings from this sequence and she writes down the number of times each
character occurs. When for all of the K letters these numbers are equal, she calls the current
substring magical.
Remarks: A substring is a part of a given string, which contains consecutively written charac-
ters.
During this English lesson she is able to check every substring of the sequence. Meanwhile
she has counted how many of the substrings are magical and in the end she is very happy with
the accomplished activity. Deni decides that she would like to do so in every English lesson. But
with every subsequent English lesson the text on the board written by Mr. Daskalov is becoming
longer and longer. So she asks for your help - you have to write a program which tells her the
number of magical substrings in a given sequence of N English letters.
Task
Write a program magic which counts the number of magical substrings in a given sequence
of N English letters. Substrings which are the same but on different positions are counted as
different
Input
From the first line of the standard input, your program has to read one integer N - the number
of characters in the sequence written by Mr. Daskalov. From the next line your program has to
read a string of N English letters. The letters can be lower- and uppercase. Note that the lower-
and uppercase forms of the same letter are considered to be different characters (A and a are
different characters).
Output
The program must print to the standard output the number of magical substrings in the given
string. Since this number may be quite large, you are required to print its remainder when divided
by 1 000 000 007.
Constraints
366
CAPITOLUL 11. EJOI 2017 11.1. MAGIC 367
Subtasks
Subtask Points N Further constraints
1 10 & 100 There are no further constraints.
2 20 & 2000 There are no further constraints.
3 30 & 100 000 There are only two kinds of characters in the given string (K 2).
4 40 & 100 000 There are no further constraints.
Examples
Sample Input Sample Explanation
Output
8 4 The magical substrings are abc, cba, abc and abccba.
abccbabc Note that for example the substring ab is not magical
because the letter c is not in it.
7 1 Only the substring abcABC is magical (the letters
abcABCC a and A are different because a is a lowercase letter
and A is an uppercase letter).
20 22 The number of magical substrings is 22 and one of
SwSSSwwwwSwSwwSwwwwS them is SwSwwS.
This task looks like a direct dynamic optimization problem but this is not correct. There have to
be made some important observations and after them the task becomes more straightforward.
The first subtask is for 10 points. No observations are needed to be made here - considering the
constraints it is enough for every substring to be viewed and to be counted how many times every
type of letter is met. Next the counts for every type of letter are checked and if they are all equal
3 2
then the current substring is counted in the answer. The expected complexity is O n kn .
The second subtask is for 20 points. Here the idea is to optimize what we did before. We
will remove the inner cycle - we will calculate the count for every type of letter for a current
substring in constant complexity. There are different ways to do that. The author precomputes
the prefix counts for every type of letter and with this the count for every type of letter for a
current substring can be calculated as a subtraction of prefix counts. So the complexity here is
2
O kn .
The third subtask is for 30 points. We have to make the first observation in the task which is
for an easier variant - when we only have two types of letters. Let we do the following change of the
letters in the string. We replace the first type of letters with the number +1 and the second type -
with the number -1 (negative 1). In this way our string becomes an array of numbers. The needed
substrings are with equal number of letters from the first and the second type i.e. the sum of the
numbers in the array in these positions would be 0 which means we are looking for subintervals
with 0 sum in the array. This task is solved easier than the original. Let we calculate the prefix
sums in the array pref (we have a fictive prefix sum in the beginning which is 0). The sum of a
subinterval of the array from x to y is pref y pref x 1. We want this to be 0 i.e. for a given
y the subintervals ending there with zero sum are with x-es for which pref x 1 pref y . To
solve the current subtask we can save how many prefix sums are there for every possible value of
a sum in the array cnt and for a current index ind the number of subintervals with the needed
property ending there are cntind. We add this to the value of the answer and then we need to
make the update: cntind . The complexity of the described procedure is linear - O n but
the solution for the whole task isn’t so here it can be made a solution with complexity O n log2 n.
The fourth subtask is for 40 points. The previous subtask was useful because the idea can be
adapted for the whole task. Let we fix two types of letters - a and b (these are only fictive and the
letters can be different). Let we save the number values in the array nums1 . Again in the same
way we replace the letters of type a with +1, we replace the letters of type b with -1 but for every
letter which is from a different type we replace it with the number 0. Let we take the second type
of letters - b and a new type of letters - c and we will save the numbers in a new array nums2 .
After we make the replacements and save the numbers using the described scheme we take c and
another different type of letters (for example d) and we again fill in an array nums3 and we do
this while we still have more unused types of letters. A substring that fulfills the requirement in
the statement is such that the sums of the numbers in the corresponding subintervals in the arrays
CAPITOLUL 11. EJOI 2017 11.1. MAGIC 368
nums1 , nums2 , ..., nums k1 are all zeroes. Now we can approach analogously as in the previous
subtask.
Here we have a problem - the array cnt which we used now has to have several numbers as a
parameter. We can use hashes which isn’t expected to be known by the competitors so the author’s
solution doesn’t use this despite providing complexity of O kn. We can use the data structure
map from STL but we have to predefine operator and there will be a big constant which will make
the solution slower. The author approaches in the following way. Let for every array numsi we
calculate the corresponding prefix array prefi . For every position i we can make this type of sets
Si rpref1 , pref2 , ..., prefn x. In reality we search for pairs of sets Sx and Sy (of course x $ y) for
which Sx Sy . Let we sort the sets Si . Now the equivalent sets are adjacent. Let we view all
groups of equivalent sets and their number is p and every group’s length is numi . The number of
< p1
all substrings which fulfill the requirement from the statement is i 1 numi numi 1. This is
easy to be calculated and solves the task for 100 points. The complexity of the described procedure
is O kn log2 n - this is the complexity of the sorting of the sets Si which is the dominating in the
solution.
The thing which shouldn’t be forgotten is that we have to make the calculations by the modulo
in the statement. In reality it turns out that the answer can’t be too big (the more types of
letters the small it gets) - using a convenient sample the maximal number for a given n and k is
k n & k &1
n
n
k
& n 1
k
2
which for the maximal constraints isn’t much bigger than the modulo.
The reason there is a modulo is for deception that the answer will be very big and to prevent the
competitors from doing cheat solutions.
The task is interesting because of the approach that the letters are replaced with numbers which
is the big step towards finding a solution with smaller complexity.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
struct H
{
int x1,x2;ull x3;
H(){}
H(int x1,int x2,ull x3):x1(x1),x2(x2),x3(x3){}
H operator + (H a)
{
return H((x1+a.x1)%mod1,
(x2+a.x2)%mod2,
x3+a.x3);
}
H operator - (H a)
{
return H((x1-a.x1+mod1)%mod1,
(x2-a.x2+mod2)%mod2,
x3-a.x3);
}
H operator * (H a)
{
CAPITOLUL 11. EJOI 2017 11.1. MAGIC 369
return H(1ll*x1*a.x1%mod1,
1ll*x2*a.x2%mod2,
x3*a.x3);}
bool operator == (H a)
{
return x1==a.x1&&x2==a.x2&&x3==a.x3;
}
bool operator < (H a)
{
if(x1!=a.x1) return x1<a.x1;
else
if(x2!=a.x2) return x2<a.x2;
else
return x3<a.x3;
}
};
int cnt[N];
H h[N],hsh[N],p[N];
H a[N];
int vis[N];
char s[N];
int ans;
int main()
{
std::freopen("../magic_tests/magic.20.in", "r", stdin); // 21636849
//std::freopen("magic.out", "w", stdout);
int i,j,n;
int mx;int l,r;
scanf("%d",&n);
scanf("%s",s+1);
p[0]=H(1,1,1);
rep(i,1,maxn) p[i]=p[i-1]*H(base,base,base);
rep(i,1,n)
{
hsh[i]=hsh[i-1]+p[s[i]];
}
rep(i,1,n) vis[s[i]]=’1’;
rep(i,’A’,’z’)
if(vis[i]) h[1]=h[1]+p[i];
rep(i,2,n) h[i]=h[i-1]+h[1];
a[0]=H(0,0,0);
rep(i,1,n)
{
cnt[s[i]]++;
mx=n;
rep(j,’A’,’z’) if(vis[j]) mx=min(mx,cnt[j]);
a[i]=hsh[i]-h[mx];
}
sort(a,a+1+n);
for(l=0;l<=n;l=r)
{
r=l;
while(a[r]==a[l]&&r<=n) r++;
ans=(ans+1ll*(r-l)*(r-l-1)/2)%mod;
}
printf("%d",ans);
}
#include <string>
#include <iostream>
CAPITOLUL 11. EJOI 2017 11.1. MAGIC 370
#include <algorithm>
int main()
{
std::freopen("../magic_tests/magic.20.in", "r", stdin); // 21636849
//std::freopen("magic.out", "w", stdout);
sort(v, v + n + 1);
int l = 0;
long long ret = 0;
for (int i = 1; i <= n + 1; i++)
{
if (i == n + 1 || v[i] != v[i - 1])
ret += 1LL * (i - l) * (i - l - 1) / 2, l = i;
}
return 0;
}
#include <bits/stdc++.h>
bool flag;
int H()
{
int m = MOD;
for (int i = 0; i < 52; i++)
{
if (used[i])
m = min(m, cnt[i]);
CAPITOLUL 11. EJOI 2017 11.1. MAGIC 371
if (m == 0)
flag = true;
int t = 0;
for (int i = 0; i < 52; i++)
{
if (used[i])
t = ((t * B) % MOD + cnt[i] - m) % MOD;
}
return t;
}
signed main()
{
std::freopen("../magic_tests/magic.20.in", "r", stdin); // 21636849
//std::freopen("magic.out", "w", stdout);
int i = 0;
for (char c = ’A’; c <= ’Z’; c++)
mp[(int)c] = i++;
unordered_map<int, int> m;
int N;
cin >> N;
string s;
cin >> s;
int total = 0;
for (char c : s)
used[mp[(int)c]] = true;
for (char c : s)
{
cnt[mp[(int)c]]++;
flag = false;
int tmp = H();
if (!tmp)
m[tmp]++;
if (!flag)
total = (total + m[tmp]) % 1000000007;
if (tmp)
m[tmp]++;
}
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<stdbool.h>
#include<limits.h>
#include<iostream>
int n, c[55];
bool vis[55];
ull v[100009];
char* t;
char s[100000];
int main()
{
std::freopen("../magic_tests/magic.20.in", "r", stdin); // 21636849
//std::freopen("magic.out", "w", stdout);
t = strdup("");
scanf("%d", &n);
scanf("%s", &s);
if(i < n)
{
char*pidx = strchr(t, s[i]);
int idx;
if(pidx)
idx = pidx - t;
else
idx=0;
c[idx]++;
}
}
int l = 0;
ll ret = 0;
for (int i = 1; i <= n + 1; i++)
{
if (i == n + 1 || v[i] != v[i - 1])
ret += 1LL * (i - l) * (i - l - 1) / 2, l = i;
}
return 0;
}
#include<cstdio>
#include<string>
#include<algorithm>
string s,t;
int main()
{
std::freopen("../magic_tests/magic.20.in", "r", stdin); // 21636849
//std::freopen("magic.out", "w", stdout);
int n,i,l=0,j,nr;
long long rasp=0;
char ch;
scanf("%d\n",&n);
for(i=1;i<=n;i++)
{
scanf("%c",&ch);
s=s+ch;
}
for(i=0;i<n;i++)
{
if (s[i]<=’Z’)
nr=s[i]-65;
else
nr=s[i]-71;
if (!viz[nr])
viz[nr]=1,t=t+s[i];
}
for(i=0;i<=n;i++)
{
for(j=1;j<t.size();j++)
v[i]=v[i]*1777777777+c[j]-c[0]+1LL*123456789;
if (i<n)
c[t.find(s[i])]++;
}
sort(v,v+n+1);
for(i=1;i<=n;i++)
if (v[i]!=v[i-1])
rasp=rasp+1LL*(i-l)*(i-l-1)/2,
l=i;
rasp=rasp+1LL*(n+1-l)*(n-l)/2;
printf("%lld\n",rasp%1000000007);
return 0;
}
// using
using namespace std;
CAPITOLUL 11. EJOI 2017 11.1. MAGIC 374
// types
typedef long long ll;
typedef pair<int,int> pii;
// macro
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin() , (x).end()
#define REP(i , n) for(int i = 0; i < int(n); i++)
#define REP1(i , a , b) for(int i = a; i <= int(b); i++)
#define F first
#define S second
#define MP make_pair
#define PB push_back
#define LC o<<1 , l , m
#define RC o<<1|1 , m + 1 , r
#define MS(x , v) memset(x , (v) , sizeof(x))
// input
inline bool SR(int &x)
{
return scanf("%d",&x) == 1;
}
// output
inline void SP(const int x)
{
printf("%d",x);
}
{
SP(x);
if(sizeof...(tail)) putchar(’ ’);
PL(tail...);
}
// debug
#define WangYenJen
#ifdef WangYenJen
template<typename I>
void _DOING(const char *s , I&& x)
{
cerr << s << " = " << x << endl;
}
#define DEBUG(...) \
do {\
fprintf(stderr , "%s: Line %d - ",__PRETTY_FUNCTION__,__LINE__);\
_DOING(#__VA_ARGS__ , __VA_ARGS__);\
} while(0);
#else
#define DEBUG(...)
#endif
// constant number
const int INF = 0x3f3f3f3f;
const ll INF64 = 0x3f3f3f3f3f3f3f3fll;
// random function
inline int RAND()
{
static int x = 880301;
return (x = x * 0xdefaced + 1) % 0x7fffffff;
}
ll dp[MAX_N];
char S[MAX_N];
ll power[MAX_N];
int main()
{
std::freopen("../magic_tests/magic.20.in", "r", stdin); // 21636849
//std::freopen("magic.out", "w", stdout);
int N;
RI(N);
SR(S + 1);
vector<char> rd;
REP1(i, 1, N) rd.PB(S[i]);
sort(ALL(rd));
rd.erase(unique(ALL(rd)), rd.end());
CAPITOLUL 11. EJOI 2017 11.1. MAGIC 376
power[0] = 1;
REP1(i, 1, SZ(rd)) power[i] = power[i - 1] * BASE % MOD;
ll P = 0;
REP(i, SZ(rd)) P += power[i];
ll hv = 0, ans = 0;
cnt[hv]++;
REP1(i, 1, N)
{
int x = lower_bound(ALL(rd), S[i]) - rd.begin();
(hv += power[x]) %= P;
if (cnt.count(hv)) ans += cnt[hv];
cnt[hv]++;
}
return 0;
}
OBS: “typename...” In a primary class template, the template parameter pack must be the
128
final parameter in the template parameter list.
#include<iostream>
char*concat(char*a, char b)
{
char*ptr=NULL;
asprintf(&ptr, "%s%c",a,b);
return ptr;
}
int n, c[55];
bool vis[55];
ull v[100009];
char*t;
char s[100000];
int main()
{
std::freopen("../magic_tests/magic.20.in", "r", stdin); // 21636849
//std::freopen("magic.out", "w", stdout);
t = strdup("");
scanf("%d", &n);
128
https://en.cppreference.com/w/cpp/language/parameter_pack
CAPITOLUL 11. EJOI 2017 11.1. MAGIC 377
scanf("%s", &s);
for (int i = 0; i < n; i++)
{
int p = s[i] <= ’Z’ ? s[i] - 65 : s[i] - 71;
if (!vis[p])
{
vis[p] = true;
t = concat(t, s[i]);
}
}
if(i < n)
{
char*pidx = strchr(t, s[i]);
int idx;
// if(pidx)
idx = pidx - t;
//else
// idx=0;
c[idx]++;
}
}
int l = 0;
ll ret = 0;
for (int i = 1; i <= n + 1; i++)
{
if (i == n + 1 || v[i] != v[i - 1])
ret += 1LL * (i - l) * (i - l - 1) / 2, l = i;
}
return 0;
}
#include<bits/stdc++.h>
#define ff first
#define ss second
int n,zl[205],minim;
long long hasz,ans,kand,ile;
const long long mod=1E9+123,mod2=1E9+7;
char zn[100005];
vector<char>v;
vector<long long>vec;
map<long long,int>m;
int main()
{
std::freopen("../magic_tests/magic.20.in", "r", stdin); // 21636849
//std::freopen("magic.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin>>n;
for(int i=1;i<=n;i++)
CAPITOLUL 11. EJOI 2017 11.1. MAGIC 378
{
cin>>zn[i];
zl[zn[i]]++;
}
for(int i=’a’;i<=’z’;i++)
{
if(zl[i]!=0)v.push_back(i);
}
for(int i=’A’;i<=’Z’;i++)
{
if(zl[i]!=0)v.push_back(i);
}
for(int i=0;i<v.size();i++) zl[v[i]]=0;
for(int i=1;i<=n;i++)
{
zl[zn[i]]++;
minim=INT_MAX;
for(int j=0;j<v.size();j++)
minim=min(minim,zl[v[j]]);
hasz=0;
for(int j=0;j<v.size();j++)
hasz=hasz*29+(zl[v[j]]-minim);
vec.push_back(hasz);
}
sort(vec.begin(),vec.end());
for(int i=0;i<vec.size();i++)
{
if(i==0)
{
kand=vec[i];
ile=1;
continue;
}
if(vec[i]!=vec[i-1])
{
if(kand!=0) ile--;
ans=(ans+((ile)*(ile+1))/2)%mod2;
kand=vec[i];
ile=1;
}
else
ile++;
}
if(kand!=0) ile--;
ans=(ans+((ile)*(ile+1))/2)%mod2;
cout<<ans;
}
#include<bits/stdc++.h>
char*concat(char*a, char b)
{
char*ptr = NULL;
asprintf(&ptr, "%s%c", a, b);
return ptr;
}
int n, c[55];
bool vis[55];
ull v[100009];
char*t;
char s[100000];
int main()
{
std::freopen("../magic_tests/magic.20.in", "r", stdin); // 21636849
//std::freopen("magic.out", "w", stdout);
t = strdup("");
scanf("%d", &n);
scanf("%s", &s);
if(i < n)
{
char*pidx = strchr(t, s[i]);
int idx;
if(pidx)
idx = pidx - t;
else
idx=0;
c[idx]++;
}
}
int l = 0;
ll ret = 0;
for (int i = 1; i <= n + 1; ++ i)
{
if (i == n + 1 || v[i] != v[i - 1])
ret += 1LL * (i - l) * (i - l - 1) / 2, l = i;
}
return 0;
}
11.2 Particles
Problema 2 - Particles 100 de puncte
CAPITOLUL 11. EJOI 2017 11.2. PARTICLES 380
Two linear particle accelerators A and B, placed opposite to each other at a distance L apart,
are propelling elementary particles. A is shooting x-particles, while B is shooting y-particles.
The two kinds of particles are flying one opposing the other, and when an x-particle meets a y-
particle, they collide and annihilate. One should be aware that an xparticle could overtake other
x-particles, as well as a y-particle could overtake other y-particles without any consequences for
the particles.
Like so, in a given moment of time, which we assume to be zero, a shooting of N x-particles
and N y-particles starts from the two accelerators. Each particle moves with its own constant
speed. The particles are numbered in the order of their shooting from 1 to N , this holds true for
both the x-particles and the y-particles.
Remark: For time t, a particle with speed v travels distance s vt.
The shooting time moments for the x-particles are 0 tx1 $ tx2 $ tx3 $ ... $ txN , and their
speeds are vx1 , vx2 , vx3 , ..., vxN .
Correspondingly, for the y-particles the moments are denoted by 0 ty1 $ ty2 $ ty3 $ ... $ tyN ,
and their speeds by vy1 , vy2 , vy3 , ..., vyN .
The shooting is executed in a way to guarantee the fulfillment of the following conditions:
- Each particle will collide a particle of the opposite type;
- When two particles collide, all other particles will be at a distance greater than or equal to
1 from the collision point. This is guarantee for the first collisions.
Task
Write a program particles to determine the first K collisions between particles of the two kinds.
Input
The three space separated positive integers N , L, and K are read from the first line of the
standard input.
The following N lines contain two space separated non-negative integers txi and vxi each: the
shooting moment and the speed of the corresponding x-particle.
The last N input lines contain, respectively, each the shooting moment tyi and the speed vyi
of the corresponding y-particle in the same format.
Output
The program must print to the standard output K lines, each containing two space sepa-
rated positive integers: the numbers of the x-particle and y-particle, which are involved in the
corresponding collision.
th
Lines are output increasingly by the order of collisions - from the first one to the K .
Constraints
Example
Sample input Sample output
4 100 2 42
01 24
23
32
6 10
05
3 10
51
7 20
CAPITOLUL 11. EJOI 2017 11.2. PARTICLES 381
In order to be able to solve the problem we have to learn to find the exact moment in which two
particles collide. Let us try to find the moment in which the i-th x particle and the j-th y particle
collide. We can do that quite easily using a binary search on the moment of collision, but that
would have a complexity of O log. To find the moment of collision in O 1 let us look at the
formulas that describe the position of a certain particle in a specific moment. Let us imagine that
the x particles are being shot from point 0 rightwards on the number line, and the y particles are
being shot from point L leftwards on the number line. At a certain moment t, the position of the
two particles is:
P xi t txi vxi
P yj L t tyj vyj
This formula could give negative values if we evaluate it for invalid times in which the particle
has not been shot yet, but that does not matter. We clearly have a collision if P xi P yj . That
is:
t txi vxi L t tyj vyj
t vxi txi vxi L t vyj tyj vyj
t vxi t vyj L tyj vyj txi vxi
t L tyj vyj txi vxi © vxi vyj
And hence we get a direct formula for the moment of collision. It is possible for the collision
to happen before 0 or after L on the number line, which means that this collision will surely not
happen (those particles will collide with some others before colliding with each other).
2
Solution with complexity O N log N
Since we can quickly find the moment of collision between two particles, we can find the
moment of collision for every pair of particles and order these collisions chronologically. The total
2 2
amount of collisions is O N , and sorting them takes O N log N . After this we can iterate
over all collisions chronologically and keep which of the particles have already collided. If we reach
a pair in which both particles have not collided with anything yet, then we know that they will
collide with each other. In this way we can find not only the first K, but all collisions with the
same complexity.
Solution with complexity O N K log
We will describe a solution that finds only the first collision. After finding it we can remove
the two particles that collided and repeat the whole process K times.
To find the first collision we will use binary search on the moment of the first collision. Let us
fix the time t. We want to know whether the first collision happened before or after t. To do this
we can find the furthest x particle and the furthest y particle (by ’furthest’ we mean the one that
travelled the largest distance, that is, using the formulas above, the x particle with the largest
position and the y particle with the smallest one).
Let the positions of the two particles, according to the formulas above, be respectively Px and
Py . Then:
If ¶Px Py ¶ $ ε (where ε is a small enough constant) we can assume that t is the moment
of the first collision. The particles which collided are the furthest particles.
Else:
If Px $ Py , then the first collision has not happened yet and we have to look for a larger
value of t
If Px % Py , then the first collision already happened and we have to look for a smaller value
of t
This solution has a complexity of O N log for finding the first collision. The bounds of the
binary search in which we search for t are from 0 to the time needed for any particle to be shot
and travel a distance of L (since at this moment the particle must have collided with some other
one).
Since we are doing a binary search on real values and not integers, it is a good idea to set a
limit on the amount of iterations the binary search can perform, since choosing a good ε may be
tricky. About 40-50 iterations should be ideal (more may trigger time limits and less could lead
to precision errors).
CAPITOLUL 11. EJOI 2017 11.2. PARTICLES 382
Using this procedure K times we get a solution with total complexity of O N K log.
The problem can be solved in O N K , but this was not required.
#include<stdio.h>
#include<algorithm>
#include<iostream>
int n,L,k;
int tx[ran],vx[ran],ty[ran],vy[ran];
bool fx[ran],fy[ran];
int main()
{
std::freopen("../particles_tests/particles.20.in", "r", stdin);
std::freopen("particles.out", "w", stdout);
scanf("%d%d%d",&n,&L,&k);
while(k--)
{
double lo = 0, hi = 2e9;
while(true)
{
double mi = (lo + hi)/2;
double MX = 0;
int IDX = -1;
for(int i=1; i<=n; i++)
{
if(fx[i])continue;
if(tx[i] > mi)continue;
double pos = (mi - tx[i]) * vx[i];
if(pos >= MX)MX = pos,IDX = i;
}
double MY = L;
int IDY = -1;
for(int i=1; i<=n; i++)
{
if(fy[i])continue;
if(ty[i] > mi)continue;
double pos = L - (mi - ty[i]) * vy[i];
if(pos <= MY) MY = pos, IDY = i;
}
return 0;
}
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <cmath>
#include <cstring>
#include <ctime>
#include <unordered_map>
#include <iomanip>
#define fi first
#define se second
#define pb push_back
#define all(v) (v).begin(),(v).end()
bool check(ld t)
{
ld l=0,r=0;
id[0]=id[1]=-1;
int i;
for (i=1; i<=N; i++)
if (!px[i] && tx[i]<=t && (id[0]==-1 || l<vx[i]*(t-tx[i])))
{
l=1LL*vx[i]*(t-tx[i]);
id[0]=i;
}
return 1;
}
CAPITOLUL 11. EJOI 2017 11.2. PARTICLES 384
int main()
{
std::freopen("../particles_tests/particles.20.in", "r", stdin);
std::freopen("particles.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> N >> L >> K;
int i,maxt=0;
for (i=1; i<=N; i++)
{
cin >> tx[i] >> vx[i];
maxt=max(maxt,tx[i]);
}
ld t=1;
while (K)
{
ld l=t,r=L+maxt,mid;
cout << id[0] << " " << id[1] << "\n";
t=l;
px[id[0]]=1,py[id[1]]=1;
K--;
}
return 0;
}
#include <stdio.h>
#include <iostream>
#include <vector>
#include <assert.h>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <sstream>
#include <memory.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
int main()
{
CAPITOLUL 11. EJOI 2017 11.2. PARTICLES 385
a[at.first].first = -1;
b[at.second].first = -1;
printf("%d %d\n", at.first + 1, at.second + 1);
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#pragma comment(linker, "/STACK:256000000")
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
CAPITOLUL 11. EJOI 2017 11.2. PARTICLES 386
#include <set>
#include <queue>
#include <deque>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
int solve();
int main()
{
std::freopen("../particles_tests/particles.20.in", "r", stdin);
std::freopen("particles.out", "w", stdout);
solve();
return 0;
}
int solve()
{
int n, l, k;
cin >> n >> l >> k;
int prevV = 0;
for (int i = 0; i < n; i++)
{
int t = T1[i], v = V1[i];
if (v > prevV)
{
t1.push_back(t), v1.push_back(v);
num1.push_back(i + 1);
prevV = v;
}
}
prevV = 0;
for (int i = 0; i < n; i++)
{
int t = T2[i], v = V2[i];
if (v > prevV)
{
t2.push_back(t), v2.push_back(v);
prevV = v;
num2.push_back(i + 1);
}
}
t2.erase(t2.begin() + y);
v2.erase(v2.begin() + y);
return 0;
}
#include <bits/stdc++.h>
pos = l-pos;
}
return calc(hi).second;
}
int main()
{
std::freopen("../particles_tests/particles.20.in", "r", stdin);
std::freopen("particles.out", "w", stdout);
return 0;
}
#include<cstdio>
#include<vector>
struct tip
{
int first,second,nr;
};
int n,l,k;
int main()
{
std::freopen("../particles_tests/particles.20.in", "r", stdin);
std::freopen("particles.out", "w", stdout);
int i,i1,j;
scanf("%d%d%d",&n,&l,&k);
vector<tip> a(n),b(n),c(n),d(n);
for(i=0;i<n;i++)
scanf("%d%d",&a[i].first,&a[i].second),a[i].nr=i;
for(i=0;i<n;i++)
scanf("%d%d",&b[i].first,&b[i].second),b[i].nr=i;
for(i1=0;i1<k;i1++)
CAPITOLUL 11. EJOI 2017 11.2. PARTICLES 389
{
c.clear(),d.clear();
for(i=0;i<n;i++)
{
if (c.size() && c.back().second>a[i].second)
continue;
c.push_back(a[i]);
c.back().nr=i;
}
for(i=0;i<n;i++)
{
if (d.size() && d.back().second>b[i].second)
continue;
d.push_back(b[i]);
d.back().nr=i;
}
double t=1e18;
int in1=-1,in2=-1;
for(i=0;i<(int)c.size();i++)
{
int r=(int)d.size()-1;
for(j=0;j<=r;j++)
{
double num=get(i,j,c,d);
if (t>num)
{
t=num;
in1=c[i].nr;
in2=d[j].nr;
}
}
}
printf("%d %d\n",a[in1].nr+1,b[in2].nr+1);
a.erase(a.begin()+in1);
b.erase(b.begin()+in2);
n--;
}
return 0;
}
#include <bits/stdc++.h>
#define err(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
struct cond
{
int first, second, ind;
};
int n, L, k;
int main()
{
std::freopen("../particles_tests/particles.20.in", "r", stdin);
std::freopen("particles.out", "w", stdout);
double t = 1e18;
int ind1 = -1, ind2 = -1;
int a = A[ind1].ind;
int b = B[ind2].ind;
A.erase(A.begin() + ind1);
B.erase(B.begin() + ind2);
n--;
}
return 0;
}
#include<bits/stdc++.h>
int n, lgth, K;
int tx[maxx], vx[maxx], ty[maxx], vy[maxx];
bool flag, fx[maxx], fy[maxx];
main()
{
std::freopen("../particles_tests/particles.20.in", "r", stdin);
std::freopen("particles.out", "w", stdout);
if (!fy[k])
{
double qr = lgth-(m - ty[k])*vy[k];
if(pr>qr) pr=qr, my=k;
}
fx[mx]=fy[my]=1;
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../particles_tests/particles.20.in",
(char*)"particles.out",
(char*)"../particles_tests/particles.20.sol",
};
CAPITOLUL 11. EJOI 2017 11.3. SIX 392
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
11.3 Six
Problema 3 - Six 100 de puncte
Elly studies the properties of some given integer N . So far she has discovered that it has no
more than six distinct prime divisors. A prime number (or a prime) is a natural number greater
than 1 that has no positive divisors other than 1 and itself.
Now the girl spends her time in the following way. Starting with an empty list, she writes
divisors of N , greater than 1 (some divisors she may repeat several times). When adding a new
number to the list, she makes sure that it has common divisors greater than 1 with at most one
of the already written numbers.
For example, if the number N is 12156144, some of the many possible valid sequences the girl
can generate are (42), (616, 6, 91, 23), (91, 616, 6, 23), (66, 7), (66, 7, 7, 23, 299, 66), (143, 13,
66), and (42, 12156144). Examples for invalid sequences would be (5, 11), since 5 is not a divisor
of 12156144, or (66, 13, 143), since 143 has common divisors with both 13 and 66.
Now Elly is wondering how many different valid sequences of divisors of N exist. We consider
two sequences different if they have different length or there is a position, in which they have
different numbers.
Task
Write a program six that helps Elly to find the number of valid sequences of divisors of N .
Input
From the first line of the standard input your program has to read one integer N .
Output
On the standard output your program has to print one integer - the number of different
sequences of divisors of N , which could have been written by Elly. Since this number can be
rather large, you are required to print only its remainder when divided by 1 000 000 007.
Constraints
Example
Sample Input Sample Output
6 28
203021 33628
60357056536 907882
12156144 104757552
Explanation: All 28 valid sequences in the first sample are: {(2), (2, 2), (2, 2, 3), (2, 2, 3, 3),
(2, 3), (2, 3, 2), (2, 3, 2, 3), (2, 3, 3), (2, 3, 3, 2), (2, 6), (2, 6, 3), (3), (3, 2), (3, 2, 2), (3, 2, 2, 3),
CAPITOLUL 11. EJOI 2017 11.3. SIX 393
(3, 2, 3), (3, 2, 3, 2), (3, 3), (3, 3, 2), (3, 3, 2, 2), (3, 6), (3, 6, 2), (6), (6, 2), (6, 2, 3), (6, 3), (6,
3, 2), (6, 6)}
In the last example the answer is 14104757650, but since you are required to print it modulo
1 000 000 007, the actual result is 14104757650 % 1000000007 = 104757552.
The main thing that the contestants must have noticed in this problem was that N has at most
six distinct prime divisors. Note that these 6 primes will be not only in the factorization of N ,
but also in the factorization of all of its divisors - the numbers, Elly is writing.
The first thing the contestants should do before getting to any solution is find the (up to)
6 prime factors of N . This can be done quite trivially, using the O sqrt N algorithm. Since
15
N was up to 10 , this would require around 32 million operations - a fraction of a second on a
processor manufactured in the past 10 years.
Now, let’s get to the main part of the problem. As with many other problems where the
question is ”how many” and the answer can be pretty large (thus, the modulus), here as well
the solution is based on dynamic programming. We’ll need to have a state, which tells us which
divisors of N we can write at any given time.
In order two numbers in the list to be coprime (to have no common divisors greater than or
equal to 2), they must share no prime number in their factorization. Thus, keeping track which
of the primes have not been used, which have been used once, and which have been used twice
should do the trick, right?
Well, almost. Unfortunately, it is not entirely enough and will most likely be a common
problem the competitors face. It is fairly intuitive to go this way (use a ternary mask for the
state), however we’ll show that this is actually incorrect. Luckily for them, the examples are quite
strong and reveal this!
The problem with the solution above is that it matters whether two primes (which were used
once) were used in the same number or in two different numbers. Consider the following sequences:
1. (2, 3, 30)
2. (6, 30)
The first one is invalid, because 30 has common divisors with both 2 and 3 (two different
numbers from the list). However, the second one is valid - 30 still has common divisors with 2
and 3, but this time they are used in the same number 6.
So, we need a state, which both:
Keeps track which primes were used 0, 1, and 2 times.
Keeps track which primes were used together.
We have several possible solutions. Let’s start with the easiest one.
Approach 1 (keep all occurrences of each factor)
To get to this approach we need to make the observation that the list Elly writes can have at
most 12 elements. This should be fairly obvious, as each prime can be used at most twice (and 6
* 2 = 12).
Instead of storing 0 (not used), 1 (used once), or 2 (used twice) for each prime, we can store
not used (no restrictions), used twice (cannot use) or the position, at which it was used. Knowing
the position where each of the primes was used helps us solve the problem we outlined above.
We will need 14 values for each prime: 0-11 will represent the position at which it was used,
12 will mean it was not used and 13 will mean it was already used twice. This means a DP with
6
14 = 7,529,536 states, which is okay from memory point of view (the answer fits into 4int, thus
we’ll need around 30 megabytes for the DP table).
In terms of time, for each state we have to choose which divisor of N to use. Since we have up
6
to 6 primes, the number of divisors is 2 64. This looks bad at first, since, if we do the math,
6 6
we’ll need around 14 2 = 481,890,304 operations in the worst case - more than we can afford
for the given time limit.
However, we can easily see that many of the states are invalid (can never be reached), thus
shouldn’t be counted towards that (see below for explanation why).
CAPITOLUL 11. EJOI 2017 11.3. SIX 394
In fact, running the last example (which has six prime divisors, i.e., should reach as many
states as possible) reaches only 170,000 out of the 7,500,000 possible states. With that many
actual states, the 64 operations per state are quite okay - this solution runs quite quickly on any
input with these constraints, thus it gets 100 points.
Why are the valid states so few?
How can we deduce that many of the states will be invalid? Let’s assume that as the first
number in the list we use a divisor, which includes multiple factors. This drastically reduces the
maximal length of the list. For example, if the first element is N itself (thus, uses all 6 factors),
the length of the list is suddenly limited to 7.
Moreover, an average divisor of N has (1 + 6) / 2 = 3.5 (thus 3 or 4) prime factors. This
means that the average length of a valid list is only around 12 / 3.5 = 3.42 (thus 3 to 4) numbers!
From here we can conclude that, although there are valid sequences with 12 elements, most of the
sequences will have only few. If we assume that in most cases the length of the list is no more
6
than 6, our calculation for the number of reachable states would be 6 2 = 262,144 - much
closer to what we get empirically.
Approach 2 (map-based solution)
The contestants could exploit the low number of states, by using a map-based solution (in-
stead of figuring out the perfect state). Since we don’t care where in the list we have writ-
ten each of the previous numbers, only which numbers we have written, we can instead use
map <vector<int>, int> as a dynamic table. This approach is pretty simple and, as long as
the vector is sorted, also relatively fast - it would get 80 points.
Approach 3 (smart solution)
We can do another observation (this time a hard one) to get a better state. We already saw
that the number of reachable states is much lower than what our table covers. What if we make
the table smarter (less sparse)?
We don’t really care on which position each of the prime factors was used, only which pairs
of prime factors cannot be used together anymore. For example, if we’ve already written 2 and
3, we know that we cannot use a number, which is divisible by 6. If we’ve written the numbers 6
and 35, we know that we cannot use the pairs (2, 5), (2, 7), (3, 5), and (3, 7) - thus the numbers
10, 14, 15, and 21 cannot be divisors of any new number.
How many pairs there are? Since (2, 3) and (3, 2) are the same, we’ll only need information
about 6 * 7 / 2 = 21 pairs. And we can use a bitmask for that.
21
This brings the table to 2 = 2,097,152 states (slightly lower than the previous one). In fact,
many of those are also not reachable. For example, if we know that the pairs (2, 3) and (5, 7) are
forbidden, but (3, 5) is not, then we can conclude that (2, 5) should also be forbidden (because
3 and 5 were apparently used in the same number). Checking this empirically shows that only
slightly over 3000 states were actually reached! It turns out that this solution is not only better
in terms of memory efficiency, but also much faster as runtime as well. The number of states is
so low, that even a map-based solution with this idea gets a full score.
I’d be interested in what is the best state the contestants come up with, since even this approach
is very inefficient in terms of state.
Naive (bruteforce) approaches
Of course, the contestants could have tried other simpler approaches - for example bruteforce.
Depending on how smart the backtrack was written, they could have gotten quite a lot of points.
This was done on purpose, since the smart solutions are on the hard side. The trivial bruteforce,
for example, was supposed to get around 40 points. An optimized one could get around 60.
/*
ID: espr1t
TASK: Six
KEYWORDS: Hard, Dynamic Programming, Bitmasks
*/
#include <cstdio>
#include <vector>
#include <map>
return ret;
}
if (n > 1)
facts.push_back(make_pair(n, 1));
masks.push_back(mask),
ways.push_back(cnt);
}
}
int main(void)
{
std::freopen("../six_tests/six.25.in", "r", stdin); // 591780
//std::freopen("six.out", "w", stdout);
long long n;
fscanf(stdin, "%lld", &n);
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<time.h>
#include<algorithm>
#include<map>
#include<set>
#include<iostream>
#include<vector>
BigInteger FACTORLIST[50];
int EXPONENTLIST[50],BIGOMEGA;
int smallprimes[168]=
{
2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,
59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,
137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,
227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,
313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,
419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,
509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,
CAPITOLUL 11. EJOI 2017 11.3. SIX 397
617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,
727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,
829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,
947,953,967,971,977,983,991,997
};
/* small table */
BigInteger powmod(BigInteger,BigInteger,BigInteger);
int strong_pseudo_primetest(BigInteger,int);
int isprime(BigInteger);
BigInteger gcd(BigInteger,BigInteger);
void factor_using_pollard_rho (BigInteger n,int);
void factor(BigInteger n);
return r;
// return a*b%p;
}
BigInteger result=1,
powres=n%modulus;
while(exponent>0)
{
if(exponent%2==1)
result=mulmod(result,powres,modulus);
powres=mulmod(powres,powres,modulus);
exponent/=2;
}
return result;
}
BigInteger n2=n-1,res;
int s;
s=0;
while(n2%2==0) n2/=2,s++;
res=powmod(base,n2,n);
if((res==1)||(res==n-1)) return 1;
s--;
while(s>=0)
{
res=mulmod(res,res,n);
if(res==n-1) return 1;
s--;
}
return 0;
}
int isprime(BigInteger n)
{
if(n<2) return 0;
if(n<4) return 1;
if(strong_pseudo_primetest(n,2)==0) return 0;
if(strong_pseudo_primetest(n,3)==0) return 0;
if(n<1373653LL) return 1;
if(strong_pseudo_primetest(n,5)==0) return 0;
CAPITOLUL 11. EJOI 2017 11.3. SIX 398
if(n<25326001LL) return 1;
if(strong_pseudo_primetest(n,7)==0) return 0;
if(n==3215031751LL) return 0;
if(n<25000000000LL) return 1;
if(strong_pseudo_primetest(n,11)==0) return 0;
if(n<2152302898747LL) return 1;
if(strong_pseudo_primetest(n,13)==0) return 0;
if(n<3474749660383LL) return 1;
if(strong_pseudo_primetest(n,17)==0) return 0;
if(n<341550071728321LL) return 1;
if(strong_pseudo_primetest(n,19)==0) return 0;
if(strong_pseudo_primetest(n,23)==0) return 0;
if(strong_pseudo_primetest(n,29)==0) return 0;
if(strong_pseudo_primetest(n,31)==0) return 0;
if(strong_pseudo_primetest(n,37)==0) return 0;
return 1;
/* are we sure that n is prime?!
Up to 2ˆ63 there can be some exceptions, but very few. */
}
while(b>0)
{
a%=b;
c=a;
a=b;
b=c;
}
return a;
}
while(n!=1)
{
S2:
x=mulmod(x,x,n);
x=(x+a)%n;
t1=n+x1-x;
if(t1>=n)t1-=n;
P=mulmod(P,t1,n);
c++;
if(c==20)
{
c=0;
g=gcd(P,n);
if(g!=1) goto S4;
y=x;
}
S3:
k--;
if(k>0) goto S2;
g=gcd(P,n);
if(g!=1) goto S4;
x1=x;
CAPITOLUL 11. EJOI 2017 11.3. SIX 399
k=l;
l=2*l;
for(i=0;i<k;i++)
{
x=mulmod(x,x,n);
x=(x+a)%n;
}
y=x;
c=0;
goto S2;
S4:
err=0;
count=0;
do
{
if(count>l)
{
err=1;
break;
}
y=mulmod(y,y,n);
y=(y+a)%n;
t1=n+x1-y;
if(t1>=n) t1-=n;
g=gcd(t1,n);
count++;
} while(g==1);
if(err==1)
{
do
{
a=rand();
} while(a<4);
factor_using_pollard_rho(n,a);
break;
}
else
{
n=n/g;
if(isprime(g)==0)
{
do
{
a=rand();
} while(a<4);
factor_using_pollard_rho(g,a);
}
else
{
expo=1;
while(n%g==0) n/=g,expo++;
FACTORLIST[BIGOMEGA]=g;
EXPONENTLIST[BIGOMEGA]=expo;
BIGOMEGA++;
}
}
x=mulmod(x,x,n);
if(isprime(n)==1)
{
FACTORLIST[BIGOMEGA]=n;
EXPONENTLIST[BIGOMEGA]=1;
BIGOMEGA++;
n=1;
}
}
return;
}
void factor(BigInteger n)
{
CAPITOLUL 11. EJOI 2017 11.3. SIX 400
int i,expo;
/* trial divide by the first 168 primes (primes up to 1000) */
BIGOMEGA=0;
if(n<2) return;
for(i=0;(i<168)&&(smallprimes[i]*smallprimes[i]<=n);i++)
{
if(n%smallprimes[i]==0)
{
n/=smallprimes[i],expo=1;
while(n%smallprimes[i]==0) n/=smallprimes[i],expo++;
FACTORLIST[BIGOMEGA]=smallprimes[i];
EXPONENTLIST[BIGOMEGA]=expo;
BIGOMEGA++;
}
}
if(n==1) return;
if((n<1000000)||(isprime(n)==1))
{
FACTORLIST[BIGOMEGA]=n;
EXPONENTLIST[BIGOMEGA]=1;
BIGOMEGA++;
return;
}
/* at here we know n is composite */
factor_using_pollard_rho(n,3);
}
int w,sz[64];
map<vector<int>,int> Map;
int to[3333][64];
int dp[2][3333];
void dfs(int i)
{
if(i == w)
{
vector<int> tmp;
for(int j=0; j<w; j++) tmp.push_back(aa[j]);
Map[tmp] = Lis.size();
Lis.push_back(tmp);
return;
}
aa[i] = -1;
dfs(i+1);
aa[i] = -2;
dfs(i+1);
r[lr++] = i;
aa[i] = i;
dfs(i+1);
lr--;
for(int j=0; j<lr; j++)
CAPITOLUL 11. EJOI 2017 11.3. SIX 401
{
aa[i] = r[j];
dfs(i+1);
}
}
int ace[6];
int ancestor(int x)
{
return x-ace[x]?ace[x]=ancestor(ace[x]):x;
}
void fin()
{
w = BIGOMEGA;
for(int i=0; i<(1<<w); i++)
{
sz[i] = 1;
for(int j=0; j<w; j++)if(i&(1<<j))sz[i] = mul(sz[i], EXPONENTLIST[j]);
}
Map.clear();
Lis.clear();
dfs(0);
int rr = -1;
int bad = 0;
for(int k=0; k<w; k++)
{
if(j&(1<<k))
{
if(aa[k] == -2)flag = false;else
if(aa[k] != -1)
{
aa[k] = -2;
if(bad == 0)
bad |= 1<<ancestor(k);
else
if(bad != (1<<ancestor(k)))
flag = false;
}
else
{
if(rr==-1)rr=k;
aa[k] = rr;
ace[ancestor(k)] = ancestor(rr);
}
}
}
if(!flag)continue;
vector<int> tmp;
for(int k=0; k<w; k++)if(aa[k] >= 0)
{
int rt;
for(rt=0; ancestor(rt) != ancestor(k) || aa[rt] < 0; rt++);
tmp.push_back(rt);
}
CAPITOLUL 11. EJOI 2017 11.3. SIX 402
else
tmp.push_back(aa[k]);
if(Map.count(tmp) == 0)
{
tmp.clear();
}
to[i][j] = Map[tmp];
}
memset(dp[0],0,sizeof(dp[0]));
dp[0][0] = 1;
int res = 0;
while(true)
{
memset(dp[1],0,sizeof(dp[1]));
for(int i=0; i<len; i++)
{
if(dp[0][i]==0) continue;
if(flag)break;
}
printf("%d\n",res);
}
int main()
{
std::freopen("../six_tests/six.25.in", "r", stdin); // 591780
//std::freopen("six.out", "w", stdout);
BigInteger n;
srand(time(0));
cin >> n;
factor(n);
// for(w=1; w<=6; w++)
fin();
return 0;
}
129
OBS1: strong pseudo prime
vspace2mm
130
OBS2: Pollard method
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
129
https://en.wikipedia.org/wiki/Strong_pseudoprime
130
https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
CAPITOLUL 11. EJOI 2017 11.3. SIX 403
#include <queue>
#include <cstring>
#include <cmath>
#define PB push_back
#define MP make_pair
#define SZ(v) ((int)(v).size())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define FORE(i,a,b) for(int i=(a);i<=(b);++i)
#define REPE(i,n) FORE(i,0,n)
#define FORSZ(i,a,b) FOR(i,a,SZ(v))
#define REPSZ(i,v) REP(i,SZ(v))
ll N;
int pcnt[MAXP],np;
bool ismillerrabinprime(ll n)
{
if(n<2) return false;
ll d=n-1;
int r=0;
while(d%2==0) d/=2,++r;
REP(i,PTESTCNT)
{
int a=PTEST[i];
ll x=modpw(a,d,n);
if(x==1||x==n-1) continue;
REP(j,r-1)
{
x=modmlt(x,x,n);
if(x==1||x==n-1) break;
}
if(x!=n-1) return false;
}
return true;
}
void decompose()
{
ll x=N; np=0;
for(int i=2;i<=MAGIC;++i) if(x%i==0)
{
pcnt[np]=0;
CAPITOLUL 11. EJOI 2017 11.3. SIX 404
while(x%i==0) ++pcnt[np],x/=i;
++np;
}
if(x==1) return;
int y=(int)sqrt(1.0*x);
if((ll)y*y==x)
{
pcnt[np++]=2;
return;
}
if(!ismillerrabinprime(x))
{
pcnt[np++]=1;
pcnt[np++]=1;
return;
}
pcnt[np++]=1;
}
int mem[MAXP][2*MAXP+1][1<<(2*MAXP)];
if(ret==-1)
{
ret=go(at+1,cnt,mask);
REPE(a,2*cnt)
{
int acnt=cnt,amask=mask,apos;
if(a%2==1)
apos=(a-1)/2;
else
{
apos=a/2;
++acnt;
amask=(mask&((1<<apos)-1))|((mask>>apos)<<(apos+1));
}
int acur=go(at+1,acnt,amask);
ret=(ret+(ll)acur*pcnt[at])%MOD;
int bcur=go(at+1,bcnt,bmask);
ret=(ret+(ll)bcur*pcnt[at]*pcnt[at])%MOD;
REP(i,cnt) if(mask&(1<<i))
{
CAPITOLUL 11. EJOI 2017 11.3. SIX 405
int ccur=go(at+1,cnt,mask);
ret=(ret+(ll)ccur*pcnt[at]*pcnt[at])%MOD;
}
//printf("go(%d,%d,%d)=%d\n",at,cnt,mask,ret);
}
return ret;
}
int main()
{
std::freopen("../six_tests/six.25.in", "r", stdin); // 591780
//std::freopen("six.out", "w", stdout);
scanf("%lld",&N);
decompose();
memset(mem,-1,sizeof(mem));
int ret=(go(0,0,0)+MOD-1)%MOD;
printf("%d\n",ret);
}
131
OBS: Miller-Rabin primality test
#include <bits/stdc++.h>
#define X first
#define Y second
#define vi vector<int>
#define vvi vector< vi >
#define vii vector< ii >
#define mp make_pair
#define pb push_back
int ndiv;
vector<int> fdiv;
const int md = 1e9+7;
void proc(ll N)
{
for(ll i = 2; i*i<= N; i++)
{
if(N%i == 0)
{
131
https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
CAPITOLUL 11. EJOI 2017 11.3. SIX 406
fdiv.pb(0);
}
while(N%i == 0)
{
fdiv.back()++;
N /= i;
}
}
if(N> 1)
{
fdiv.pb(1);
}
ndiv = fdiv.size();
for(int i = 0; i< (1<<ndiv); i++)
{
ways[i] = 1;
for(int j = 0; j< ndiv; j++)
{
if((1<<j) & i)
{
ways[i] = mul(ways[i], fdiv[j]);
}
}
//printf("ways[%d] = %d\n", i, ways[i]);
}
}
ll cross(int x, int y)
{
ll res = 0;
for(int i = 0; i< ndiv; i++)
{
for(int j = 0; j< ndiv; j++)
{
if( ( ( (1<<i) & x ) and ( (1<<j) & y ) ) or
( ( (1<<j) & x ) and ( (1<<i) & y ) ) )
{
res |= (1ll<<(ndiv*i+j));
}
}
}
return res;
}
//system("pause");
//printf("arrived %lld %d\n", mask, cur);
int res = 1;
for(int i = 1; i< (1<<ndiv); i++)
{
int ok = 1;
for(int x1 = 0; x1< ndiv; x1++)
{
for(int x2 = 0; x2< ndiv; x2++)
{
if( ( i & (1<<x1) ) and
(i & (1<<x2) ) and
(mask & (1ll<<(x1*ndiv+x2) ) ) )
{
ok = 0; break;
}
}
}
if(ok)
{
//printf("go %d to (%lld, %d)\n", i, mask|cross(cur, i), cur|i);
add(res, mul(ways[i], go(mask|cross(cur, i), cur|i)));
}
CAPITOLUL 11. EJOI 2017 11.3. SIX 407
int main()
{
std::freopen("../six_tests/six.25.in", "r", stdin); // 591780
//std::freopen("six.out", "w", stdout);
ll N;
scanf("%lld", &N);
proc(N);
int res = 0;
for(int i = 1; i< (1<<ndiv); i++)
{
//printf("%d:\n", i);
add(res, ways[i]);
//printf("%d\n", res);
for(int j = 1; j< (1<<ndiv); j++)
{
add(res, mul(mul(ways[i], ways[j]), go(cross(i, j), i|j)));
}
//printf("%d\n", res);
}
printf("%d\n", res);
}
#include <bits/stdc++.h>
map<ll,ll> memo[1<<6];
ll solve(int s, ll p)
{
if(memo[s].find(p)!=memo[s].end())
return memo[s][p];
ll res = 1;
for(int i = 1; i < (1<<f); ++i)
{
CAPITOLUL 11. EJOI 2017 11.3. SIX 408
bool ok = 1;
for(int j = 0; j < f; ++j)
{
for(int k = j; k < f; ++k)
{
if((p&(1ll<<(6*j+k))) && (i&(1<<j)) && (i&(1<<k)))
{
ok = 0;
break;
}
}
}
if(ok)
{
ll nowe = 0;
for(int j = 0; j < f; ++j)
{
for(int k = 0; k < f; ++k)
{
if((s&(1<<j)) && (i&(1<<k)))
nowe |= (1ll<<(6*min(j, k)+max(j, k)));
}
}
memo[s][p] = res;
return res;
}
int main()
{
std::freopen("../six_tests/six.25.in", "r", stdin); // 591780
//std::freopen("six.out", "w", stdout);
cin >> n;
ll curr = n;
for(ll i=2;i*i<=n;++i)
{
if(curr%i==0)
{
fact.eb(i,0);
while(curr%i==0)
{
curr /= i;
++fact.back().second;
}
}
}
if(curr>1)
fact.eb(curr, 1);
f = fact.size();
for(int i = 1; i < (1<<f); ++i)
{
ile[i] = 1;
for(int j = 0; j < f; ++j)
{
if(i&(1<<j))
ile[i] *= fact[j].second;
}
}
return 0;
}
#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
int w[10005];
int k;
ll n;
if (m <= a)
{
a -= m;
}
}
int calc(vector<int> v)
{
if (mm.find(v) != mm.end())
{
return mm[v];
}
int ret = 0;
vector<int> nxt = v;
void solve()
{
scanf("%lld", &n);
vector<pair<ll, int>> vv;
CAPITOLUL 11. EJOI 2017 11.3. SIX 410
while (n % i == 0)
{
++cnt;
n /= i;
}
vv.pb(mp(i, cnt));
}
}
if (n > 1)
{
vv.pb(mp(n, 1));
}
k = vv.size();
int main()
{
std::freopen("../six_tests/six.25.in", "r", stdin); // 591780
//std::freopen("six.out", "w", stdout);
int tt = 1;
while (tt--)
{
solve();
}
return 0;
}
/*************************************************************************
> File Name: Six.cpp
> Author: Roundgod
> Mail: wcysai@foxmail.com
> Created Time: 2018-12-27 17:54:48
************************************************************************/
#include<bits/stdc++.h>
#define S second
return s;
}
return s;
}
return(t==n-1||(d&1)==1);
}
bool isPrime(ll n)
{
if(n<2) return false;
ll a[]={2,3,5,7,11,13,17,19,23,29};
for(ll i=0;i<=9;++i)
if(!test(n,a[i],n-1)) return false;
return true;
}
int prime[MAXN],sz;
bool is_prime[MAXN];
int sieve(int n)
{
int p=0;
memset(is_prime,true,sizeof(is_prime));
is_prime[0]=is_prime[1]=false;
for(int i=2;i<=n;i++)
{
CAPITOLUL 11. EJOI 2017 11.3. SIX 412
if(is_prime[i]) prime[p++]=i;
for(int j=0;j<p;j++)
{
if(i*prime[j]>n) break;
is_prime[i*prime[j]]=false;
if(i%prime[j]==0) break;
}
}
return p;
}
ll n;
int tot=0;
vector<int> fact;
unordered_map<int,int> dp;
int bit[10][10],cc;
int cnt[1000];
int nmask=mask;
for(int i=0;i<sz;i++)
{
if(!(fmask&(1<<i))) continue;
for(int j=i;j<sz;j++)
if(mask&(1<<j))
nmask|=(1<<bit[i][j]);
for(int j=0;j<i;j++)
if(mask&(1<<j))
nmask|=(1<<bit[j][i]);
}
nmask|=fmask;
return nmask;
}
return dp[mask]=ans;
}
int main()
{
std::freopen("../six_tests/six.25.in", "r", stdin); // 591780
//std::freopen("six.out", "w", stdout);
int p=sieve(100000);
scanf("%lld",&n);
for(int i=0;i<p;i++)
{
int cnt=0;
CAPITOLUL 11. EJOI 2017 11.3. SIX 413
while(n%prime[i]==0)
{
n=n/prime[i];
cnt++;
}
if(cnt) fact.push_back(cnt);
}
if(n>1)
{
if(isPrime(n)) fact.push_back(1);
else
{
int r=(int)sqrt(n);
bool f=false;
for(int i=r-10;i<=r+10;i++)
if(1LL*r*r==n)
{
f=true;
fact.push_back(2);
break;
}
if(!f)
{
fact.push_back(1);
fact.push_back(1);
}
}
}
sz=(int)fact.size();
for(int i=0;i<(1<<sz);i++)
{
cnt[i]=1;
for(int j=0;j<sz;j++)
if(i&(1<<j)) cnt[i]*=fact[j];
}
int cc=sz;
for(int i=0;i<sz;i++)
for(int j=i;j<sz;j++)
bit[i][j]=cc++;
printf("%d\n",(dfs(0)-1+MOD)%MOD);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
struct hash_pair
{
template<class T1, class T2>
size_t operator() (const pair<T1, T2> &p) const
{
return hash<T1>{}(p.first) ˆ hash<T2>{}(p.second);
}
};
{
if (mp.count({msk1, msk2}))
return mp[{msk1, msk2}];
if (cnt < 2)
(mp[{msk1, msk2}] += (1LL +
bt(msk1 | 1LL << i - 1,
msk1 & 1ULL << i - 1 | msk2)) *
w[i] % P) %= P;
}
int main()
{
std::freopen("../six_tests/six.25.in", "r", stdin); // 591780
//std::freopen("six.out", "w", stdout);
ll n;
scanf("%lld", &n);
k++;
}
if (n > 1)
w[1 << k++]++;
132
OBS: hash
11.4 Camel
Problema 4 - Camel 100 de puncte
Let’s describe a new ”chess” piece and call it ”camel-tone”. The piece
moves jumping: horizontally or vertically - over two chessboard squares, or
diagonally - over one square. The picture shows a part of the board with a
camel-tone, placed in the center and the positions (marked by x), where it
can go with one move. Of course, it cannot go outside the playing board,
which happens to be a big square, divided into N N little squares. In this
task N is always divisible by 5.
The camel-tone starts at the square in the top-left corner of the board.
The game consists of making a sequence of moves on the board, visiting every square exactly
132
https://en.cppreference.com/w/cpp/utility/hash
. http://www.cplusplus.com/reference/functional/hash/
. https://www.geeksforgeeks.org/stdhash-class-in-c-stl/
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 415
2
once. Moreover, after N 1 moves the piece should be exactly one move away from its starting
position. This is a so-called ”camel-tonian cycle”!
Task
Write a program camel to find any possible way to play the game, or to report that the cycle
is impossible.
Input
A single line is read from the standard input, containing only one integer N .
Output
The program has to write to the standard output:
one line with the message NO, if you establish that the cycle is impossible or
N lines, each containing N space separated numbers, which are the different positive integers
2
between 1 and N inclusive. The first number in the first line is 1. The output represents the
playing board (N N squares), where integers indicate the consecutive occupied positions.
See the example below.
Constraints
N is divisible by 5
5&N & 1000
Grading
There is a test with N 5 that is worth 20% of the points for the task
The remaining 16 tests are worth 5% of the points each.
Example
Sample Input Sample Output
10 1 52 29 8 51 28 9 50 37 16
85 95 59 86 94 66 87 93 65 88
40 19 100 39 18 76 38 17 77 49
2 53 30 7 58 27 10 89 36 15
84 96 60 75 99 67 72 92 64 71
41 20 82 44 23 90 45 24 78 48
3 54 31 6 57 26 11 68 35 14
83 97 61 74 98 62 73 91 63 70
42 21 81 43 22 80 46 25 79 47
4 55 32 5 56 33 12 69 34 13
Explanation: The camel-tone starts at the top left position (row:1, column:1), numbered 1. The
second occupied position is (row:4, column:1), so it is numbered 2. The next position is (row:7,
column: 1), and it is numbered 3, and so on. The final (hundredth) occupied position is (row:3,
column:3), and it is at one move away from the starting position.
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 416
The task concerns finding a Hamiltonian cycle in a graph, defined by some neighborhood on a
rectangular network. Generally, it is an NP-complete problem and its solution needs exhausting
algorithms. For small values of N this can be done here, too. For bigger values, some rule is to
be found to realize the tour.
The solution, if it exists, is even far not unique, which gives the chance for different rules to
be noticed. A usual way is to split the given graph into smaller subgraphs, each with existing
Hamiltonian path and after walking it, to provide a legal transition to the next subgraph. We use
this method here as well.
The idea is to be able to construct a Hamiltonian path for a square with side of length 5,
with given start and final positions. For to calculate quicker the first desired path using standard
backtracking, we can often diminish the final demands to only the desired row or column, setting
free the other dimension, as it, more often than not, does not matter. What counts is to get
correctly to the next subgraph - a 5 5 square. If we can solve subtasks of this kind, we can divide
the big board into smaller 5 5 squares, every one of which can be travelled without leaving its
boundaries, finishing the path in a place, which assures a correct move to the next 5 5 square.
If we denote the number of columns (and rows) of 5 5 squares with T , a Hamiltonian tour on it
is easy to be seen. In the tours shown below every square is in fact a 5 5 square:
It appears that we can use a small number of different Hamiltonian paths on a 5 5 square, less
than 20. This makes it possible to remember them and reuse the found ones. They are identified
by their start and end positions, as, once again, the final row or column usually do not matter.
Nothing remains but to take into consideration the necessity of leaving ”steps” in the top left
5 5 corner: one or two unvisited little squares, leading to the top left little square. This should
be the end of the path, transforming it into a cycle. One little square is enough for ”stepping”
when is even, and, if is odd, at least two little squares are needed. Of course, this is true for
”natural” walks like the one above. As one can guess, the number of suitable paths on the board
can be large.
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 417
#include <bits/stdc++.h>
return c;
}
matrix Def;
if (st == 1)
return a;
return b;
}
ll myrand()
{
ll ZR = (XR * AR + YR * BR + CR) % MOD;
XR = YR;
YR = ZR;
return ZR;
}
ll sqr(ll x)
{
return x * x;
}
int q[1000][1000];
vector<int> p[10];
vector<int> DEFAULT;
int n;
int main()
{
std::freopen("../camel_tests/camel.17.in", "r", stdin);
std::freopen("camel.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
p[0] = {8, 21, 2, 7, 20, 16, 5, 10, 17, 4, 1, 13,
25, 22, 12, 9, 18, 3, 6, 19, 15, 23, 11, 14, 24};
p[1] = {7, 12, 1, 6, 11, 15, 4, 9, 14, 3, 21, 18,
25, 22, 19, 8, 13, 2, 5, 10, 16, 23, 20, 17, 24};
p[2] = {8, 16, 2, 9, 17, 13, 5, 19, 14, 4, 21, 10,
25, 22, 1, 7, 15, 3, 6, 18, 12, 23, 20, 11, 24};
p[3] = {14, 9, 20, 15, 10, 6, 17, 12, 7, 18, 21, 3,
25, 22, 2, 13, 8, 19, 16, 11, 5, 23, 1, 4, 24};
p[4] = {0, 21, 14, 11, 22, 16, 9, 24, 19, 8, 4, 12,
0, 5, 13, 25, 20, 15, 10, 23, 17, 6, 3, 18, 7};
DEFAULT = {1, 9, 18, 2, 10, 6, 15, 12, 7, 16, 21, 3,
25, 22, 19, 13, 8, 17, 14, 11, 5, 23, 20, 4, 24};
if (n == 5)
{
fill(0, 0, 0, DEFAULT);
}
else
if (n % 10 == 0)
{
q[0][0] = 1;
q[2][2] = 2;
for (int it = 0; it < n; it += 10)
{
if (it == 0)
fill(it, 5, 2, 0);
else
fill(it, 5, it * (n - 5) + 2, 1);
for (int i = 10; i < n; i += 5)
fill(it, i, it * (n - 5) + 2 + (i / 5 - 1) * 25, 0);
fill(it + 5, n - 5, it * (n - 5) + 2 + (n - 5) * 5, 1);
for (int i = 5; i < n - 5; i += 5)
fill(it + 5, i, it * (n-5) + 2 + (n-5) * 5 + 5 * (n-i-5), 2);
}
fill(n - 5, 0, 2 + (n - 5) * n, 2);
for (int i = n - 10; i > 0; i -= 5)
fill(i, 0, 2 + (n - 5) * n + (n - i - 5) * 5, 3);
fill(0, 0, n * n - 25, 4);
}
else
{
p[4] = {0, 8, 20, 23, 7, 13, 16, 5, 10, 15, 19, 22,
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 419
q[0][0] = 1;
q[2][2] = 2;
q[4][4] = 3;
fill(n - 5, 0, 3 + (n - 5) * n, 2);
#include<bits/stdc++.h>
int a,s,d[1002][1002],f,g,h,j,k,l,i,n,m,d1,d2,s1,s2;
pair<int,int> p[8]={{-3,0},{-2,2},{0,3},{2,2},{3,0},{2,-2},{0,-3},{-2,-2}};
for(int i=0;i<8;i++)
{
if(init(i1+p[i].first,i2+p[i].second,sv+1)) return 1;
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 420
d[i1][i2]=0;
return 0;
}
d[i1][i2]=0;
return 0;
}
main()
{
std::freopen("../camel_tests/camel.17.in", "r", stdin);
std::freopen("camel.out", "w", stdout);
cin>>n;
if(n>5) d[2][2]=n*n;
init(0,0,1);
if(n>5)
{
k=25;
i=0;
for(a=5;a<n-5;a+=5)
{
d1=0,d2=a+5;
s1=i;
s2=a;
dfs(0,a,k);
k+=25;
}//cout<<a<<"%";
d1=5;
d2=n-1;
s1=i;
s2=a;
dfs(0,a,k);
k+=25;
l=-1;
int st2=5,st1=n-1;
for(a=n-1;a>=0;a-=5)
{
l*=-1;
swap(st1,st2);
if(a==9 && n%2==1)
{
s1=n-5;
s2=5;
d1=n-1;
d2=4;
dfs(i,a,k);
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 421
k+=25;
}
for(i=st1;i!=st2-4*l;i+=5*l)
{//cout<<i<<" "<<a<<" "<<st2<<endl;
if(a==9 && n%2==1)
{
s1=i-4;
s2=0;
//cout<<s1<<" "<<s2<<" "<<d1<<" "<<d2<<" "<<i<<" "<<a<<endl;
if(s1==5)
{
d1=2;d2=2;
dfs(i,a-5,k);
break;
}
d1=i-5;
d2=5;
dfs(i,a-5,k);
k+=25;
s1=i-9;
s2=5;
d1=i-5;
d2=4;
dfs(i-5,a-4,k);
k+=25;
continue;
}
d1=i+5*l;
d2=a;
s1=min(i,i+4*l);
s2=a-4;
if(i==st1)
dfs(i,a,k);
else
{
for(int i=s1;i<s1+5;i++)
{
for(int a=s2;a<s2+5;a++)
{//cout<<i<<" "<<a<<" "<<s1<<endl;
d[i][a]=d[i-5*l][a]+25;
}
}
}
k+=25;
}
dfs(i,a-5,k);
break;
//break;
}
d1=i+4*l;
d2=a-5;
s1=min(i,i+4*l);
s2=a-4;
if(s1==5 && s2==0) d1=2,d2=2;
dfs(i,a,k);
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 422
k+=25;
}
}/////
for(i=0;i<n;i++)
{
for(a=0;a<n;a++)
{
printf("%d ",d[i][a]);
}
cout<<endl;
}
}
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cstdio>
#include <numeric>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <list>
#include <cmath>
#include <bitset>
#include <cassert>
#include <queue>
#include <stack>
#include <deque>
/** Interface */
/** Read */
if (pos == len)
{
return -1;
}
return buf[pos++];
}
return c;
}
return s == 1 ? x : -x;
}
/** Write */
write_buf[write_pos++] = x;
}
char s[24];
int n = 0;
while (x || !n)
s[n++] = ’0’ + x % 10, x /= 10;
while (n--)
writeChar(s[n]);
if (end)
writeChar(end);
}
struct Flusher
{
˜Flusher()
{
if (write_pos)
fwrite(write_buf, 1, write_pos, stdout), write_pos = 0;
}
} flusher;
int ans[MAXN][MAXN];
vector<int> p[10];
vector<int> base;
int n;
int main()
{
std::freopen("../camel_tests/camel.17.in", "r", stdin);
std::freopen("camel.out", "w", stdout);
n = readInt();
p[0] = {8, 21, 2, 7, 20, 16, 5, 10, 17, 4, 1, 13, 25,
22, 12, 9, 18, 3, 6, 19, 15, 23, 11, 14, 24};
p[1] = {7, 12, 1, 6, 11, 15, 4, 9, 14, 3, 21, 18, 25,
22, 19, 8, 13, 2, 5, 10, 16, 23, 20, 17, 24};
p[2] = {8, 16, 2, 9, 17, 13, 5, 19, 14, 4, 21, 10, 25,
22, 1, 7, 15, 3, 6, 18, 12, 23, 20, 11, 24};
p[3] = {14, 9, 20, 15, 10, 6, 17, 12, 7, 18, 21, 3, 25,
22, 2, 13, 8, 19, 16, 11, 5, 23, 1, 4, 24};
p[4] = {0, 21, 14, 11, 22, 16, 9, 24, 19, 8, 4, 12,
0, 5, 13, 25, 20, 15, 10, 23, 17, 6, 3, 18, 7};
base = {1, 9, 18, 2, 10, 6, 15, 12, 7, 16, 21, 3, 25,
22, 19, 13, 8, 17, 14, 11, 5, 23, 20, 4, 24};
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 425
if (n == 5)
{
paint(0, 0, 0, base);
}
else
{
if (n % 10 == 0)
{
ans[0][0] = 1;
ans[2][2] = 2;
for (int it = 0; it < n; it += 10)
{
if (it == 0)
{
paint(it, 5, 2, 0);
}
else
{
paint(it, 5, it * (n - 5) + 2, 1);
}
paint(it + 5, n - 5, it * (n - 5) + 2 + (n - 5) * 5, 1);
paint(n - 5, 0, 2 + (n - 5) * n, 2);
ans[0][0] = 1;
ans[2][2] = 2;
ans[4][4] = 3;
paint(it + 5, n - 5, it * (n - 5) + 3 + (n - 5) * 5, 1);
paint(n - 5, 0, 3 + (n - 5) * n, 2);
writeChar(’\n’);
}
return 0;
}
#include <bits/stdc++.h>
do
{
133
(t*=10)+=ch-’0’;
ch=getchar();
} while (’0’<=ch&&ch<=’9’);
t*=f;
}
int d[5][5]={
{1,11,18,4,10},
{16,22,8,13,23},
{19,5,25,20,6},
{2,12,17,3,9},
{15,21,7,14,24}
133
t=t*10+ch-’0’;
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 427
};
pair<int,int> to[1010][1010];
int n,ans[1010][1010];
int main()
{
std::freopen("../camel_tests/camel.17.in", "r", stdin);
std::freopen("camel.out", "w", stdout);
read(n);
int x=1,y=1,cnt=0;
while (1)
{
ans[x][y]=++cnt;
pair<int,int> tmp=to[x][y];
x=tmp.first,
y=tmp.second;
return 0;
}
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cstdio>
#include <numeric>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <set>
#include <map>
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 428
#include <unordered_map>
#include <unordered_set>
#include <list>
#include <cmath>
#include <bitset>
#include <cassert>
#include <queue>
#include <stack>
#include <deque>
/** Interface */
/** Read */
/** Write */
char s[24];
int n = 0;
while (x || !n)
s[n++] = ’0’ + x % 10, x /= 10;
while (n--)
writeChar(s[n]);
if (end)
writeChar(end);
}
struct Flusher
{
˜Flusher()
{
if (write_pos)
fwrite(write_buf, 1, write_pos, stdout), write_pos = 0;
}
} flusher;
int ans[MAXN][MAXN];
vector<int> p[10];
vector<int> base;
int n;
int main()
{
std::freopen("../camel_tests/camel.17.in", "r", stdin);
std::freopen("camel.out", "w", stdout);
n = readInt();
p[0] = {8, 21, 2, 7, 20, 16, 5, 10, 17, 4, 1, 13, 25,
22, 12, 9, 18, 3, 6, 19, 15, 23, 11, 14, 24};
p[1] = {7, 12, 1, 6, 11, 15, 4, 9, 14, 3, 21, 18, 25,
22, 19, 8, 13, 2, 5, 10, 16, 23, 20, 17, 24};
p[2] = {8, 16, 2, 9, 17, 13, 5, 19, 14, 4, 21, 10, 25,
22, 1, 7, 15, 3, 6, 18, 12, 23, 20, 11, 24};
p[3] = {14, 9, 20, 15, 10, 6, 17, 12, 7, 18, 21, 3, 25,
22, 2, 13, 8, 19, 16, 11, 5, 23, 1, 4, 24};
p[4] = {0, 21, 14, 11, 22, 16, 9, 24, 19, 8, 4, 12, 0,
5, 13, 25, 20, 15, 10, 23, 17, 6, 3, 18, 7};
base = {1, 9, 18, 2, 10, 6, 15, 12, 7, 16, 21, 3, 25,
22, 19, 13, 8, 17, 14, 11, 5, 23, 20, 4, 24};
if (n == 5)
{
paint(0, 0, 0, base);
}
else
{
if (n % 10 == 0)
{
ans[0][0] = 1;
ans[2][2] = 2;
for (int it = 0; it < n; it += 10)
{
if (it == 0)
{
paint(it, 5, 2, 0);
}
else
{
paint(it, 5, it * (n - 5) + 2, 1);
}
paint(it + 5, n - 5, it * (n - 5) + 2 + (n - 5) * 5, 1);
for (int i = 5; i < n - 5; i += 5)
{
paint(it + 5, i, it*(n-5)+2+(n-5)*5+5*(n-i-5), 2);
}
}
paint(n - 5, 0, 2 + (n - 5) * n, 2);
for (int i = n - 10; i > 0; i -= 5)
{
paint(i, 0, 2 + (n - 5) * n + (n - i - 5) * 5, 3);
}
ans[0][0] = 1;
ans[2][2] = 2;
ans[4][4] = 3;
paint(it + 5, n - 5, it * (n - 5) + 3 + (n - 5) * 5, 1);
for (int i = 5; i < n - 5; i += 5)
{
paint(it+5, i, it*(n-5)+3+(n-5)*5+5*(n-i-5), 2);
}
}
paint(n - 5, 0, 3 + (n - 5) * n, 2);
for (int i = n - 10; i > 0; i -= 5)
{
paint(i, 0, 3 + (n - 5) * n + (n - i - 5) * 5, 3);
}
paint(0, 0, n * n - 25, 4);
}
}
writeChar(’\n’);
}
return 0;
}
#include<iostream>
typedef struct
{
int row,col;
bool vis;
} Place;
int N;
Place p[MAXN*MAXN+1];
Place offs[8]={
{0,3,0},
{0,-3,0},
{3,0,0},
CAPITOLUL 11. EJOI 2017 11.4. CAMEL 432
{-3,0,0},
{2,2,0},
{2,-2,0},
{-2,2,0},
{-2,-2,0}
};
void showPlaces()
{
for (int i=1;i<=N*N;i++)
{
printf("%d:",i);
showPlace(&p[i]);
printf(" ");
}
printf("\n");
}
return false;
}
int check()
{
for (int i=2;i<=N*N;i++)
{
if (p[i].vis) return 1;
if (!isCorr(i-1,i)) return 2;
p[i].vis=true;
}
if (!isCorr(N*N,1)) return 3;
return 0;
}
int main()
{
char b[512];
FILE *f;
f=fopen("../camel_tests/camel.17.in","r");//s[1] - in-file
if (!f)
{
fprintf(stderr,"In-file not found\n");
return 0;
}
fscanf(f,"%d",&N);
fclose(f);
if (!f)
{
printf("0\nResult not found\n");
return 0;
}
if (N<5)
{
fscanf(f,"%s",b);
CAPITOLUL 11. EJOI 2017 11.5. EXPERIENCE 433
if (strcmp(b,"NO"))
printf("0\nIncorrect output\n");
else
printf("1\nCorrect\n");
fclose(f);
return 0;
}
int k;
fscanf(f,"%d",&k);
if (k<1 || k>N*N)
{
printf("0\nIncorrect output value\n");
fclose(f);
return 0;
}
p[k].row=r;
p[k].col=c;
p[k].vis=false;
}
fclose(f);
switch (check())
{
case 0:{printf("1\nCorrect\n");break;}
case 1:{printf("0\nPlace visited twice\n");break;}
case 2:{printf("0\nInvalid move\n");break;}
case 3:printf("0\nIncorrect finish place\n");
}
return 0;
}
11.5 Experience
Problema 5 - Experience 100 de puncte
Company X has N employees. The company has a strict hierarchical tree-like structure - the
CEO (Chief Executive Officer) stands at the top (root of the tree), he has some number of direct
subordinates, who also have direct subordinates and so on, until we reach regular employees, who
have no subordinates (leaves of the tree).
The employees are numbered with integers from 1 to N . The CEO has number 1, but the
other numbers have nothing to do with the hierarchy. Each employee has some experience - the
i-th employee has experience, denoted by non-negative integer Wi .
The company has a large number of group projects to complete and the management has
decided to split all of the employees into different groups (teams), so that the following conditions
are satisfied:
Each team must consist of at least one person and each person must belong to exactly one
team.
Each team must consist only of people, who are consecutive subordinates of one another. A
CAPITOLUL 11. EJOI 2017 11.5. EXPERIENCE 434
N & 20 in the tests that are worth 20% of the points for the task
N & 5000 in the tests that are worth 50% of the points for the task
Each employee has at most one direct subordinate in the tests that are worth 10% of the
points for the task
Example
Sample Input Sample Output
7 6
5536233
16
53
15
62
24
67
Explanation:
CAPITOLUL 11. EJOI 2017 11.5. EXPERIENCE 435
One possible configuration that maximizes the total experience increase is {1, 5, 3}, {6, 2, 4},
{7}. There is another configuration with the same maximal total experience increase - {1, 5}, {3},
{6, 2, 4}, {7}.
1 Introduction
The problem statement in short is:
We have a it tree in which every vertex has a weight. We want to decompose the tree into
vertical chains, such that every vertex belongs to exactly one chain and the sum of ”values” of the
chains is maximum. The value of a chain is defined as Wmax Wmin , where Wmax is the maximal
weight of a vertex in the chain and Wmin is the minimal weight.
We want our solution to be O N log N or O N in time, where N is the number of vertices
in the tree.
2 Observations
To solve the problem we first need to make some observations. The most important one is
that at least one of the following is true for every chain:
The chain should start from the vertex with the largest weight and finish on the vertex with
the smallest weight from this path.
The chain should start from the vertex with the smallest weight and finish on the vertex
with the largest weight from this path.
This is true, because if we have a path not satisfying one of the above conditions we can divide
this path into several smaller ones without decreasing the initial value.
The second observation is that there exists an optimal decomposition into chains such that the
weights of the vertices in each chain are either increasing or decreasing. This observation is again
true because if there was a chain not satisfying this, we could have divided it into several smaller
ones without decreasing its initial values.
3 Main part
Using the above observations we can solve the problem in linear time.
The authors solution uses only the first observation. Also there exists a solution which is easier
to be implemented but it uses both observations. Both solutions are linear in time.
To get partial points one could have implemented a brute force for 10 points. To get 40 points
one could implement a solution quadratic in time.
3.1 Solution for 40 points
We will solve the problem with dynamic programming.
Our state will be dpu which is the maximal sum of values of chains in a decomposition of
the subtree rooted at vertex u. We know that there is a chain starting at vertex u and finishing
in a vertex in its subtree. Lets denote this vertex as v and the set of vertices which belong to
the path from u to v as S. Also lets denote by Ci the sum of the dp values of the children of u
(Ci < x"children i dpx ). From here we get that for the chain starting at u and finishing at v, the
< <
value of dpu will be x"S Cx x"Surux dpx maxx"S Wx minx"S Wx . And so we can find dpu
by checking this value for all vertices v in the subtree of u and then by getting the maximal value.
2
This solution is O N . If implemented well it can get even 50 points.
3.2 Author’s Solution
We will use dynamic programming to solve the problem. With each vertex we will associate 3
values:
dpu,2 - maximum sum of values to cover the subtree of u, if we have an unfinished path, which
includes the root and a fixed minimum (the value of the minimum has been substracted in
advance).
#include <bits/stdc++.h>
int n, W[MAXN];
vector<int> adj[MAXN];
void read()
{
cin >> n;
for(int i = 1; i <= n; i++)
cin >> W[i];
int64_t dp[MAXN][3];
dp[u][1] = S + W[u];
dp[u][2] = S - W[u];
for(int v: adj[u])
if(v != pr)
{
dp[u][1] = max(dp[u][1], (int64_t)(S + dp[v][1] - dp[v][0]));
dp[u][2] = max(dp[u][2], (int64_t)(S + dp[v][2] - dp[v][0]));
}
void solve()
{
dfs(1);
cout << dp[1][0] << endl;
}
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
std::freopen("experience.out", "w", stdout);
ios_base::sync_with_stdio(false);
cin.tie(NULL);
read();
CAPITOLUL 11. EJOI 2017 11.5. EXPERIENCE 438
solve();
return 0;
}
#include <bits/stdc++.h>
//#ifndef M_PI
//const ld M_PI = acos(-1.0);
//#endif
template<typename T>
inline void setmax(T& a, T b)
{
if (a < b) a = b;
}
template<typename T>
inline void setmin(T& a, T b)
{
if (a > b) a = b;
}
vector<int> ch[N];
ll dp1[N], dp2[N];
int w[N];
void dfs(int u)
{
for (int v : ch[u])
dfs(v);
ll sum = 0;
for (int v : ch[u])
sum += max(dp1[v], dp2[v]);
dp1[u] = sum;
dp2[u] = sum;
for (int v : ch[u])
{
ll* dp = w[u] > w[v] ? dp1 : dp2;
setmax(dp[u], sum - max(dp1[v], dp2[v]) + abs(w[u] - w[v]) + dp[v]);
}
}
CAPITOLUL 11. EJOI 2017 11.5. EXPERIENCE 439
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
std::freopen("experience.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);
//srand((unsigned) chrono::high_resolution_clock::\
now().time_since_epoch().count());
int n;
cin >> n;
forn(i, 1, n)
{
int u, v;
cin >> u >> v;
--u, --v;
p[v] = u;
ch[u].eb(v); // emplace_back
}
dfs(0);
#include <bits/stdc++.h>
#define X first
#define Y second
int n,w[N];
vector <int> v[N];
int q[N],pa[N];
ll f[N][3];
void BFS()
{
int top=1,bot=1;
q[1]=1;
while (top<=bot)
{
int x=q[top++];
for(auto y:v[x])
if (y!=pa[x])
{
pa[y]=x;
q[++bot]=y;
}
}
}
CAPITOLUL 11. EJOI 2017 11.5. EXPERIENCE 440
ll solve()
{
BFS();
for(int i=n;i>=1;i--)
{
int x=q[i];
f[x][0]=f[x][1]=-inf;
f[x][2]=0;
for(auto y:v[x])
if (y!=pa[x])
f[x][2]+=*max_element(f[y],f[y]+3);
for(auto y:v[x])
if (y!=pa[x])
{
ll sub=*max_element(f[y],f[y]+3);
if (w[y]>=w[x])
f[x][0]=max(f[x][0],
f[x][2]-sub+max(f[y][0], f[y][2])+w[y]-w[x]);
else
f[x][1]=max(f[x][1],
f[x][2]-sub+max(f[y][1], f[y][2])+w[x]-w[y]);
}
// cout<<x<<" "<<f[x][0]<<" "<<f[x][1]<<" "<<f[x][2]<<’\n’;
}
return *max_element(f[1],f[1]+3);
}
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
std::freopen("experience.out", "w", stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",w+i);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
cout<<solve();
}
134
OBS: max element returnează iterator, *max element returnează valoare!
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <numeric>
#include <iterator>
#include <cstring>
int n;
int a[100005];
vector<int> e[100005];
long long dp[100005][2];
void solve(int x)
134
https://en.cppreference.com/w/cpp/algorithm/max_element
CAPITOLUL 11. EJOI 2017 11.5. EXPERIENCE 441
{
long long sum = 0;
dp[x][0] = sum;
dp[x][1] = sum;
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
std::freopen("experience.out", "w", stdout);
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cerr.tie(nullptr);
cin >> n;
for (int i=1; i<=n; i++)
{
cin >> a[i];
}
solve(1);
#include <bits/stdc++.h>
int n, w[100000];
vector<int> g[100000];
long long dp[100000][2], ans[100000];
void dfs(int v)
{
long long sum = 0;
dp[v][0] = -w[v];
dp[v][1] = w[v];
CAPITOLUL 11. EJOI 2017 11.5. EXPERIENCE 442
for(int to : g[v])
{
dfs(to);
sum += ans[to];
dp[v][0] = max(dp[v][0], dp[to][0] - ans[to]);
dp[v][1] = max(dp[v][1], dp[to][1] - ans[to]);
}
dp[v][0] += sum;
dp[v][1] += sum;
ans[v] = max(dp[v][0] + w[v], dp[v][1] - w[v]);
}
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
std::freopen("experience.out", "w", stdout);
ios::sync_with_stdio(0);
cin >> n;
for(int i = 0; i < n; i++)
{
cin >> w[i];
}
dfs(0);
cout << ans[0];
}
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
struct E
{
int to,next;
} mem[N<<1];
int n,num,x,y;
int w[N],head[N];
ll dp[N][2];
int u; ll ans,sum=0;
for (int j=head[k];j;j=mem[j].next)
{
u=mem[j].to;
if (u==pre) continue;
ans=dfs(u,k);
sum+=ans;
if (w[k]>w[u])
dp[k][0]=max(dp[k][0],dp[u][0]+1ll*w[k]-1ll*w[u]-ans);
if (w[k]<w[u])
dp[k][1]=max(dp[k][1],dp[u][1]+1ll*w[u]-1ll*w[k]-ans);
}
dp[k][0]+=sum;
dp[k][1]+=sum;
return max(dp[k][0],dp[k][1]);
}
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
std::freopen("experience.out", "w", stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&w[i]);
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
printf("%lld\n",dfs(1,0));
return 0;
}
#include <iostream>
#include <vector>
ll n,val[100123],i,a,b;
vector<ll> sus[100123];
ll dp[100123][2];
for(ll g=0;g<sus[cur].size();g++)
{
ll z=sus[cur][g];
if(z==par)continue;
ll f=max( dp[z][0] , dp[z][1] );
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
std::freopen("experience.out", "w", stdout);
ios_base::sync_with_stdio(false);
cin>>n;
for(i=1;i<=n;i++)
cin>>val[i];
for(i=1;i<n;i++)
{
cin>>a>>b;
sus[a].push_back(b);
sus[b].push_back(a);
}
dfs( -1 , 1 );
return 0;
}
#include<bits/stdc++.h>
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
CAPITOLUL 11. EJOI 2017 11.5. EXPERIENCE 445
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n, u, v;
cin >> n;
dfs(1, -1);
return 0;
}
#include<bits/stdc++.h>
//#define gc getchar
{
a=-a;
putchar(’-’);
}
write(a);
puts("");
}
if(w[p]<=w[v[p][i]])
dp[p][1]=max(dp[p][1],dp[v[p][i]][1]+w[v[p][i]]-w[p]-zs);
}
dp[p][0]+=sum;
dp[p][1]+=sum;
}
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
std::freopen("experience.out", "w", stdout);
n=read();
for(int i=1;i<=n;i++)
w[i]=read();
for(int i=1;i<n;i++)
{
int s=read(),
t=read();
v[s].push_back(t);
v[t].push_back(s);
}
dfs(1,0);
cout<<max(dp[1][0],dp[1][1])<<endl;
}
#include <bits/stdc++.h>
struct state
{
long long v0, v1, v2;
};
void solve(int u,
vector<state>& mem,
const vector<int>& a,
CAPITOLUL 11. EJOI 2017 11.5. EXPERIENCE 447
const vector<vector<int>>& g)
{
if ((int) g[u].size() == 0)
{
return;
}
return;
}
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
std::freopen("experience.out", "w", stdout);
ios_base::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
return 0;
}
#include<bits/stdc++.h>
vector<int> adj[maxn];
int a[maxn];
ll dp[maxn] , pd[maxn];
void dfs(int v)
{
ll sum = 0;
for(auto u : adj[v])
{
dfs(u);
for(auto u : adj[v])
{
ll k = max(dp[u] , pd[u]);
int main()
{
std::freopen("../experience_tests/experience.18.in", "r", stdin);
std::freopen("experience.out", "w", stdout);
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
adj[a].pb(b);
}
CAPITOLUL 11. EJOI 2017 11.6. GAME 449
dfs(0);
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../experience_tests/experience.18.in",
(char*)"experience.out",
(char*)"../experience_tests/experience.18.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
11.6 Game
Problema 6 - Game 100 de puncte
Alice and Bob are playing the following game:
They are given a sequence of N positive integers with values less than or equal to N . The
elements of the sequence are numbered from 1 to N . Equal numbers may exist in the sequence.
A set S is created in the beginning of the game, containing the first P elements of the sequence.
Note that S may be a multiset - it may contain equal elements. The players take turns to play
and Alice is playing first. Each move is made as follows:
1) The player whose turn has come, selects one number from the set S and takes it away, adding
its value to his/her score (initially, the score of both players is 0).
2) The next number in the sequence, if any left at all, is added to the set S (if the sequence is
already empty, this action is skipped). This is to say, that after the first taking from S, the
number indexed with P 1 is added to the set, after the second one - the number indexed
with P 2 is added, etc.
The game continues, until the set S becomes empty. We assume that each player does their best
to maximize their own score. The game’s result is the number obtained by subtracting the points,
collected by Bob, from those, collected by Alice.
Task
Write a program game, which has to process K games on a given starting sequence.
Input
Two space separated positive integers N and K are read from the first line of the standard
input.
The second line consists of N space separated positive integers a1 , a2 , ..., aN , representing the
elements of the given sequence.
CAPITOLUL 11. EJOI 2017 11.6. GAME 450
The third line contains K space separated positive integers p1 , p2 , ..., pK , each defining the
starting set S, created from the given sequence (taking the first pi elements) and intended for the
i-th game, i 1, 2, ..., K.
Output
The program should print to the standard output K lines, each containing a single integer -
the corresponding game’s result. Line number i should contain the result of the game number i
(the games are numbered from 1 to K by the input).
Constraints
Example
Sample input Sample output
52 2
24235 6
43
Explanation: The input data determines that your program will process two games. For both
games, the given sequence is the same, but for the first game P 4 and the starting multiset S is
{2, 4, 2, 3}, and for the second game, P 3 and S is {2, 4, 2}.
Exponential solution
For very small constraints we can simulate the games with exponential complexity - we simply
try all possible ways the game could go. Since on every turn a player can have many different
choices, this solution runs very slowly. It would work for about N & 10, depending on the
implementation.
Polynomial solutions
The main observation in the problem is the following statement:
The optimal choice for the player whose turn it is is to take the largest number in the multiset.
This statement is obvious, since taking any other number does not obstruct the other player
in any way and only reduces the players own score.
In such case, we can just simulate all K games.
2
Solution for O N K
On every turn, we have to find the largest number in the multiset. We can do this by simply
iterating through the multiset linearly. Since its size can be at most O N , the complexity for the
2 2
simulation of a single game is O N and the total complexity of the solution is O N K .
Solution for O N K log N
We can improve our previous solution by keeping the elements that are in the multiset in
some structure that allows to quickly find the maximum number, as well as to remove the largest
element and to add new elements. There are many structures that support these operations with
logarithmic complexity per operation. The competitors can implement a structure of their own
CAPITOLUL 11. EJOI 2017 11.6. GAME 451
or use one of the STL structures - for example priority queue or set/map. The best complexity
that can be obtained using a structure of this kind is O N log N for the simulation of a single
game and hence a total complexity of O N K log N .
Solution for O N K
In order to improve the efficiency of our simulation we have to make the following observation:
If in a certain moment the number that is being added to the multiset is the largest number in
the multiset, then this number will be taken on the very next turn.
This statement follows directly from the optimal playing strategy. In such case, let us define:
countx = the amount of times we have the number x in the multiset at a certain moment
Since all numbers are up to N , the size of count is also N .
The optimal move at a certain moment is to take the largest x, such that countx % 0. Adding
and removing numbers can be done in O 1 time by simply increasing or decreasing the respective
value in count with 1. The algorithm to quickly simulate a single game is as follows:
We begin with a pointer ptr N and we want to have countx 0 for every x % ptr at any
moment. To find the optimal choice at a certain moment we reduce the pointer until we reach
countptr % 0. When we are adding a new number A to the multiset, we have two options:
1. If A % ptr, then we remember that this number will be taken on the very next move. We
don’t have to update count at all.
2. If A & ptr then we can simply add the number and find the optimal choice using the pointer.
Since we reduce the pointer at most N times and process every addition in constant time,
the total amortized complexity for the simulation of a single game is O N . Thus we get a total
complexity of O N K .
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <numeric>
#include <iterator>
#include <cstring>
int n;
int a[100005], c[100005];
int main()
{
std::freopen("../game_tests/game.20.in", "r", stdin);
std::freopen("game.out", "w", stdout);
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cerr.tie(nullptr);
int q;
cin >> n >> q;
while (q--)
{
int k, p = 0, e = 0;
cin >> k;
for (int i=1; i<=k; i++)
{
c[a[i]]++;
p = max(p, a[i]);
}
int j = k;
long long sum = 0;
for (int step=1; step<=n; step++)
{
if (e != 0)
{
if (step & 1)
{
sum += e;
}
else
{
sum -= e;
}
e = 0;
}
else
{
if (step & 1)
{
sum += p;
}
else
{
sum -= p;
}
c[p]--;
while (p > 0 && c[p] == 0)
{
p--;
}
}
#include <bits/stdc++.h>
int main()
{
std::freopen("../game_tests/game.20.in", "r", stdin);
std::freopen("game.out", "w", stdout);
int n, k;
cin >> n >> k;
vector<int> A(n);
for (int i = 0; i < n; i++) cin >> A[i];
ll ans = 0;
int sn = 1, last = -1;
if (p + it < n)
{
if (A[p + it] > pos)
last = A[p + it];
else
last = -1, cnt[A[p + it]]++;
}
else
{
last = -1;
}
sn = -sn;
}
printf("%lld\n", ans);
}
return 0;
}
#include<bits/stdc++.h>
ll a[ARRS];
pair<ll,ll> b[ARRS];
int main()
{
std::freopen("../game_tests/game.20.in", "r", stdin);
std::freopen("game.out", "w", stdout);
ll n,p,m,q;
ll p1,p2,k;
cin>>n>>q;
for(int i=0; i<n; i++)
{
cin>>a[i];
b[i]={a[i],i};
}
sort(b,b+n);
while(q--)
{
cin>>k;
ll c=0,x=0;
while(c<k-1)
{
if(b[x].sc<k-1)c++;
x++;
}
x--;
ll d=1,p=0;
for(int i=k-1; i<n; i++)
{
//cout<<i<<" -> "<<x<<" "<<b[x].fr<<" "<<b[x].sc<<" "<<p<<endl;
if(a[i]>=b[x].fr)
p+=a[i]*d;
else
{
p+=b[x].fr*d;
x--;
while(x&&b[x].sc>i)x--;
}
d=d*-1;
}
while(x>=0)
{
p+=b[x].fr*d;
d*=-1;
x--;
}
cout<<p<<endl;
}
return 0;
}
#include<cstdio>
int f[100005],v[100005];
int main()
{
std::freopen("../game_tests/game.20.in", "r", stdin);
CAPITOLUL 11. EJOI 2017 11.6. GAME 455
int n,k,i,i1,poz,num,urmat=0,p,rand=1;
long long a=0,b=0;
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++)
scanf("%d",&v[i]);
for(i1=1;i1<=k;i1++)
{
scanf("%d",&p);
for(i=1;i<=p;i++)
f[v[i]]++;
num=100000;
a=0;
b=0;
while(f[num]==0)
num--;
urmat=num;
rand=1;
poz=p+1;
while(num!=0)
{
if (rand==1)
a=a+1LL*urmat;
else
b=b+1LL*urmat;
f[urmat]--;
if (v[poz]>num && poz<=n)
urmat=v[poz],poz++;
else
{
if (poz<=n)
{
f[v[poz]]++;
poz++;
}
urmat=num;
}
rand=1-rand;
}
printf("%lld\n",a-b);
for(i=1;i<=100000;i++)
f[i]=0;
}
return 0;
}
#include <bits/stdc++.h>
int n, k, a[maxN];
int pos[maxN];
int main()
{
std::freopen("../game_tests/game.20.in", "r", stdin);
std::freopen("game.out", "w", stdout);
-- idx;
int t = 1;
for (int j = p; j <= n; ++ j)
{
if (pos[idx] > j || a[j] >= a[pos[idx]])
ans += t * a[j];
else
{
ans += t * a[pos[idx]];
-- idx;
t = -t;
}
-- idx;
}
printf("%lld\n", ans);
}
return 0;
}
// https://csacademy.com/contest/ejoi-2017-day-2/task/
#include<cstdio>
int main()
{
std::freopen("../game_tests/game.20.in", "r", stdin);
std::freopen("game.out", "w", stdout);
int n, k, p;
scanf("%d%d", &n, &k);
for(int i = 0; i < n; ++i)
scanf("%d", &v[i]);
while(fr[up] == 0)
--up;
--fr[up];
s = s + player * up;
}
player = -player;
}
printf("%lld\n", s);
}
return 0;
}
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<utility>
int n;
pair<int,int> a[111111];
bool f[111111];
int main()
CAPITOLUL 11. EJOI 2017 11.6. GAME 458
{
std::freopen("../game_tests/game.20.in", "r", stdin);
std::freopen("game.out", "w", stdout);
int q;
scanf("%d%d",&n,&q);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i].first);
a[i].second = i;
}
sort(a+1,a+n+1);
reverse(a+1,a+n+1);
while(q--)
{
int x;
scanf("%d",&x);
int pnt = x;
long long int res = 0;
memset(f,0,sizeof(f));
if(pnt > n)
{
upd(res, i, val);
}
else
if(pos > pnt)
{
upd(res, pos - x + 1, val);
f[pos] = true;
}
else
{
upd(res, pnt - x + 1, val);
f[pnt] = true;
}
}
return 0;
}
#include <bits/stdc++.h>
int cnt[NMAX];
main()
{
std::freopen("../game_tests/game.20.in", "r", stdin);
std::freopen("game.out", "w", stdout);
int n, K;
scanf("%d%d", &n, &K);
int arr[n];
for (int i = 0; i < n; ++i)
CAPITOLUL 11. EJOI 2017 11.6. GAME 459
{
scanf("%d", &arr[i]);
}
ind = !ind;
}
ind = !ind;
}
#include <stdio.h>
#include <queue>
#include <algorithm>
#include<iostream>
int k,n,t[100001],nxt[100001],iz[100010];
struct pa
{
int ind,val;
};
{
return a.val>b.val;
}
pa a[100010];
int main()
{
std::freopen("../game_tests/game.20.in", "r", stdin);
std::freopen("game.out", "w", stdout);
scanf("%d %d",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i].val);
a[i].ind=i;
}
sort(a,a+n,cmp);
for(int i=0;i<k;i++)
scanf("%d",&t[i]);
for(int i=0;i<k;i++)
printf("%lld\n",simulate(t[i]));
}
#include <bits/stdc++.h>
#define X first
#define Y second
#define vi vector<int>
#define vvi vector< vi >
#define vii vector< ii >
#define mp make_pair
#define pb push_back
int a[100005];
int b[100005];
vii foo;
int use[100005];
CAPITOLUL 11. EJOI 2017 11.6. GAME 461
int main()
{
std::freopen("../game_tests/game.20.in", "r", stdin);
std::freopen("game.out", "w", stdout);
int n, k;
scanf("%d %d", &n, &k);
for(int i = 0; i< n; i++)
{
scanf("%d", a+i);
foo.pb(ii(a[i], i));
}
sort(a, a+n);
reverse(a, a+n);
sort(foo.begin(), foo.end()); reverse(foo.begin(), foo.end());
while(k--)
{
int x; scanf("%d", &x);
for(int i = 0; i< x-1; i++)
{
int k = b[i];
use[k] = 1;
//printf("use %d\n", k);
}
int ptr = 0;
ll res = 0;
int cnt = 1;
while(cnt<= n)
{
if(x+cnt-2< n)
{
int nxt = b[x+cnt-2];
use[nxt] = 1;
//printf("turn on %d\n", nxt);
if(nxt< ptr)
{
update(res, cnt++, a[nxt]);
use[nxt] = 0;
continue;
}
}
use[ptr] = 0;
update(res, cnt++, a[ptr]);
}
printf("%lld\n", res);
}
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../game_tests/game.20.in",
(char*)"game.out",
(char*)"../game_tests/game.20.sol",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
A.5 Observaţie
Pentru clasele a VI-a - a VIII-a, programa de concurs corespunzătoare clasei se completează cu
programele claselor anterioare.
464
Appendix B
”Instalare” C++
Instalarea este foarte uşoară (este de tipul ”next -> next -> ... -> next”) iar pe in-
ternet sunt multe site-uri de ajutor. De exemplu:
https://www.pbinfo.ro/?pagina=intrebari-afisare&id=26
https://www.youtube.com/watch?v=CLkWRvAwLO8
https://infoas.ro/lectie/112/tutorial-instalare-codeblocks-usor-introducere-in-in
https://www.competentedigitale.ro/c/oji2019/Kit_OJI_2017.rar
465
APPENDIX B. ”INSTALARE” C++ B.1. KIT OJI 2017 466
B.1.1 Code::Blocks
Pentru versiuni mai noi, de Code::Blocks şi compilatoare, se poate accesa site-ul
http://www.codeblocks.org/downloads/binaries
de unde se poate descărca, de exemplu, codeblocks-20.03mingw-setup.exe.
Versiuni mai vechi, dar foarte bune, se pot descărca de la adresa
135
Code::Blocks este un IDE (integrated development environment) pentru C/C++, un fel de Notepad ... mai
sofisticat, cu multe butoane care lansează ı̂n execuţie diverse programe, de exeplu g++.exe
136
g++.exe este compilatorul de C++, programul care va verifica dacă instrucţiunile noastre sunt ok sau nu ...
şi care ne va supăra mereu cu erorile pe care ni le arată ... ... Este “o mică artă” să ı̂nţelegem mesajele de
eroare pe care le vedem pe ecran şi să fim ı̂n stare să “depanăm” programele noastre!
APPENDIX B. ”INSTALARE” C++ B.1. KIT OJI 2017 467
http://www.codeblocks.org/downloads/source/5
Mai precis:
https://sourceforge.net/projects/codeblocks/files/Binaries/20.03/
http://sourceforge.net/projects/codeblocks/files/Binaries/17.12
http://sourceforge.net/projects/codeblocks/files/Binaries/16.01
De preferat este să avem cel puţin două partiţii: C:¯, D:¯, ... şi să “lăsăm ı̂n pace” partiţia C:¯
pentru sistemul de operare şi programele instalate!
În figura de mai sus se poate observa că pe D:¯ există un folder de lucru pentru programele ı̂n
C++, folder care se numeşte Programe C++. Aici vom salva toate programele C++ pe care
le vom scrie, eventual organizate pe mai multe subfoldere.
Click-dreapta cu mouse-ul şi selectăm “New -¿ Text document” ca ı̂n figura următoare.
APPENDIX B. ”INSTALARE” C++ B.1. KIT OJI 2017 468
Dacă vom executa două click-uri pe numele fşierului p01.cpp sau un click pentru a marca
fişierul şi apoi un ¡Enter¿, se va declanşa Code::Blocks cu p01.cpp ı̂n fereastra de editare şi, ce
este şi mai important, cu Programe C++ ca folder curent de lucru pentru Code::Blocks.
Adică, aici vor apărea toate fişiere generate de Code::Blocks pentru p01.cpp.
Figura B.9: Pregătit pentru a scrie cod de program C++ ı̂n Code::Blocks
APPENDIX B. ”INSTALARE” C++ B.1. KIT OJI 2017 470
Dacă avem fişierele p01.cpp, ..., p05.cpp, ı̂n folderul nostru de lucru, şi facem dublu-click pe
fiecare ... vor apărea toate ...
B.2 winlibs
B.2.1 GCC şi MinGW-w64 pentru Windows
Se descarcă de la
http://winlibs.com/#download-release
unul dintre fişierele:
winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r
3.7z dimensiune fişier = 148 MB
winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r
3.zip dimensiune fişier = 324 MB
winlibs-x86_64-posix-seh-gcc-10.2.0-mingw-w64-8.0.0-r3.7z dimensiune
fişier = 52.1 MB
winlibs-x86_64-posix-seh-gcc-10.2.0-mingw-w64-8.0.0-r3.zip dimensi-
une fişier = 141 MB
B.2.2 PATH
Trebuie pusă ı̂n PATH calea pentru D:\mingw64\bin\. În “Type here to search” scrieţi: path
şi apoi click pe “Edit the system environment variables”, ca ı̂n figura următoare:
APPENDIX B. ”INSTALARE” C++ B.2. WINLIBS 476
Se selecteaza “Path” şi click pe “Edit”. Apare fereastra “Edit Environment Variables”
C:¯path
C:¯gcc –version (Atentie! sunt 2 caractere - consecutive)
APPENDIX B. ”INSTALARE” C++ B.2. WINLIBS 478
Dacă totul este OK atunci se trece la instalarea IDE-ului preferat (Integrated Development
137
Environment ), de exemplu Code::Blocks 20.03 (sau Eclipse, Visual Studio Code, Dev C++,
NetBeans, şi altele).
B.2.3 CodeBlocks
CodeBlocks se poate descărca de la http://www.codeblocks.org/downloads/26. Sunt
mai multe variante dar eu am descărcat numai codeblocks-20.03-setup.exe care are 35.7 MB.
La instalare am lăsat totul implicit, deci ... Next, Next, ..., Next până la sfârşit!
La prima lansare ı̂n execuţie este necesară setarea locaţiei compilatorului de C++ (gcc-ul pe
care tocmai l-am instalat!).
137
https://en.wikipedia.org/wiki/Integrated_development_environment
https://ro.wikipedia.org/wiki/Mediu_de_dezvoltare
APPENDIX B. ”INSTALARE” C++ B.2. WINLIBS 479
Exponenţiere rapidă
În figura C.1 este considerat numărul nr 234 care ı̂n baza 2 se scrie sub forma 11101010 (celula
C10).
Pe R3 (rândul 3) este arătat ce se ı̂ntâmplă cu nr atunci când se fac ı̂mpărţiri succesive prin
baza 10: se ”şterge” ulima cifră (care este egală cu nr%10 adică ultima cifră este de fapt restul
ı̂mpărţirii lui nr la baza 10).
Pe R10 (rândul 10) este arătat ce se ı̂ntâmplă cu nr atunci când se fac ı̂mpărţiri succesive prin
baza 2: se ”şterge” ulima cifră (care este egală cu nr%2 adică ultima cifră este de fapt restul
ı̂mpărţirii lui nr la baza 2, la fel cum se ı̂ntâmplă ı̂n baza 10).
Observaţia 6. Cifrele se obţin ı̂n ordine inversă. Prima cifră obţinută ca rest este de fapt ultima
cifră din număr (vezi R4 şi R11).
Pe R6 şi R16 sunt precizate puterile bazei.
Valoarea numărului nr este suma produselor dintre cifre şi puterile corespunzătoare:
ı̂n baza 10: 4*1 + 3*10 + 2*100 = 234 (R3 şi R6)
ı̂n baza 2: 0*1 + 1*2 + 0*4 + 1*8 + 0*16 + 1*32 + 1*64 + 1*128 = 234 (R13 şi R16)
488
APPENDIX C. EXPONENŢIERE RAPIDĂ C.2. NOTAŢII, RELAŢII ŞI FORMULE 489
2 2 2 4 2 8 2 16
a0 a a1 a0 a a2 a1 a a3 a2 a a4 a3 a
2 32 2 64 2 128
a5 a4 a a6 a5 a a7 a6 a
Dacă notăm ek ”exponentul (puterea)” la care apare ak ı̂n produs, atunci putem observa
uşor că şirul e0 , e1 , e2 , e3 , ... se obţine prin ı̂mpărţiri succesive ale lui n prin 2 şi preluı̂nd restul
rezultatului. Pentru a folmaliza acest lucru vom considera şirul n0 , n1 , n2 , n3 , ... definit astfel:
n0 n,
w
nk nk1 ©2 (câtul ı̂mpărţirii!) k '1
Folosind aceste notaţii, putem scrie:
~
n0 n;
a0 a;
e n0 %2 " r0, 1x;
0
1 a0 , dacă e0 1;
p0
e
a00 sau, altfel scris: p0 w
1, dacă e0 0;
(C.2.1)
nk nk1 ©2 k ' 1; nk1 j 0 desigur ! ... dar şi nk1 j 1
ak1 , k ' 1;
2
a k
ek nk %2 " r0, 1x, k ' 0;
pk1 ak , k ' 0, dacă ek 1; ak ak modifică produsul pk1
1
p w
k k ' 0, dacă ek 0; ak 1 nu modifică produsul pk1
0
pk1 ,
C.4 Codul
Codul pentru relaţiile (C.2.1) devine:
Observaţia 7. În acest cod actualizarea lui p se face după actualizările pentru a şi n.
Observaţia 8. În codul următor actualizarea lui p se face ı̂naintea actualizărilor pentru a şi n,
corespunzător relaţiilor (C.4.2).
APPENDIX C. EXPONENŢIERE RAPIDĂ C.4. CODUL 491
~
iniţializări:
p1 1;
n1 n;
a1 a;
calcul pentru k ' 0:
e
k nk1 %2 " r0, 1x; k ' 0 (C.4.2)
pk1 ak1 , k ' 0, dacă ek 1; ak1
1
ak1 modifică produsul pk1
k w
p
k ' 0, dacă ek 0; ak1
0
pk1 , 1 nu modifică produsul pk1
actualizări k ' 0:
a ak1 , k ' 0;
2
k
nk nk1 ©2 k ' 0; şi nk1 j 0 desigur !
APPENDIX C. EXPONENŢIERE RAPIDĂ C.4. CODUL 492
Observaţia 9. Instrucţiunile care sunt ”ı̂n plus” se pot elimina. Codul următor arată acest lucru:
Observaţia 10. Produsul poate deveni foarte mare şi din cauza asta se cere rezultatul modulo un
număr prim. Codul următor arată acest lucru:
14 a = (a * a)%MOD;
15 n = n / 2;
16 nropr=nropr+6; // n%2, p*a, a*a, (a * a)%MOD si n/2
17 }
18 return p;
19 }
20
21 int main()
22 {
23 int a=1234;
24 int n=1e+9; // 10ˆ9
25 int rezn; // rezultat exponentiere naiva
26
27 rezn=exponentiere_rapida(a,n);
28
29 cout<<"rezr = "<<rezn<<" nropr = "<<nropr<<"\n";
30
31 return 0;
32 }
33 /*
34 rezr = 376 nropr = 180
35
36 Process returned 0 (0x0) execution time : 0.021 s
37 Press any key to continue.
38 */
Numărul de operaţii:
cu metoda naivă acest număr este 2 000 000 000
cu metoda rapidă este 180.
Iar ca număr de operaţii ... una este să faci 2 miliarde de operaţii şi alta este să faci
numai 180 de operaţii de acelaşi tip (de fapt sunt numai 30 de paşi dar la fiecare pas se fac 5
sau 6 operaţii aritmetice)!
138
şi nu mai trebuie ”atâtea formule matematice”!
138
Este o glumă!
Appendix D
Căutare binară
D.1 Mijlocul = ?
Care este poziţia (indicele) ”mijlocului” unei zone dintr-un vector?
În figura D.1 sunt trei formule pentru determinarea mijlocului unei zone [i1, i2] din vector:
mij1 = (i1+i2)/2
mij2 = i1+(i2-i1)/2
mijdr = (i1+i2+1)/2
Toate trei dau rezultat corect dacă secvenţa [i1, ..., i2] are un număr impar de elemente.
Când secvenţa [i1, ..., i2] are un număr par de elemente apar două elemente la mijloc ... şi ...
primele două formule dau ”mijlocul din stânga” iar a treia formulă dă ”mijlocul din dreapta”.
Atunci când căutăm o valoare ı̂ntr-un vector avem la dispoziţie căutarea secvenţială. Dacă
ştim că vectorul este sortat (şir crescător de numere) atunci este bine să folosim căutarea binară
pentru că aceasta ”găseste” numărul căutat (sau ”spune” că acel număr nu este ı̂n şir)
ı̂n 10 paşi dacă şirul are 1000 de elemnte (de fapt 1024 dar ... aproximăm!),
ı̂n 20 de paşi dacă şirul are 1,000,000 de elemente,
ı̂n 30 de paşi dacă şirul are 1,000,000,000 de elemente,
...
Explicaţia simplă este că noi tot ı̂njumătăţim intervalul de căutare până când acest interval
rămâne cu un singur element ... şi vedem dacă acel element este cel căutat (dacă elementul rămas
nu este cel căutat ... ı̂nseamnă că acel element ”căutat” nu există ı̂n şir).
Putem să ne gândim la drumul invers: plecăm de la o secvenţă cu un singur element şi dublăm
secvenţa (invers faţă de cum am făcut ı̂njumătăţind secvenţa) până ajungem la o secvenţă care
are atâtea elemente câte a avut şirul iniţial (ne oprim imediat dacă am depăşit acel număr!).
Lungimile secvenţelor sunt: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, ...
Observăm că ı̂n 10 paşi, plecând din 1, ajungem să depăşim 1000.
496
APPENDIX D. CĂUTARE BINARĂ D.2. POZIŢIE OARECARE 497
70
71 int a[]={1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 7, 7, 8, 8, 9, 9, 9, 9};
72
73 int n=sizeof(a)/sizeof(int);
74
75 cout<<"prima pozitie in vector = 0\n";
76 cout<<"ultima pozitie in vector = "<<n-1<<endl<<endl;
77
78 cautareBinaraIter1(x,a,0,n-1); // caut x in vectorul a[] de dimensiune=n
79
80 cout<<endl;
81 cout<<"nr cautari = "<<nrc<<"\n";
82
83 return 0;
84 }
55 int main()
56 {
57 int x; // caut x in vectorul a[]
58
59 //x=1; // secventa pe primele pozitii
60 x=2; // nu exista 2 ... ultima cautare in (dr,st) dr=st-1
61 //x=3; // exista numai un 3
62 //x=4; // exista secventa de 4
63 //x=9; // secventa pe ultimele pozitii
64
65 int a[]={1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 7, 7, 8, 8, 9, 9, 9, 9};
66
67 int n=sizeof(a)/sizeof(int);
68
69 cout<<"prima pozitie in vector = 0\n";
70 cout<<"ultima pozitie in vector = "<<n-1<<endl<<endl;
71
72 cautareBinaraRec1(x,a,0,n-1); // caut x in vectorul a[] de dimensiune=n
73
74 cout<<endl;
75 cout<<"nr cautari = "<<nrc<<"\n";
76
77 return 0;
78 }
43 if(st==dr) // am terminat (gasit cel mai din stanga sau nu exista deloc)
44 {
45 if(v[st]==x)
46 {
47 cout<<"am gasit "<<x<<" pe pozitia "<<st<<"\n";
48
49 return true;
50 }
51
52 else
53 {
54 cout<<x<<" nu exista in vector ...!"<<" st="<<st<<" dr="<<dr
55 <<" v[st]="<<v[st]<<" v[dr]="<<v[dr]<<"\n";
56
57 return false;
58 }
59 }
60
61 return true; // sau return false; ... oricum nu ajunge aici ... !!!
62 }
63
64 // ------------------------------------------------------------------
65
66 int main()
67 {
68 int x; // caut x in vectorul a[]
69
70 //x=1; // secventa pe primele pozitii
71 x=2; // nu exista 2 ... ultima cautare in (dr,st) dr=st-1
72 //x=3; // exista numai un 3
73 //x=4; // exista secventa de 4
74 //x=9; // secventa pe ultimele pozitii
75
76 int a[]={1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 7, 7, 8, 8, 9, 9, 9, 9};
77
78 int n=sizeof(a)/sizeof(int);
79
80 cout<<"prima pozitie in vector = 0\n";
81 cout<<"ultima pozitie in vector = "<<n-1<<endl<<endl;
82
83 cautareBinaraIter1(x,a,0,n-1); // caut x in vectorul a[] de dimensiune=n
84
85 cout<<endl;
86 cout<<"nr cautari = "<<nrc<<"\n";
87
88 return 0;
89 }
11 void afisv(int v[], int st, int dr) // afisez v[] intre st si dr
12 {
13 int i;
14 for(i=st; i<=dr; i++)
15 {
16 cout<<v[i]<<" ";
17 }
18 }
19
20 // ------------------------------------------------------------------
21
22 bool cautareBinaraIter1(int x, int v[], int st, int dr)
23 {
24 int mij;
25
26 while(st != dr)
27 {
28 nrc++;
29 mij=(st+dr+1)/2; // actualizez zona de cautare
30
31 cout<<"caut "<<x<<" in ";
32 afisv(v,st,dr);
33 cout<<"\n\n";
34
35 if(x >= v[mij])
36 st=mij; // caut in dreapta
37 else
38 dr=mij-1; // caut in stanga
39
40 cout<<"v["<<st<<"] = "<<v[st]<<" v["<<dr<<"] = "<<v[dr]<<endl;
41 //getchar();
42 }
43
44 if(st==dr) // am terminat (gasit cel mai din stanga sau nu exista deloc)
45 {
46 if(v[st]==x)
47 {
48 cout<<"am gasit "<<x<<" pe pozitia "<<st<<"\n";
49 return true;
50 }
51 else
52 {
53 cout<<x<<" nu exista in vector ...!"<<" st="<<st<<" dr="<<dr
54 <<" v[st]="<<v[st]<<" v[dr]="<<v[dr]<<"\n";
55 return false;
56 }
57 }
58
59 return true; // sau return false; ... oricum nu ajunge aici ... !!!
60 }
61 // ------------------------------------------------------------------
62
63 int main()
64 {
65 int x; // caut x in vectorul a[]
66
67 //x=1; // secventa pe primele pozitii
68 x=2; // nu exista 2 ... ultima cautare in (dr,st) dr=st-1
69 //x=3; // exista numai un 3
70 //x=4; // exista secventa de 4
71 //x=9; // secventa pe ultimele pozitii
72
73 int a[]={1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 7, 7, 8, 8, 9, 9, 9, 9};
74 int n=sizeof(a)/sizeof(int);
75
76 cout<<"prima pozitie in vector = 0\n";
77 cout<<"ultima pozitie in vector = "<<n-1<<endl<<endl;
78
79 cautareBinaraIter1(x,a,0,n-1); // caut x in vectorul a[] de dimensiune=n
80
81 cout<<endl;
82 cout<<"nr cautari = "<<nrc<<"\n";
83
84 return 0;
85 }
APPENDIX D. CĂUTARE BINARĂ D.4. POZIŢIA DIN DREAPTA 503
”Vecini” ...
E.1 Direcţiile N, E, S, V
În figura E.1 sunt două modele (notaţii) utile ı̂n probleme ı̂n care se folosesc directiile N, E, S şi
V (NE, NV, SE şi SV se deduc uşor!).
504
APPENDIX E. ”VECINI” ... E.1. DIRECŢIILE N, E, S, V 505
În figura F.1 sunt prezentate diagonale principală şi secundară ı̂mpreună cu zonele din matrice pe
care acestea le separă (indici plecând de la 0).
În figura F.2 sunt prezentate diagonale principală şi secundară ı̂mpreună cu zonele din matrice
pe care acestea le separă (indici plecând de la 1).
506
APPENDIX F. DIAGONALE ÎN MATRICE F.2. SIMETRIC FAŢĂ DE DIAGONALE 507
Parcurgere matrice
În figura H.1 este prezentată parcurgerea ı̂n matrice din NE spre SV.
508
Appendix H
Interclasare
În figura H.1 este prezentată interclasarea a doi vectori a1[ ] şi a2[ ] ı̂n vectorul a12[ ].
Vom folosi doi indici i1 (care se ”plimbă” prin vectorul a1[ ]) şi i2 (care se ”plimbă” prin vectorul
a2[ ]). La ”momentul 0” cei doi indici sunt plasaţi pe poziţia 0 (fiecare ı̂n vectorul lui!). Aceşti
doi indici pot fi priviţi ca două persoane (i1 şi i2) care parcurg fiecare câte un şir de cutii (a1[ ] şi
a2[ ]) numerotate cu 0, 1, 2, ... ı̂n care sunt obiecte care au scris preţul lor pe ele. Ambele şiruri de
cutii conţin obiecte cu valori ı̂n ordine crescătoare. Aceste obiecte trebuie mutate ı̂n şirul cutiilor
goale a12[ ] dar trebuie să rămână tot ı̂n ordine crescătoare acolo!
Cele două persoane (i1 şi i2) cunosc ı̂n orice moment care este valoarea din cutia ı̂n faţa
căreia ”aşteaptă” celălalt indice (persoană!). La momentrul 0 ı̂ncepe să ”care obiectele”, pentru
depozitare ı̂n şirul a12[ ], cel care are ı̂n cutia din faţa lui valoarea cea mai mică ... iar dacă au
509
Index
15
10 , 392 auto &, 261
18
10 , 230
bit inversion, 185 backtracking, 394, 416
((1 ¡¡ n)-1)ˆmask, 261 Be careful
(c ˆ 48), 162 Array bounds, 254
(void)0;, 265 Integer overflows, 254
(x ¡¡ 3) + (x ¡¡ 1), 162 Special cases, 254
(x & (-x)), 162 begin(), 88
(x¡¡1LL)+(x¡¡3LL)+ch-’0’, 265 begin()), 100
*–, 154 best practice, 31
*max element, 74 biţi, 165
*set.lower bound(...), 154 Big Endian, 56
? :, 57 binary indexed tree, 109
[&], 74 binary lifting, 84, 127
#define, 35, 74, 100 binary representation, 166
#define GNU SOURCE, 372 binary search, 78, 116, 117, 381
asprintf, 372, 379 bipartite graph
#include, 35 matching, 83
#include ”testlib.h”, 206 bit, 41, 121, 165
#pragma GCC, 100 BIT - binary indexed trees, 109
&, 194, 261 bit mask, 121
&..., 376 bitmask, 394
&&, 261 bits, 190
&&..., 376 bitset, 371
ˆ, 200 bitwise and—hyperpage, 121
ˆ=, 194, 200 bool, 80, 88
builtin ctzll, 414 cmp, 154
gcd, 313 bool cmp(int x, int y), 164
şablonul final, 36 boolean
0x, 51 variable, 83
0x3f3f3f3f, 162, 265, 376 bottom-up, 4
0x3f3f3f3f3f3f3f3fll, 376 breadth first search, 121
0x7fffffff, 376 breath-first search, 215
2D dynamic programming, 153 brute force, 95
32 million operations, 393 brute-force, 123, 242, 394
32-bit integer, 190 bubble sort, 165
byte, 41
a¡¡1 ¶ 1, 200
AC - Accepted Code, 103 C++, 7
accumulate(a.begin(), a.end(), 0LL);, 92 C++ Operator Precedence, 154
alfabet, 44 căutare binară, 496
analogie cu baza 10, 3, 10 căutare secvenţială, 496
ancestor, 127, 402 caracter, 44
arbore, 81 cerr, 213, 223
de acoperire, 81 chain, 435
array, 74 char*, 372, 379
ascending order, 126 cicle, 175
ASCII, 37 CINOR, vi
auto, 74, 80, 87, 156, 224, 246 class, 343
510
INDEX INDEX 511
[1] Aho, A., Hopcroft, J., Ullman, J.D.; Data strutures and algorithms, Addison Wesley, 1983
[2] Andreica M.I.; Elemente de algoritmică - probleme şi soluţii, Cibernetica MC, 2011
[3] Andonie R., Gârbacea I.; Algoritmi fundamentali, o perspectivă C++, Ed. Libris, 1995
[4] Atanasiu, A.; Concursuri de informatică. Editura Petrion, 1995
[5] Bell D., Perr M.; Java for Students, Second Edition, Prentice Hall, 1999
[21] Knuth, D.E.; The art of computer programming, vol. 4A: Combinatorial algorithms, Part 1,
Addison Wesley, 2011.
[22] Lambert,K. A., Osborne,M.; Java. A Framework for Programming and Problem Solving,
PWS Publishing, 1999
[23] Laaksonen A.; Guide to competitive programming, Springer, 2017
[24] Livovschi, L.; Georgescu H.; Analiza şi sinteza algoritmilor. Ed. Enciclopedică, Bucureşti,
1986.
[25] Niemeyer, P., Peck J.; Exploring Java, O’Reilly, 1997.
514
BIBLIOGRAFIE BIBLIOGRAFIE 515
[26] Odăgescu, I., Smeureanu, I., Ştefănescu, I.; Programarea avansată a calculatoarelor personale,
Ed. Militară, Bucureşti 1993
[27] Odăgescu, I.; Metode şi tehnici de programare, Ed. Computer Lobris Agora, Cluj, 1998
[28] Popescu Anastasiu, D.; Puncte de articulaţie şi punţi ı̂n grafuri, Gazeta de Informatică nr.
5/1993
[29] Răbâea, A.; https://math.univ-ovidius.ro/Doc/Admitere/CentruPregatire
/2007/Info/Lista_probleme_2000-2007.pdf
[30] Răbâea, A.; https://math.univ-ovidius.ro/Doc/Admitere/CentruPregatire
/2007/Info/Rezolvari_C09.pdf
517
What’s the next?
ORNL’s Frontier First to Break the Exaflop Ceiling
Over time
the following steps
will lead you to the value
you seek for yourself
now!