Documente Academic
Documente Profesional
Documente Cultură
Olimpiada - I.O.I.
2023-4
PROBLEME DE INFORMATICĂ
date la olimpiade
I.O.I.
ı̂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!
Volumul 1
... draft (ciornă) ...
*** Nobody is perfect ***
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
1 IOI 2019 1
1.1 Arranging Shoes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.2 Coduri sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.2 Split the Attractions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.2.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.2.2 Coduri sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.2.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.3 Rectangles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.3.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.3.2 Coduri sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.3.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
1.4 Broken Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
1.4.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
1.4.2 Coduri sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
1.4.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
1.5 Vision Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
1.5.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
1.5.2 Coduri sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
1.5.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
1.6 Sky Walking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
1.6.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
1.6.2 Coduri sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
1.6.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
viii
2.4.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
2.4.2 Coduri sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
2.4.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
2.5 Highway Tolls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
2.5.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
2.5.2 Coduri sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
2.5.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
2.6 Meetings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
2.6.1 Indicaţii de rezolvare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
2.6.2 Coduri sursă . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
2.6.3 *Rezolvare detaliată . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Index 1071
Bibliografie 1074
1.1 Shoes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Split1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.3 split2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4 rectangular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
1.5 Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
1.6 vision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
1.7 walk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
xiv
A.30 Schimbare nume şi extensie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1055
A.31 Moore apps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1056
A.32 Look for another app . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1056
A.33 Cale pentru codeblocks.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1057
A.34 Selectare codeblocks.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1057
A.35 Editare test01.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1058
A.36 Compilare test01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1058
A.37 Mesaje după compilare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1059
A.38 Execuţie test01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1059
A.39 Rezultat execuţie test01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1060
A.40 Fişiere apărute după compilare! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1060
A.41 Creare test02.cpp gol! + ¡dublu click¿ sau ¡Enter¿ . . . . . . . . . . . . . . . . . . 1060
A.42 Lista programelor de utilizat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1061
A.43 Selectare Code::Blocks IDE pentru fişierele .cpp . . . . . . . . . . . . . . . . . . 1061
A.44 Editare+Compilare+Execuţie pentru test02 . . . . . . . . . . . . . . . . . . . . . 1061
A.45 Selectare tab ce conţine test01.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . 1062
xvi
Lista programelor
xvii
1.6.9 walk 143257 Benq+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
1.6.10 walk 147051+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
2.1.1 compile cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
2.1.2 combo.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
2.1.3 combo.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
2.1.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
2.1.5 combo-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
2.1.6 combo 75294.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
2.1.7 combo 75871.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
2.1.8 combo 76356.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
2.1.9 combo 77113.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
2.1.10 combo koosaga.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
2.2.1 compile cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
2.2.2 seat.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
2.2.3 seat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
2.2.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
2.2.5 seat-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
2.2.6 seats 75159.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
2.2.7 seats 75485.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
2.2.8 seats 76357.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
2.2.9 seats 80434.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
2.2.10 seats 81209.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
2.3.1 compile cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
2.3.2 werewolf.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
2.3.3 werewolf.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
2.3.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
2.3.5 werewolf-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
2.3.6 werewolf 75105.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
2.3.7 werewolf 75296.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
2.3.8 werewolf 75793.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
2.3.9 werewolf 81140.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
2.3.10 werewolf 85439.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
2.4.1 compile cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
2.4.2 dool.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
2.4.3 dool.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
2.4.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
2.4.5 doll 75123.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
2.4.6 dool 75619.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
2.4.7 dool 76623.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
2.4.8 dool 78782.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
2.5.1 compile cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
2.5.2 highway.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
2.5.3 highway.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
2.5.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
2.5.5 highway 74962.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
2.5.6 highway 77105.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
2.5.7 highway 78948.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
2.6.1 compile cpp.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
2.6.2 meetings.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
2.6.3 meetings.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
2.6.4 grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
2.6.5 meetings-model.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
2.6.6 meetings 76204.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
2.6.7 meetings 120908.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
2.6.8 meetings 159115.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
3.1.1 nowruz.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
3.1.2 checker.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
3.1.3 addleaves.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
3.1.4 addleaves once.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
3.1.5 addleaves rand.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
3.1.6 dfs.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
3.1.7 haircomb.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
3.1.8 nowruz1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
3.2.1 wiring.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
3.2.2 wiring+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
3.2.3 wiring-haas-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
3.2.4 wiring-haas-ac-ternary.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
3.2.5 wiring-mahdi-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
3.2.6 wiring-malek-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
3.2.7 wiring-saeed-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
3.2.8 wiring-197505.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
3.2.9 wiring-200512.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
3.2.10 wiring-206573.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
3.2.11 wiring-216947.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
3.2.12 wiring-221801.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
3.2.13 wiring-227702.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
3.2.14 wiring-227979.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
3.3.1 train.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
3.3.2 train+grader.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
3.3.3 checkerModificat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
3.3.4 train-malek-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
3.3.5 train-saeed-ac.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
3.3.6 train-134142.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
3.3.7 train-146520.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
3.3.8 train-160375.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
3.3.9 train-163181.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
3.3.10 train-201183.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
3.3.11 train-221800.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
3.3.12 train-222137.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
3.4.1 prize.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
3.4.2 prize+graderpublic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
3.4.3 prize-169927.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
3.4.4 prize-187329.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
3.4.5 prize-206577.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
3.4.6 prize-208873.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
3.4.7 prize-221802.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
3.4.8 prize-229052.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
3.4.9 prize-232826.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
3.5.1 simurgh.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
3.5.2 simurgh-33904.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
3.5.3 simurgh-70374.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
3.5.4 simurgh-70729.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
3.5.5 simurgh-136567.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
3.5.6 simurgh-137723.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
3.6.1 books+graderpublic.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
3.6.2 books-42759.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
3.6.3 books-51837.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
3.6.4 books-94567.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
3.6.5 books-122101.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
3.6.6 books-138862.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
3.6.7 books-152524.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
3.6.8 books-206638.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
4.1.1 molecules sk.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
4.1.2 molecules sk greedy 1 n.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
4.1.3 molecules sk greedy 2 n.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
4.1.4 molecules sk greedy 3 ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
4.1.5 molecules-20751.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
4.1.6 molecules-72936.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
4.1.7 molecules-93472.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
4.1.8 molecules-114550.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
4.1.9 molecules-159299.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
4.2.1 railroad mp nlogn.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
4.2.2 railroad-103076.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
4.2.3 railroad-117891.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
4.2.4 railroad-135900.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
4.2.5 railroad-223610.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
4.2.6 railroad-233098.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
4.3.1 shortcut c.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
4.3.2 sol ge nlogd.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
4.3.3 sol ge nlogd fastio.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
4.3.4 sol nk nlogd.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
4.3.5 shortcut-24626.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
4.3.6 shortcut-33932.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
4.3.7 shortcut-94572.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
4.3.8 shortcut-97033.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446
4.3.9 shortcut-99074.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
4.3.10 shortcut-99075.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
4.3.11 shortcut-113364.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
4.3.12 shortcut-114144.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
4.3.13 shortcut-142952.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
4.3.14 shortcut-162764.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
4.3.15 shortcut-207049.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
4.3.16 shortcut-225819.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464
4.4.1 paint c.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471
4.4.2 paint iz.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
4.4.3 solve-correct-lc.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
4.4.4 checkerPaintModificat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479
4.4.5 paint-65961.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480
4.4.6 paint-66328.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482
4.4.7 paint-97040.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483
4.4.8 paint-105782.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485
4.4.9 paint-107399.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487
4.4.10 paint-108251.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489
4.4.11 paint-112136.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491
4.4.12 paint-130510.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493
4.4.13 paint-180292.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
4.4.14 paint-204502.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496
4.5.1 checkerMessyModificat.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
4.5.2 messy cpp ok.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
4.5.3 messy iz.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506
4.5.4 messy tourist.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
4.5.5 messy-21910.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513
4.5.6 messy-23726.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516
4.5.7 messy-23992.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520
4.5.8 messy-59231.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523
4.5.9 messy-66964.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526
4.5.10 messy-67587.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529
4.5.11 messy-70792.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533
4.5.12 messy-71456.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536
4.5.13 messy-102062.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539
4.6.1 checkerAliens.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547
4.6.2 alien-bsearch.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548
4.6.3 aliens ma nlogm.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551
4.6.4 aliens ma nlogm double.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554
4.6.5 alien-32012.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556
4.6.6 alien-43618.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559
4.6.7 alien-45993.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
4.6.8 alien-70398.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
4.6.9 alien-94585.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565
4.6.10 alien-96357.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
4.6.11 alien-97219.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569
4.6.12 alien-121473.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
4.6.13 alien-166476.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574
4.6.14 alien-171563.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 576
4.6.15 alien-172712.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578
4.6.16 alien-173410.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581
4.6.17 alien-224940.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584
4.6.18 alien-225911.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586
4.6.19 alien-228077.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 588
5.1.1 boxes-16533.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595
5.1.2 boxes-64042.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596
5.1.3 boxes-70567.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600
5.1.4 checkerBoxes.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601
5.2.1 graderlib.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605
5.2.2 scales-45773.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607
5.2.3 scales-115418.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 609
5.2.4 scales-122639.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612
5.2.5 checkerScales.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615
5.3.1 teams-17286.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 619
5.3.2 teams-69885.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 622
5.3.3 teams-172439.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 625
5.3.4 checkerTeams.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 628
5.4.1 horses-91995.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 632
5.4.2 horses-102703.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634
5.4.3 horses-202434.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 637
5.4.4 checkerHorses.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640
5.5.1 sorting-70140.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
5.5.2 sorting-114135.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
5.5.3 sorting-129522.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 650
5.5.4 sorting-155927.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 652
5.5.5 sorting-225877.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654
5.5.6 sorting-233228.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656
5.6.1 graderlib.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663
5.6.2 towns-127541.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663
5.6.3 towns-134867.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666
5.6.4 towns-151462.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 668
5.6.5 checkerTowns.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 670
6.1.1 game-92195.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675
6.1.2 game-117330.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
6.1.3 game-231330.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678
6.1.4 game nˆ2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679
6.1.5 checkerGame.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680
6.2.1 rail-117000.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 683
6.2.2 rail-121219.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 687
6.2.3 rail-125767.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
6.2.4 rail-139096.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694
6.2.5 rail-173712.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698
6.3.1 wall-39307.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705
6.3.2 wall-93939.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706
6.3.3 wall-173006.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708
6.3.4 wall-232336.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 710
6.3.5 checkerWall.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712
6.4.1 friend-16524.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 717
6.4.2 friend-115760.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 719
6.4.3 friend-119597.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720
6.4.4 checkerFriend.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721
6.5.1 gondola-7306.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726
6.5.2 gondola-93790map.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 728
6.5.3 gondola-102776.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 730
6.5.4 gondola-153281.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733
6.5.5 checkerGondola.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735
6.6.1 holiday-120785.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739
6.6.2 holiday-134641.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 741
6.6.3 holiday-211797.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 743
6.6.4 holiday-229391.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745
6.6.5 checkerHoliday.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 748
7.2.1 cave-1749.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 756
7.2.2 cave-16655.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758
7.2.3 cave-170339.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 760
7.2.4 cave-231414.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 763
7.2.5 checkerCave.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 766
7.3.1 dreaming-3168.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769
7.3.2 dreaming-16636.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772
7.3.3 dreaming-81476.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 774
7.3.4 dreaming-172308.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 776
7.3.5 dreaming-198762.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 778
7.3.6 checkerDreaming.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 780
7.4.1 game-220385.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 784
7.4.2 game-224978.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788
7.4.3 game-225963.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 792
7.4.4 checkerGame.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 795
7.5.1 robot-7026.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798
7.5.2 robot-7037.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801
7.5.3 robot-17227.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803
7.5.4 robot-96364.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 806
7.5.5 checkerRobot.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809
7.6.1 wombats-108194.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 816
7.6.2 wombats-108196.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 818
7.6.3 wombats-118871.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 820
7.6.4 checkerWombats.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 822
8.1.1 odometer.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 827
8.2.1 rings.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831
8.2.2 rings-13540.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835
8.2.3 rings-49004.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 838
8.2.4 rings-62499.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
8.2.5 rings-223749.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 843
8.2.6 rings-233348.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 846
8.2.7 checkerRings.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 849
8.3.1 scrivener.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 852
8.3.2 scrivener-7279.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854
8.3.3 scrivener-18725.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 856
8.3.4 scrivener-230126.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858
8.3.5 checkerScrivener.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860
8.4.1 city.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863
8.4.2 city-16324.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 867
8.4.3 city-18847.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 869
8.4.4 city-32163.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 872
8.4.5 city-197022.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874
8.4.6 checkerCity.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 877
8.5.1 supper.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 882
8.5.2 supper-231107.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 887
8.6.1 tournament.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 893
8.6.2 tournament-2193.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897
8.6.3 tournament-4657.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 899
8.6.4 tournament-14774.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 901
8.6.5 checkerTournament.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 903
9.1.1 garden-49449.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 909
9.1.2 garden-49789.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 911
9.1.3 garden-116557.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 914
9.1.4 checkerGarden.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917
9.2.1 race-28930.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921
9.2.2 race-112526.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 923
9.2.3 race-216556.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925
9.2.4 checkerRace.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 927
9.3.1 racehub-7321.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931
9.3.2 racehub-95096.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932
9.3.3 racehub-113697.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 933
9.3.4 racehub-116283.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 935
9.3.5 checkerRaceHub.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 936
9.4.1 crocodile-10431.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 940
9.4.2 crocodile-16656.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 942
9.4.3 crocodile-133704.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
9.4.4 crocodile-228833.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 946
9.4.5 checkerCrocodile.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947
9.5.1 elephants-115857.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 952
9.5.2 elephants-192442.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 954
9.5.3 elephants-207733.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 957
9.5.4 checkerElephants.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 960
9.6.1 parrot-224033.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 966
9.6.2 parrots-235627.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 971
10.1.1 cluedosol.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 978
10.1.2 cluedosol.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 979
10.1.3 cluedo-218031.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 979
10.1.4 cluedo-220599.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 980
10.1.5 cluedo-229322.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 981
10.2.1 coldersol1.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 986
10.2.2 coldersol2.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 986
10.2.3 hottercolder.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 987
10.2.4 hottercolder-173047.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 990
10.2.5 hottercolder-201977.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 992
10.3.1 rectanglesol.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 998
10.3.2 quality-208958.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 999
10.3.3 quality-234933.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1001
10.3.4 checkerQuality.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1003
10.4.1 lang-8124.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1005
10.4.2 lang-12891.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1007
10.4.3 lang-155338.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1009
10.4.4 lang-235517.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1011
10.5.1 memory.pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015
10.5.2 memory.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015
10.5.3 memory-206951.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016
10.5.4 memory-217254.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1017
10.5.5 memory-232610.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1018
10.6.1 quality-229321.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1022
10.6.2 quality-232654.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1023
10.6.3 quality-236364.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1024
10.6.4 checkerQuality.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1026
10.8.1 saveit-231998.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1032
10.8.2 saveit-224546.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1035
B.4.1exponentiere rapida1.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1065
B.4.2exponentiere rapida2.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1066
B.4.3exponentiere rapida3.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1067
B.4.4exponentiere rapida MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1067
B.5.1exponentiere naiva MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1068
B.5.2exponentiere rapida MOD.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1069
B.6.1secventa cod.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1070
Capitolul 1
27
IOI 2019
Adnan este proprietarul celui mai mare magazin de ı̂ncălţăminte din Baku. O cutie ce conţine
n perechi de pantofi tocmai a sosit ı̂n magazin. Fiecare pereche este formată din doi pantofi de
aceeaşi mărime: stânga respectiv dreapta. Adnan a pus toţi cei 2n pantofi ı̂ntr-o linie formată din
2n poziţii numerotate de la 0 la 2n 1, de la stânga la dreapta.
Adnan doreşte să rearanjeze pantofii ı̂ntr-un aranjament valid. Un aranjament este valid
dacă şi numai dacă pentru orice i (0 & i & n 1), următoarele condiţii sunt respectate:
a Pantofii de pe poziţiile 2i şi 2i 1 au aceeaşi mărime.
a Pantoful de pe poziţia 2i este cel din stânga.
a Pantoful de pe poziţia 2i 1 este cel din dreapta.
Pentru a realiza acest lucru, Adnan poate efectua un şir de interschimbări. Într-o interschim-
bare, acesta selectează doi pantofi adiacenţi ı̂n acel moment şi ı̂i interschimbă (ı̂i ridică şi pune
fiecare pantof pe locul celuilalt). Doi pantofi sunt adiacenţi dacă diferenţa absolută a poziţiilor
este 1.
Determinaţi numărul minim de interschimbări ce Adnan trebuie să facă pentru a obţine un
aranjament valid de pantofi.
Detalii de implementare
Exemple
Exemplul 1
Să considerăm următorul apel:
count_swaps([2, 1, -1, -2])
27
argint: Theodor Pierre Moroianu, ICHB (Bucureşti),
. argint: Bogdan Sitaru, Dinicu Golescu (Campulung),
. bronz: Laura Ioana Georgescu, ICHB (Bucureşti)
. bronz: Alexandru Petrescu, Tudor Vianu (Bucureşti).
1
CAPITOLUL 1. IOI 2019 1.1. ARRANGING SHOES 2
Restricţii
Subtaskuri
1. (10 puncte) n 1
2. (20 de puncte) n & 8
3. (20 de puncte) Toţi pantofii sunt de aceeaşi mărime.
4. (15 puncte) Toţi pantofii de pe poziţiile 0, ..., n 1 sunt de stânga, iar toţi pantofii de pe
poziţiile n, ..., 2n 1 sunt de dreapta. De asemenea, pentru fiecare i (0 & i & n 1), pantofii de
pe poziţiile i şi i 1 sunt de aceeaşi mărime.
5. (20 de puncte) n & 1000
6. (15 puncte) Nu există alte restricţii.
Exemplu de grader
a linia 1: n
a linia 2: S 0 S 1 S 2 ... S 2n 1
Grader-ul returnează o singură linie ce conţine valoarea returnată de funcţia count_swaps
Timp maxim de executare/test: 1.0 secunde
Memorie: total 1024 MB
problem=shoes
"grader.cpp" "${problem}.cpp"
28
Dacă cineva are nevoie de traducere, cred că a nimerit un pic aiurea pe aici!!!
CAPITOLUL 1. IOI 2019 1.1. ARRANGING SHOES 4
int main()
{
int n;
assert(1 == scanf("%d", &n));
vector<int> S(2 * n);
for (int i = 0; i < 2 * n; i++)
assert(1 == scanf("%d", &S[i]));
fclose(stdin);
printf("%lld\n", result);
fclose(stdout);
return 0;
}
class Fenwick
{
vector<int> a;
public:
explicit Fenwick(int n)
{
a.assign(n, 0);
}
{
vector<int> index = create_index(n, S);
Fenwick f = Fenwick(2 * n);
long long ans = 0;
for (int i = 0; i < 2 * n; i++)
{
if (S[i] != 0)
{
int pos = index[-S[i] + n];
ans += pos - i - f.count(i, pos) - (S[i] < 0 ? 1 : 0);
S[pos] = 0;
f.put(pos);
}
}
return ans;
}
vector<int> change(vector<int> v)
{
int n = (int)v.size() / 2;
vector<int> cnt(n, 0);
for(int i = 0; i < 2*n; i++)
if(v[i] > 0)
cnt[v[i] - 1]++;
#include <cstdio>
#include <cassert>
class Fenwick
{
vector<int> a;
public:
explicit Fenwick(int n)
{
a.assign(n, 0);
CAPITOLUL 1. IOI 2019 1.1. ARRANGING SHOES 6
vector<int> change(vector<int> v)
{
int n = (int)v.size() / 2;
vector<int> cnt(n, 0);
for(int i = 0; i < 2*n; i++)
if(v[i] > 0)
cnt[v[i] - 1]++;
int read_int()
{
int x;
CAPITOLUL 1. IOI 2019 1.1. ARRANGING SHOES 7
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
int main()
{
auto t1 = clock();
int n;
//assert(1 == scanf("%d", &n));
n = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
std::cout <<result<<’\n’<<’\n’;
std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
return 0;
}
#include <bits/stdc++.h>
#include "shoes.h"
using std::vector;
using std::pair;
vector<int> change(vector<int> v)
{
int n = (int)v.size() / 2;
vector<int> cnt(n, 0);
for(int i = 0; i < 2*n; i++)
if(v[i] > 0)
cnt[v[i] - 1]++;
if(v[i] > 0)
v[i] = (--cntr[v[i] - 1]) + 1;
else
v[i] = -((--cntl[-v[i] - 1]) + 1);
return v;
}
if (where[in[i].first] == -1)
where[in[i].first] = i;
}
vector<int> fenw(SZ(in));
for (int i = 0; i != SZ(in); ++i)
fenw[i] = 1 + i - (i & (i+1));
int i = where[in[pos].first];
dead[i] = 1;
int dist = 0;
for (int p = pos; p >= 0; p = (p & (p + 1)) - 1)
dist += fenw[p];
if (in[pos].second == 1)
--dist;
ans += dist;
for (int p = i; p < SZ(fenw); p = p | (p + 1))
fenw[p] -= 1;
}
return ans;
}
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
int main()
{
auto t1 = clock();
int n;
CAPITOLUL 1. IOI 2019 1.1. ARRANGING SHOES 9
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
std::cout <<result<<’\n’<<’\n’;
std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
return 0;
}
#include <bits/stdc++.h>
#include "shoes.h"
class Fenwick
{
vector<int> a;
public:
explicit Fenwick(int n)
{
a.assign(n, 0);
}
vector<int> change(vector<int> v)
{
int n = (int)v.size() / 2;
vector<int> cnt(n, 0);
for(int i = 0; i < 2*n; i++)
if(v[i] > 0)
cnt[v[i] - 1]++;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
int main()
{
auto t1 = clock();
int n;
CAPITOLUL 1. IOI 2019 1.1. ARRANGING SHOES 11
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
std::cout <<result<<’\n’<<’\n’;
std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
return 0;
}
#include <bits/stdc++.h>
#include "shoes.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::tuple;
using std::make_tuple;
using std::get;
using std::min;
using std::abs;
using std::max;
using std::swap;
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
CAPITOLUL 1. IOI 2019 1.1. ARRANGING SHOES 12
vector<int> change(vector<int> v)
{
int n = (int)v.size() / 2;
vector<int> cnt(n, 0);
for(int i = 0; i < 2*n; i++)
if(v[i] > 0)
cnt[v[i] - 1]++;
if (where[in[i].first] == -1)
where[in[i].first] = i;
}
vector<int> fenw(SZ(in));
for (int i = 0; i != SZ(in); ++i)
fenw[i] = 1 + i - (i & (i+1));
int i = where[in[pos].first];
dead[i] = 1;
int dist = 0;
for (int p = pos; p >= 0; p = (p & (p + 1)) - 1)
dist += fenw[p];
if (in[pos].second == 1)
--dist;
ans += dist;
for (int p = i; p < SZ(fenw); p = p | (p + 1))
fenw[p] -= 1;
}
return ans;
CAPITOLUL 1. IOI 2019 1.1. ARRANGING SHOES 13
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
int main()
{
auto t1 = clock();
int n;
//assert(1 == scanf("%d", &n));
n = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
std::cout <<result<<’\n’<<’\n’;
std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
return 0;
}
#include <bits/stdc++.h>
namespace testcaseCheck
{
sort(S.begin(), S.end());
sort(V.begin(), V.end());
for (int i = 0; i < 2 * N; ++i)
{
if (S[i] != V[i])
{
return false;
}
}
return true;
}
void run(std::vector<int> S)
{
assert(1 <= SUBTASK && SUBTASK <= 6);
assert(S.size() % 2 == 0);
int N = S.size() / 2;
assert(1 <= N && N <= 100000);
if (SUBTASK == 1)
{
assert(N == 1);
}
if (SUBTASK == 2)
{
assert(N <= 8);
}
if (SUBTASK == 3)
{
for (int s : S)
{
assert(abs(s) == abs(S[0]));
}
}
if (SUBTASK == 4)
{
for (int i = 0; i < N; ++i)
{
assert(abs(S[i]) == S[i + N]);
}
}
if (SUBTASK == 5)
{
assert(N <= 1000);
}
}
} // namespace testcaseCheck
struct FenwickTree
{
vector<int> arr;
FenwickTree(int n)
{
arr.resize(n + 1, 0);
}
int query(int x)
{
int ret = 0;
for (int i = x + 1; i > 0; i -= (i & -i))
{
ret += arr[i];
}
return ret;
}
};
positions[S[i]].pop_back();
positions[-S[i]].pop_back();
}
return answer;
}
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
int main()
{
auto t1 = clock();
int n;
//assert(1 == scanf("%d", &n));
n = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
std::cout <<result<<’\n’<<’\n’;
std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
return 0;
}
#include <bits/stdc++.h>
#include "shoes.h"
int fen[maxn];
int _pos[maxn];
int *pos = _pos + maxn / 2;
void add(int x)
{
for (x ++; x < maxn; x += x & -x)
fen[x] ++;
}
int get(int x)
{
int r = 0;
for (x ++; x; x -= x & -x)
r += fen[x];
return r;
}
vector<int> change(vector<int> v)
{
int n = (int)v.size() / 2;
vector<int> cnt(n, 0);
for(int i = 0; i < 2*n; i++)
if(v[i] > 0)
cnt[v[i] - 1]++;
lng count_swaps(vector<int> S)
{
S = change(S);
memset(fen, 0, sizeof fen);
memset(_pos, 0, sizeof _pos);
lng r = 0;
for (int i = 0; i < S.size(); i ++)
pos[S[i]] = i;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
int main()
{
auto t1 = clock();
int n;
//assert(1 == scanf("%d", &n));
n = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
std::cout <<result<<’\n’<<’\n’;
std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
return 0;
}
Detalii de implementare
Exemple
Exemplul 1
Se consideră următorul apel:
find_split(9, 4, 2, 3, [0, 0, 0, 0, 0, 0, 1, 2, 4, 5],
[1, 3, 4, 6, 7, 8, 2, 3, 5, 6])
CAPITOLUL 1. IOI 2019 1.2. SPLIT THE ATTRACTIONS 19
O posibilă soluţie corectă este 1, 1, 1, 1, 2, 2, 3, 3, 3. Această soluţie descrie următoarea
ı̂mpărţire: A r0, 1, 2, 3x, B r4, 5x, şi C r6, 7, 8x. Mulţimile A şi B sunt conectate.
Exemplul 2
Se consideră următorul apel:
find_split(6, 2, 2, 2, [0, 0, 0, 0, 0],
[1, 2, 3, 4, 5])
Nu există ı̂mpărţiri valide. Prin urmare, răspunsul corect este 0, 0, 0, 0, 0, 0.
Restricţii
Subtaskuri
Exemplu de grader
Subtask 1
In this subtask, the given graph is a path or a cycle. Therefore, the answer is always YES
and a solution can be easily found by partitioning a path: v1 , v2 , ..., vn into A v1 , v2 , ..., va ,
B va1 , va2 , ..., vab , and C vab1 , vab2 , ..., vn . In case of a cycle, we can cut the cycle
in any place and apply the similar solution as we had in path.
Subtask 2
In this subtask, the answer is always YES as follows. Let us assume that a & b & c. Find
a connected subgraph of size b (like using DFS or any graph traversing algorithm) as subset B,
construct subset A consisting of an arbitrary vertex outside of B, and other vertices are set C.
Subtask 3
In this subtask, the given graph is a tree. The solution is similar to that of the the last subtask
but the cases to be considered are easier. Without loss of generality suppose a & b & c. One
solution is to run a DFS on an arbitrary vertex to find some arbitrary spanning tree and find a
vertex v such that the size of the subtree of v [including v] denoted by size v is at least a, but
the sizes of the subtrees of all children of v are less than a. Remove the edge between v and the
parent of v which partition the tree into two connected components.
If both of the components have a size more than a, then the answer is YES.
Otherwise, the answer is no since removing v from the original graph only produces components
of size less than a.
If the answer is YES, then a connected subgraph of size a (namely A) from the smallest
component, and a connected subgraph of size b (namely B) from the smallest component can be
extracted (since b & c, the size of the larger component is at least b).
Finally, C consists of all of the remaining vertices.
Subtask 4
The input of this subtask is similar to that of the final subtask. However, since the limits for
n and m are more restricted, one can use n instances of DFS instead of only one.
Subtast 5
Similar to the solution of Subtask 3, assume we run a DFS on an arbitrary vertex and found
a vertex v such that size v ' a but the sizes of the subtrees of the children of v are all smaller
than a.
Note that other edges outside the DFS tree are backward edges. Hence, the children of v may
have backward edges to v or the ancestors of v, but no edge exists between them.
Suppose we want to partition the graph into two connected components by only considering
the edges of the DFS tree and removing the edge between v and the parent of v.
In this way the graph is partitioned into part P1 consisting of v and its subtree and P2 consisting
of all other vertices.
Before proceeding, we check every child of v (in an arbitrary order) like u and if the following
conditions hold, we remove its subtree from P1 and add it to P2 .
The subtree of u has a backward edge to the ancestors of v. The size of P1 after removing the
subtree of u is still at least a. By doing so, one by one, we may encounter a child of v, namely u,
such that
¶P1 ¶ ' a and ¶P1 ¶ size u $ a
Hence,
¶P2 ¶ % n 2a a b c 2a b c a ' b
In the other case, either ¶P2 ¶ % a, which is also good since ¶P1 ¶ % n b a b c b a c % b,
or ¶P2 ¶ $ a and the answer is NO, since v is a cut vertex such that removing it from the original
graph produces several components where all of them are of size less than a.
problem=split
"grader.cpp" "${problem}.cpp"
int main()
{
int n, m, a, b, c;
return 0;
}
sort(sizes.begin(), sizes.end());
a = sizes[0].first; b = sizes[1].first; c = sizes[2].first;
dfs1(0);
dfs2(0);
ret[pa] = sizes[0].second;
ret[pb] = sizes[a].second;
counter = a;
dfs3(pa, sizes[0].second);
vis[pb] = sizes[1].second;
counter = b;
dfs3(pb, sizes[1].second);
vis[pa] = false;
for(int i=0; i<n; i++) if(ret[i] == -1) ret[i] = sizes[2].second;
for(int i=0; i<n; i++) ret[i]++;
return ret;
};
if(both_dir.first != -1)
{
return find_solution(both_dir.first, both_dir.second);
}
else
{
vector <int> in_deg(n);
for(auto edge : dir) in_deg[edge.second]++;
vector <int> CH;
for(int i=0; i<n; i++) if(in_deg[i] == 0) CH.push_back(i);
assert((int)CH.size() == 1);
vis = vector<bool>(n, false);
subtree = vector<int>(n, 0);
int root = CH.back();
for(auto edge : non_tree)
{
G[edge.first].push_back(edge.second);
G[edge.second].push_back(edge.first);
}
dfs1(root);
for(auto son : G[root])
{
if(subtree[son] >= a) return find_solution(son, root);
}
return vector<int>(n, 0);
}
}
#include "bits/stdc++.h"
#include "split.h"
sort(sizes.begin(), sizes.end());
a = sizes[0].first;
b = sizes[1].first;
c = sizes[2].first;
};
dfs1(0);
dfs2(0);
ret[pa] = sizes[0].second;
ret[pb] = sizes[a].second;
counter = a;
dfs3(pa, sizes[0].second);
vis[pb] = sizes[1].second;
counter = b;
dfs3(pb, sizes[1].second);
vis[pa] = false;
return ret;
};
if(both_dir.first != -1)
{
return find_solution(both_dir.first, both_dir.second);
}
else
{
vector <int> in_deg(n);
for(auto edge : dir) in_deg[edge.second]++;
vector <int> CH;
for(int i=0; i<n; i++) if(in_deg[i] == 0) CH.push_back(i);
assert((int)CH.size() == 1);
vis = vector<bool>(n, false);
subtree = vector<int>(n, 0);
CAPITOLUL 1. IOI 2019 1.2. SPLIT THE ATTRACTIONS 26
dfs1(root);
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int n, m, a, b, c;
//assert(5 == scanf("%d%d%d%d%d", &n, &m, &a, &b, &c));
n = read_int();
m = read_int();
a = read_int();
b = read_int();
c = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
#include "../split.h"
#include<bits/stdc++.h>
using namespace std;
const int mn=2e5+10;
int p[mn],si[mn];
void init()
{
iota(p,p+mn,0);
fill(si,si+mn,1);
}
bool u[mn];
vector<int>g[mn],ans;
int s[mn];
int ctr,n;
int lef,tar;
bool vis[mn];
int conv[4];
void dfs3(int x)
{
if(!lef)return;
vis[x]=1;
lef--;
ans[x]=conv[tar];
for(int y:g[x])
{
if(!vis[y])
{
dfs3(y);
if(!lef)return;
}
}
}
if(a==sm)
conv[1]=1;
else
if(a==bi)
conv[3]=1;
else
conv[2]=1;
if(b==sm&&!conv[1]) conv[1]=2;
else
if(b==bi&&!conv[3])conv[3]=2;
else conv[2]=2;
if(c==sm&&!conv[1])conv[1]=3;
else
if(c==bi&&!conv[3])conv[3]=3;
else conv[2]=3;
b=a+b+c-sm-bi;
a=sm;
c=bi;
n=N;
ans.resize(n,conv[3]);
int m=p.size(),i;
init();
for(i=0;i<m;i++)
{
if(f(p[i])!=f(q[i]))
{
mrg(p[i],q[i]);
g[p[i]].push_back(q[i]);
g[q[i]].push_back(p[i]);
}
}
dfs(0,-1);
ctr=fc(0,-1);
init();
for(int y:g[ctr])
{
dfs2(y,ctr);
if(siz(y)>=a)
{
vis[ctr]=1;
lef=a;
tar=1;
dfs3(y);
CAPITOLUL 1. IOI 2019 1.2. SPLIT THE ATTRACTIONS 29
lef=b;
tar=2;
vis[ctr]=0;
dfs3(ctr);
return ans;
}
}
for(i=0;i<m;i++)
{
if(p[i]==ctr||q[i]==ctr)continue;
if(f(p[i])==f(q[i]))continue;
mrg(p[i],q[i]);
g[p[i]].push_back(q[i]);
g[q[i]].push_back(p[i]);
if(siz(p[i])>=a)
{
vis[ctr]=1;
lef=a;
tar=1;
dfs3(p[i]);
lef=b;
tar=2;
vis[ctr]=0;
dfs3(ctr);
return ans;
}
}
fill(ans.begin(),ans.end(),0);
return ans;
}
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
int main()
{
auto t1 = clock();
int n, m, a, b, c;
//assert(5 == scanf("%d%d%d%d%d", &n, &m, &a, &b, &c));
n = read_int();
m = read_int();
a = read_int();
b = read_int();
c = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
printf("\n");
fclose(stdout);
auto t4 = clock();
return 0;
}
int n;
vector<int> gph[MAXN];
vector<int> tr[MAXN];
namespace report
{
vector<int> gph[MAXN];
int mark[MAXN], vis[MAXN];
void dfs(int x, vector<int> &dfn)
{
dfn.push_back(x);
vis[x] = 1;
for(auto &i : gph[x])
{
if(mark[x] == mark[i] && !vis[i])
{
dfs(i, dfn);
}
}
}
vector<pi> color;
vector<int> Do(vector<int> S)
{
for(auto &i : S) mark[i] = 1;
vector<int> ans(n, color[2].second);
for(int i=0; i<n; i++)
{
vector<int> dfn;
if(mark[i] == 1 && !vis[i])
{
dfs(i, dfn);
for(int j=0; j<color[0].first; j++)
{
ans[dfn[j]] = color[0].second;
}
}
return ans;
}
}
struct disj
{
int pa[MAXN], sz[MAXN];
void init(int n)
{
iota(pa, pa + n + 1, 0);
fill(sz, sz + n + 1, 1);
}
int find(int x)
{
return pa[x] = (pa[x] == x ? x : find(pa[x]));
}
int getsz(int x)
{
return sz[find(x)];
}
int get_center()
{
dfsc(0, 0);
pi ret(1e9, 1e9);
for(int i=0; i<n; i++)
{
ret = min(ret, pi(max(msz[i], n - sz[i]), i));
}
return ret.second;
}
bool vis[MAXN];
CAPITOLUL 1. IOI 2019 1.2. SPLIT THE ATTRACTIONS 32
sort(cs.begin(), cs.end());
report::color = cs;
a = cs[0].first;
disj.init(n);
for(int i=0; i<sz(p); i++)
{
if(disj.uni(p[i], q[i]))
{
tr[p[i]].push_back(q[i]);
tr[q[i]].push_back(p[i]);
}
report::gph[p[i]].push_back(q[i]);
report::gph[q[i]].push_back(p[i]);
}
disj.init(n);
int c = get_center();
for(auto &i : tr[c])
{
vector<int> dfn;
dfs(i, c, dfn);
if(disj.getsz(i) >= a)
{
return report::Do(dfn);
}
}
if(sum >= a)
{
vector<int> ans;
for(int i=0; i<n; i++)
{
CAPITOLUL 1. IOI 2019 1.2. SPLIT THE ATTRACTIONS 33
if(pot.find(disj.find(i)) != pot.end())
{
ans.push_back(i);
}
}
return report::Do(ans);
}
}
}
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
int main()
{
auto t1 = clock();
int n, m, a, b, c;
//assert(5 == scanf("%d%d%d%d%d", &n, &m, &a, &b, &c));
n = read_int();
m = read_int();
a = read_int();
b = read_int();
c = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
#include "../split.h"
#include <vector>
#include <algorithm>
#include<iostream>
#include<ctime>
int n;
vector<int> a[maxn];
vector<int> result(maxn);
intpair b[3];
forn(i, a[v].size())
if (!mark[a[v][i]])
{
dfs(a[v][i], v);
if (finishedPhase1)
return;
sizev[v]+=sizev[a[v][i]];
mintime[v] = min(mintime[v], mintime[a[v][i]]);
if (mintime[a[v][i]] < startingtime[v])
removablesSum += sizev[a[v][i]];
}
else
if (a[v][i]!=par)
{
mintime[v] = min(mintime[v], mintime[a[v][i]]);
}
int element = 0;
if (n - sizev[v] + removablesSum < b[1].first)
element = 1;
result[v] = b[element].second;
mark[v] = 2;
int goal = b[element].first - 1;
forn(i, a[v].size())
{
if (mark[a[v][i]] < 2 &&
goal > 0 &&
mintime[a[v][i]] >= startingtime[v] &&
startingtime[a[v][i]] > startingtime[v])
goal -= dfs2(a[v][i], goal, b[element].second);
}
forn(i, a[v].size())
{
if (mark[a[v][i]] < 2 &&
goal > 0 &&
mintime[a[v][i]] < startingtime[v] &&
startingtime[a[v][i]] > startingtime[v])
goal -= dfs2(a[v][i], goal, b[element].second);
}
vector <int> find_split(int n_, int a_, int b_, int c_,
vector <int> p, vector <int> q)
{
n = n_;
b[0]=intpair(a_, 1);
b[1]=intpair(b_, 2);
b[2]=intpair(c_, 3);
sort(b, b+3);
forn(i, p.size())
{
a[p[i]].push_back(q[i]);
a[q[i]].push_back(p[i]);
}
dfs(0, -1);
result.resize(n);
return result;
}
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
int main()
{
auto t1 = clock();
int n, m, a, b, c;
//assert(5 == scanf("%d%d%d%d%d", &n, &m, &a, &b, &c));
CAPITOLUL 1. IOI 2019 1.2. SPLIT THE ATTRACTIONS 36
n = read_int();
m = read_int();
a = read_int();
b = read_int();
c = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
using pi=pair<int,int>;
using vi=vc<int>;
vc<pi> g[nmmax];
int ans[nmmax];
bool us[nmmax];
bool vis[nmmax];
//find any spanning tree
void dfs1(int v,int pe)
{
if(vis[v])return;
vis[v]=1;
if(pe!=-1)
us[pe]=1;
for(auto e:g[v])
dfs1(e.a,e.b);
}
//find a centroid
int dfs2(int v,int p,int n)
{
int s=1,mx=0;
for(auto e:g[v])if(us[e.b]&&p!=e.a)
{
int f=dfs2(e.a,v,n);
if(f<=0)return f;
chmax(mx,f);
s+=f;
}
chmax(mx,n-s);
if(mx*2<=n)return -v;
return s;
}
int m=p.size();
rep(i,m)
{
g[p[i]].eb(q[i],i);
g[q[i]].eb(p[i],i);
}
dfs1(0,-1);
int r=-dfs2(0,-1,n);
CAPITOLUL 1. IOI 2019 1.2. SPLIT THE ATTRACTIONS 38
vvc<int> cmps;
for(auto e:g[r])if(us[e.b])
{
vi w;
dfs3(e.a,r,w);
cmps.pb(w);
}
bool fd=false;
for(auto w:cmps)
{
if(int(w.size())>=si[0].a)
{
ans[r]=-1;
puti(w[0],si[0].b,si[0].a);
ans[r]=0;
puti(r,si[1].b,si[1].a);
fd=true;
break;
}
}
if(!fd)
{
vi idx(n,-1);
rep(i,cmps.size())
for(auto v:cmps[i])
idx[v]=i;
int z=idx[0];
if(z==-1) return vi(n,0);
int cur=cmps[z].size();
vi ad(cmps.size());
ad[z]=1;
rep(i,m)
{
int x=idx[p[i]],y=idx[q[i]];
if(y==z)swap(x,y);
if(x==z&&y!=-1&&!ad[y])
{
ad[y]=1;
cur+=cmps[y].size();
us[i]=1;
if(cur>=si[0].a)
{
ans[r]=-1;
puti(0,si[0].b,si[0].a);
ans[r]=0;
puti(r,si[1].b,si[1].a);
fd=true;
break;
}
}
}
}
if(!fd)return vi(n,0);
assert(si[0].a==0);
assert(si[1].a==0);
rep(i,n)
if(ans[i]==0)
ans[i]=si[2].b;
return vi(ans,ans+n);
}
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
CAPITOLUL 1. IOI 2019 1.3. RECTANGLES 39
return x;
}
int main()
{
auto t1 = clock();
int n, m, a, b, c;
//assert(5 == scanf("%d%d%d%d%d", &n, &m, &a, &b, &c));
n = read_int();
m = read_int();
a = read_int();
b = read_int();
c = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
1.3 Rectangles
Problema 3 - Rectangles 100 de puncte
La ı̂nceputul secolului al 19-lea, conducătorul Hoseyngulu Khan Sardar ordonă să se constru-
iască un palat ı̂n platoul din oraşul Zangi. Platoul oraşului este modelat sub forma unei matrice
cu n m celule pătratice. Rândurile matricei sunt numerotate de la 0 la n 1, iar coloanele
sunt numerotate de la 0 la m 1. Vom numi celula de pe linia i şi coloana j (0 & i & n 1,
0 & j & m 1), celula i, j . Fiecare celulă i, j are o anumită ı̂nălţime, notată cu aij .
Hoseyngulu Khan Sardar şi-a rugat arhitecţii să aleagă o zonă dreptunghiulară ı̂n matrice
unde să contruiască palatul. Zona respectivă nu are voie să conţină nici o celulă aflată pe marginea
matricei (linia 0, linia n 1, coloana 0 şi coloana m 1). În concluzie, arhitecţii trebuie să aleagă
patru ı̂ntregi r1 , r2 , c1 şi c2 (1 & r1 , r2 & n 2 şi 1 & c 1, c2 & m 2), care vor defini o zonă ce
va conţine toate celulele i, j cu proprietatea că r1 & i & r2 şi c1 & j & c2 .
CAPITOLUL 1. IOI 2019 1.3. RECTANGLES 40
În plus, o zonă este considerată validă dacă şi numai dacă pentru fiecare celulă i, j din zona
respectivă, următoarea condiţie va avea loc:
a Se consideră cele două celule adiacente zonei selectate de pe linia i (celulele i, c1 1 şi
i, c2 1) şi cele două celule adiacente zonei de pe coloana j (celulele r1 1, j şi r2 1, j ).
Înălţimea celulei trebuie să fie strict mai mică decât ı̂nălţimea celor patru celule menţionate mai
sus.
Misiunea voastră este să ı̂i ajutaţi pe arhitecţi să găsească numărul de zone valide ı̂n care poate
să fie stabilit palatul (numărul de moduri ı̂n care se pot alege valorile r1 , r2 , c1 şi c2 care definesc
o zonă validă).
Detalii de implementare
Exemple
Exemplul 1
Considerăm următoarea apelare.
count_rectangles([[4, 8, 7, 5, 6],
[7, 4, 10, 3, 5],
[9, 7, 20, 14, 2],
[9, 14, 7, 5, 6],
[5, 7, 5, 2, 7],
[4, 5, 13, 5, 6]])
Restricţii
Subtaskuri
1. (8 puncte) n, m & 30
2. (7 puncte) n, m & 80
3. (12 puncte) n, m & 200
4. (22 de puncte) n, m & 700
5. (10 puncte) n & 3
6. (13 puncte) 0 & aij & 1 (oricare 0 & i & n 1, 0 & j & m 1)
7. (28 de puncte) Fără restricţii suplimentare.
Exemplu de grader
Subtasks 1, 2, and 3
6 4
Subtask 1 can be solved via a trivial O n solution: considering all O n rectangles and
2
checking whether each of them is valid in O n . Moreover, if we use breaks in loops for checking
whether a rectangle is valid, then this solution is accepted in Subtask 1, 2, and 3.
5 4
Moreover, an O n solution exist which gets accepted in Subtask 1 and 2, and an O n
solution exist which gets accepted in Subtask 1, 2, and 3.
Subtask 5
In this subtask, valid rectangles are all consecutive subsets of the middle. All of these rectangles
2
can be checked in time O m .
Subtask 6
This subtask is finding a 0 rectangle with 1 on outer borders (except corners). This is a classic
2 3
dynamic programming problem which can be solved in O n . Moreover, most of the O n and
2
O n log n solutions run in O n in this subtask.
Subtasks 4 and 7
Solution 1
We denote a pair of cells in a row or a column which are on the outer border of a valid rectangle
2
as a good pair. The total number of good pairs are bounded by O n and can be found using a
stack and traversing over cells of each row and each column. Then, we can extend these good pairs
into two potential sides of a valid rectangle. Therefore, we have potential left and right sides, and
potential top and bottom sides of valid rectangles. Finally, we try all cells as the bottom-right
corner of valid rectangles and match sizes.
3
If the matching phase is done naively, we have a O n solution which get accepted in subtask
4 but not Subtask 7. However, many optimizations results in getting accepted in Subtask 7. The
2
best of which is using a Fenwick tree which decreases the total running time downto O n log n.
Moreover, in order to get accepted in Subtask 7, one might not use time-consuming data
29
structure libraries such as STL maps .
29
time-consuming
CAPITOLUL 1. IOI 2019 1.3. RECTANGLES 42
Solution 2
A very useful observation is that in a good pair, if we look at the smaller element, the pair is
unique (one for the left direction, and one for the right direction).
Using this observation, we can change the data structure needed for keeping good pairs into
two simple arrays. For a valid rectangle, let a block corner be a 2 2 square that exactly one of
its elements is inside the rectangle. Each valid rectangle have exactly four block corners. We can
connect block corners of a valid rectangle which are in a row or a column based on whether which
one captures the larger element in the outer border of the row or column.
4
These connections define a structure for a valid rectangle. At most 2 16 structures exist
and for each structure there is a block corner that uniquely define the valid rectangle.
2 2
Therefore, the number of valid rectangles is bounded by O n . After finding these O n
2
candidate rectangles, we can check each of them in O 1 after a preprocess in O n .
problem=rect
"grader.cpp" "${problem}.cpp"
class InputReader
{
private:
static const int SIZE = 4096;
int inputFileDescriptor;
char buf[SIZE];
int curChar;
int numChars;
public:
}
};
int main()
{
InputReader inputReader(STDIN_FILENO);
int n, m;
n = inputReader.readInt();
m = inputReader.readInt();
vector<vector<int>> a(n, vector<int>(m));
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
a[i][j] = inputReader.readInt();
}
}
inputReader.close();
printf("%lld\n", result);
fclose(stdout);
return 0;
}
int n, m;
vector<vector<int>> H;
vector<ll> v;
void precalc()
{
short st[maxn];
rep(i, n)
{
int t = 0;
rep(j, m)
{
while(t && H[i][j] > H[i][st[t-1]]) t--;
L[i][j] = (t ? st[t-1] : -1);
st[t++] = j;
}
}
rep(i, n)
{
int t = 0;
CAPITOLUL 1. IOI 2019 1.3. RECTANGLES 45
rof(j, m, 0)
{
while(t && H[i][j] > H[i][st[t-1]]) t--;
R[i][j] = (t ? st[t-1] : -1);
st[t++] = j;
}
}
rep(j, m)
{
int t = 0;
rep(i, n)
{
while(t && H[i][j] > H[st[t-1]][j]) t--;
U[i][j] = (t ? st[t-1] : -1);
st[t++] = i;
}
}
rep(j, m)
{
int t = 0;
rof(i, n, 0)
{
while(t && H[i][j] > H[st[t-1]][j]) t--;
D[i][j] = (t ? st[t-1] : -1);
st[t++] = i;
}
}
rep(j, m) rep(i, n)
{
if(U[i][j] != -1)
{
if(j > 0 && U[i][j] == U[i][j-1]) UL[i][j] = UL[i][j-1];
else if(j > 0 && i == D[U[i][j]][j-1]) UL[i][j] = DL[U[i][j]][j-1];
else UL[i][j] = j;
}
if(D[i][j] != -1)
{
if(j > 0 && D[i][j] == D[i][j-1]) DL[i][j] = DL[i][j-1];
else if(j > 0 && i == U[D[i][j]][j-1]) DL[i][j] = UL[D[i][j]][j-1];
else DL[i][j] = j;
}
}
rep(i, n) rep(j, m)
{
if(L[i][j] != -1)
{
if(i > 0 && L[i][j] == L[i-1][j]) LU[i][j] = LU[i-1][j];
else if(i > 0 && j == R[i-1][L[i][j]]) LU[i][j] = RU[i-1][L[i][j]];
else LU[i][j] = i;
}
if(R[i][j] != -1)
{
if(i > 0 && R[i][j] == R[i-1][j]) RU[i][j] = RU[i-1][j];
else if(i > 0 && j == L[i-1][R[i][j]]) RU[i][j] = LU[i-1][R[i][j]];
else RU[i][j] = i;
}
}
}
precalc();
sort(all(v));
v.resize(unique(all(v)) - v.begin());
return sz(v);
}
#include<unistd.h> // close
#include<stdio.h> // STDOUT_FILENO,STDERR_FILENO
int n, m;
vector<vector<int>> H;
vector<ll> v;
void precalc()
{
short st[maxn];
rep(i, n)
{
int t = 0;
rep(j, m)
{
while(t && H[i][j] > H[i][st[t-1]]) t--;
L[i][j] = (t ? st[t-1] : -1);
st[t++] = j;
}
}
CAPITOLUL 1. IOI 2019 1.3. RECTANGLES 47
rep(i, n)
{
int t = 0;
rof(j, m, 0)
{
while(t && H[i][j] > H[i][st[t-1]]) t--;
R[i][j] = (t ? st[t-1] : -1);
st[t++] = j;
}
}
rep(j, m)
{
int t = 0;
rep(i, n)
{
while(t && H[i][j] > H[st[t-1]][j]) t--;
U[i][j] = (t ? st[t-1] : -1);
st[t++] = i;
}
}
rep(j, m)
{
int t = 0;
rof(i, n, 0)
{
while(t && H[i][j] > H[st[t-1]][j]) t--;
D[i][j] = (t ? st[t-1] : -1);
st[t++] = i;
}
}
rep(j, m) rep(i, n)
{
if(U[i][j] != -1)
{
if(j > 0 && U[i][j] == U[i][j-1])
UL[i][j] = UL[i][j-1];
else
if(j > 0 && i == D[U[i][j]][j-1])
UL[i][j] = DL[U[i][j]][j-1];
else
UL[i][j] = j;
}
if(D[i][j] != -1)
{
if(j > 0 && D[i][j] == D[i][j-1])
DL[i][j] = DL[i][j-1];
else
if(j > 0 && i == U[D[i][j]][j-1])
DL[i][j] = UL[D[i][j]][j-1];
else
DL[i][j] = j;
}
}
rep(i, n) rep(j, m)
{
if(L[i][j] != -1)
{
if(i > 0 && L[i][j] == L[i-1][j])
LU[i][j] = LU[i-1][j];
else
if(i > 0 && j == R[i-1][L[i][j]])
LU[i][j] = RU[i-1][L[i][j]];
else
LU[i][j] = i;
}
if(R[i][j] != -1)
{
if(i > 0 && R[i][j] == R[i-1][j])
RU[i][j] = RU[i-1][j];
else
CAPITOLUL 1. IOI 2019 1.3. RECTANGLES 48
precalc();
sort(all(v));
v.resize(unique(all(v)) - v.begin());
return sz(v);
}
class InputReader
{
private:
static const int SIZE = 4096;
int inputFileDescriptor;
char buf[SIZE];
int curChar;
int numChars;
public:
if (numChars == -1)
return -1;
}
return buf[curChar++];
}
int res = 0;
do
{
assert(c >= ’0’ && c <= ’9’);
res *= 10;
res += c - ’0’;
c = read();
} while (!isSpaceChar(c));
return res;
}
return res;
}
int main()
{
auto t1 = clock();
InputReader inputReader(STDIN_FILENO);
int n, m;
n = inputReader.readInt();
m = inputReader.readInt();
cerr<<"cerr : "<<n<<" "<<m<<"\n";
inputReader.close();
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
return 0;
}
// --------------- end grader ---------------------
#include <bits/stdc++.h>
#include "../rect.h"
#include<unistd.h> // close
#include<stdio.h> // STDOUT_FILENO,STDERR_FILENO
#define fi first
#define se second
CAPITOLUL 1. IOI 2019 1.3. RECTANGLES 51
int query(int u)
{
int ret = 0;
for (; u > 0; u -= u & -u)
ret += bit[u];
return ret;
}
int pt = 0;
for (pair<int, int> &v : row)
{
for (; pt < col.size() && v.fi <= col[pt].fi; pt++)
update(col[pt].se, 1);
ans += query(v.se);
}
return ans;
}
row[i].push_back(j + 1);
eq = false; pair_col.clear();
while (!col[j].empty())
{
int u = col[j].back();
if (u < i && !eq)
pair_col.push_back(process(u, i + 1, j,
lst_col, cnt_col));
eq = (a[u][j] == a[i + 1][j]);
if (a[u][j] <= a[i + 1][j])
col[j].pop_back();
else
break;
}
col[j].push_back(i + 1);
ans += find_ans(pair_row, pair_col);
}
return ans;
}
int inputFileDescriptor;
char buf[SIZE];
int curChar;
int numChars;
public:
if (numChars == -1)
return -1;
}
return buf[curChar++];
}
c = read();
}
int res = 0;
do
{
assert(c >= ’0’ && c <= ’9’);
res *= 10;
res += c - ’0’;
c = read();
} while (!isSpaceChar(c));
return res;
}
return res;
}
int main()
{
auto t1 = clock();
InputReader inputReader(STDIN_FILENO);
int n, m;
n = inputReader.readInt();
m = inputReader.readInt();
cerr<<"cerr : "<<n<<" "<<m<<"\n";
inputReader.close();
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
return 0;
}
// --------------- end grader ---------------------
#include "../rect.h"
#include<bits/stdc++.h>
#include<unistd.h> // close
#include<stdio.h> // STDOUT_FILENO,STDERR_FILENO
ll count_rectangles(vector<vector<int>> G)
{
int N = int(G.size()) - 1;
int M = int(G[0].size()) - 1;
vector<stack<int>> stacks(M);
for (int j = 1; j < M; j++)
{
if (G[0][j] > G[1][j])
{
stacks[j].push(0);
}
stacks[j].push(1);
}
vector<vector<pair<int, int>>>
history(M,
vector<pair<int, int>>(M, pair<int, int>(-1, -1)));
ll ans = 0;
s.emplace(0, vector<int>());
for (int j = 1; j <= M; j++)
{
vector<int> curSet;
bool initialized = false;
vector<int> nCurSet;
set_intersection(curSet.begin(), curSet.end(),
v.begin(), v.end(), back_inserter(nCurSet));
curSet = std::move(nCurSet);
};
assert(initialized);
int numGood = int(curSet.end() -
lower_bound(curSet.begin(),
curSet.end(),
history[l][r].first));
//cerr << numGood << ’\n’;
ans += numGood;
}
}
else
{
s.pop();
}
}
if (j == M) break;
vector<int> heights;
{ // build heights
while (!stacks[j].empty() &&
G[i+1][j] >= G[stacks[j].top()][j])
{
if (G[i+1][j] > G[stacks[j].top()][j])
{
stacks[j].pop();
if (!stacks[j].empty())
{
heights.push_back(stacks[j].top()+1);
}
}
else
{
stacks[j].pop();
}
}
stacks[j].push(i+1);
}
CAPITOLUL 1. IOI 2019 1.3. RECTANGLES 56
reverse(heights.begin(), heights.end());
merge(heights);
s.emplace(j, std::move(curSet));
}
}
return ans;
}
int inputFileDescriptor;
char buf[SIZE];
int curChar;
int numChars;
public:
if (numChars == -1)
return -1;
}
return buf[curChar++];
}
char c = read();
if (c == ’\n’ || c == ’\r’ || c == -1)
break;
res += c;
}
return res;
}
int main()
{
auto t1 = clock();
InputReader inputReader(STDIN_FILENO);
int n, m;
n = inputReader.readInt();
m = inputReader.readInt();
cerr<<"cerr : "<<n<<" "<<m<<"\n";
inputReader.close();
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
return 0;
}
// --------------- end grader ---------------------
#include<unistd.h> // close
#include<stdio.h> // STDOUT_FILENO,STDERR_FILENO
#define X first
#define Y second
int fen_f(int x)
{
x++;
int ret = 0;
while(x<maxx)
{
ret += fen_t[x];
x += x&(-x);
}
return ret;
}
if(type == 0)
{
if(r-l-1>0)
sp[type][lvl+1][r].push_back(pii(r-l-1, tmp));
}
else
{
if(r-l-1>0)
sp[type][r][lvl+1].push_back(pii(tmp, r-l-1));
}
fp[lvl+1][l][r] = tmp;
}
nozoli.pop_back();
}
if(nozoli.size())
add_pair(type, lvl, nozoli.back(), i);
nozoli.push_back(i);
}
}
for(int i=0;i<n;i++)
{
vec.clear();
for(int j=0;j<m;j++)
vec.push_back(a[i][j]);
extract_pairs(0,i);
}
for(int i=0;i<=max(n,m);i++)
for(int j=0;j<=max(n,m);j++)
fp[i][j].clear();
for(int j=0;j<m;j++)
{
vec.clear();
for(int i=0;i<n;i++)
vec.push_back(a[i][j]);
extract_pairs(1,j);
}
for(int i=0;i<=max(n,m);i++)
for(int j=0;j<=max(n,m);j++)
if(sp[0][i][j].size() && sp[1][i][j].size())
{
sort(sp[0][i][j].begin(), sp[0][i][j].end());
sort(sp[1][i][j].begin(), sp[1][i][j].end());
// sp[0].X fix sp[1].X moteghaier
int p = 0;
will_remove.clear();
for(int k=0;k<sp[1][i][j].size();k++)
{
while(p<sp[0][i][j].size() &&
sp[0][i][j][p].X <= sp[1][i][j][k].X)
{
fen_add(sp[0][i][j][p].Y, 1);
will_remove.push_back(sp[0][i][j][p].Y);
p++;
}
ans += fen_f(sp[1][i][j][k].Y);
}
for(int k=0;k<will_remove.size();k++)
fen_add(will_remove[k], -1);
}
return ans;
}
int inputFileDescriptor;
char buf[SIZE];
int curChar;
int numChars;
public:
CAPITOLUL 1. IOI 2019 1.3. RECTANGLES 60
if (numChars == -1)
return -1;
}
return buf[curChar++];
}
int res = 0;
do
{
assert(c >= ’0’ && c <= ’9’);
res *= 10;
res += c - ’0’;
c = read();
} while (!isSpaceChar(c));
return res;
}
return res;
}
CAPITOLUL 1. IOI 2019 1.3. RECTANGLES 61
int main()
{
auto t1 = clock();
InputReader inputReader(STDIN_FILENO);
int n, m;
n = inputReader.readInt();
m = inputReader.readInt();
cerr<<"cerr : "<<n<<" "<<m<<"\n";
inputReader.close();
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
return 0;
}
// --------------- end grader ---------------------
CAPITOLUL 1. IOI 2019 1.4. BROKEN LINE 62
Azerbaidjan este faimos pentru covoarele sale. Ca un maestru ı̂n designer de covoare, doriţi
să elaboraţi un nou design prin desenarea unei linii frânte. O linie frântă este o secvenţă de t
segmente intr-un plan bidimensional, definite printr-o secvenţă de t 1 puncte p0 , ..., pt după cum
urmează:
Pentru fiecare 0 & j & t 1 există un segment ce conectează punctele pj şi pj 1 .
Pentru a elabora noul design, aţi marcat deja n puncte intr-un plan bidimensional. Coordo-
natele punctului i (1 & i & n) sunt xi, y i. Nu există două puncte care să aibă aceeaşi
coordonată x sau y.
Doriţi să găsiţi o secvenţă de puncte sx0, sy 0, sx1, sy 1, ..., sxk , sy k , ce de-
fineşte o linie frântă care:
a ı̂ncepe la 0, 0 (adică sx0 0 şi sy 0 0),
a conţine toate punctele marcate (nu neapărat ca extremităţi ale segmentelor)
a constă exclusiv din segmente orizontale şi verticale (două puncte consecutive care definesc
linia frântă au aceeaşi coordonată x sau y)
Se permite ca linia frântă să se intersecteze sau să se suprapună ı̂n orice fel. Formal, fiecare
punct din plan poate aparţine oricărui număr de segmente din linia frântă.
Această problemă este de tip output-only, cu scor parţial. Veţi avea 10 fişiere de intrare ı̂n care
vor fi specificate locaţiile punctelor marcate. Pentru fiecare fişier de intrare, trebuie să ı̂ncărcaţi
un fişier de ieşire care descrie o linie frântă cu proprietăţile cerute.
Pentru fiecare fişier de ieşire care descrie o linie frântă validă, scorul vostru va depinde de
numărul de segmente din linia frântă (a se vedea Punctarea de mai jos).
Nu veţi ı̂ncărca vreun cod sursă pentru această problemă.
Format de intrare
Format de ieşire
Exemple
Pentru intrarea:
4
2 1
3 3
4 4
5 2
CAPITOLUL 1. IOI 2019 1.4. BROKEN LINE 63
6
2 0
2 3
5 3
5 2
4 2
4 4
Restricţii
a Mărimea fiecărui fişier de ieşire (fişier de intrare sau arhivă zip) nu trebuie să depăşească
15M B.
Punctare
Pentru fiecare test, puteţi obţine maxim 10 puncte. Output-ul unui test va fi punctat cu 0
puncte dacă nu conţine o linie frântă cu proprietăţile cerute. Altfel, punctajul va fi determinat
utilizând o secvenţă descrescătoare c1 , ..., c10 care diferă de la test la test.
...
Timp maxim de executare/test: output-only
Memorie: output-only
In this problem, we are given n dots in a 2D-plane with distinct x coordinates and y coordinates.
Our task is to construct a broken line starting from the origin that will cover all dots.
2n solution
An easy solution is to use 2 segments to cover each dot (for example: first set the x coordinate,
then y coordinate). This solution uses 2n segments and receives 12 points.
Spiral
Let us consider the left-most, top-most, right-most and bottom-most dot. They create a
bounding box which we can cover with 4 segments. We can remove these points and continue
with a smaller problem. To connect the bounding boxes, we can just continue the line from the
CAPITOLUL 1. IOI 2019 1.4. BROKEN LINE 64
inner bounding box and go toward the proper direction in the outer box. This solution receives
about 50 points, depending on the implementation.
Chain
Let us notice that we can cover a chain of points (for example with increasing x and y values)
without wasting any segment. From the Dilworth’s theorem, we know thatÓ in the sequence of
length k, there exists an increasing sequence or decreasing sequence of length k. Ó We can find this
sequence in O k log k . Moreover, we can decompose the whole sequence Ó
into k log k increasing
and decreasing
Ó sequences. Therefore in our problem, we can create n log n chains and connect
them with k log k additional segments. This solution uses n 2 log n segments and receives about
60 points.
n 6 solution
Let us reconsider the spiral. We waste additional segments only if the bounding box contains
less than 4 points (for example there’s a point that is both the left-most and the top-most one).
We can remove these points and put them in one of two chains (one going from the top-left
corner to the bottom-right corner) and one going from the top-right corner to the bottom-left
one).
The algorithm is as follows:
if a bounding box has 4 points in it, add them to the spiral, and remove these points,
otherwise, find a point that lies on two sides of the bounding box, add it to the proper chain
and remove it.
Then we have three objects (spiral and two chains) and we can use up to 2 segments to connect
them to themselves and the origin. This solution gets about 95 points.
n 3 solution
To come up with an even better solution, we need to add some small tricks, including considering
all possible orders in which we can connect these objects and directions in which we can traverse
them. These optimizations lead a solution with n 3 segments, which gets 100 points.
problem=line
"grader.cpp" "${problem}.cpp"
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <cassert>
#include <ctime>
#include <vector>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#define pb push_back
#define mp make_pair
#define fs first
#define sc second
int n;
vector <pair <int, int> > input;
vector <pair <int, int> > answer;
bool last_volatile = false;
return;
}
answer[last].fs = point.fs;
}
}
}
}
if (point.fs != answer.back().fs)
{
answer.pb(mp(point.fs, answer.back().sc));
}
if (point.sc != answer.back().sc)
{
answer.pb(point);
}
}
void add_spiral(vector <pair <pair <int, int>, pair <int, int> > > spiral)
{
for (int i = 0; i < (int) spiral.size(); i++)
{
int lft = spiral[i].fs.fs;
int up = spiral[i].fs.sc;
int rgt = spiral[i].sc.fs;
int down = spiral[i].sc.sc;
if (i == 0)
{
continue_answer(ldc);
continue_answer(luc);
continue_answer(ruc);
continue_answer(rdc);
continue_answer(ldc);
}
else
{
answer.back().fs = input[lft].fs;
if (input[lft].sc >= answer.back().sc)
{
continue_answer(luc);
continue_answer(ruc);
continue_answer(rdc);
continue_answer(ldc);
}
else
{
continue_answer(ldc);
continue_answer(rdc);
continue_answer(ruc);
continue_answer(luc);
}
}
}
}
{
for (int i = 0; i < len; i++)
{
chain[i].sc *= -1;
}
}
sort(chain.begin(), chain.end());
if (flip)
{
for (int i = 0; i < len; i++)
{
chain[i].fs *= -1;
}
}
if (order)
{
for (int i = 0; i < len; i++)
{
chain[i].sc *= -1;
}
}
continue_answer(chain[0]);
for (int i = 1; i < len; i++)
{
if (i % 2 xor interleave)
{
continue_answer(mp(chain[i].fs, chain[i - 1].sc));
}
else
{
continue_answer(mp(chain[i - 1].fs, chain[i].sc));
}
}
if (len > 1)
{
continue_answer(chain.back());
}
}
void finalize()
{
cerr << n << ’ ’ << answer.size() - 1 << ’ ’ << answer.size() - 1 - n << ’\n’;
cout << answer.size()-1 << ’\n’;
for (int i = 1; i < (int) answer.size(); i++)
{
cout << answer[i].fs << ’ ’ << answer[i].sc << ’\n’;
}
}
int main ()
{
cin >> n;
while (true)
{
int lft = -1;
CAPITOLUL 1. IOI 2019 1.4. BROKEN LINE 68
int up = -1;
while (!ys.empty() && used[ys.rbegin()->sc])
{
ys.erase( *ys.rbegin());
}
if (!ys.empty())
{
up = ys.rbegin()->sc;
}
if (lft == down)
{
chain1.pb(input[lft]);
used[lft] = true;
continue;
}
if (lft == up)
{
chain2.pb(input[lft]);
used[lft] = true;
continue;
}
if (rgt == down)
{
chain2.pb(input[rgt]);
used[rgt] = true;
continue;
}
if (rgt == up)
{
chain1.pb(input[rgt]);
used[rgt] = true;
continue;
}
spiral.pb(mp(mp(lft, up), mp(rgt, down)));
used[lft] = true;
used[rgt] = true;
used[down] = true;
used[up] = true;
}
reverse(spiral.begin(), spiral.end());
CAPITOLUL 1. IOI 2019 1.4. BROKEN LINE 69
answer = best_answer;
finalize();
return 0;
}
#define pb push_back
#define mp make_pair
#define fs first
#define sc second
int n;
vector <pair <int, int> > input;
vector <pair <int, int> > answer;
bool last_volatile = false;
answer.pb(point);
return;
}
if (point.fs != answer.back().fs)
{
answer.pb(mp(point.fs, answer.back().sc));
}
if (point.sc != answer.back().sc)
{
answer.pb(point);
}
}
void add_spiral(vector <pair <pair <int, int>, pair <int, int> > > spiral)
{
for (int i = 0; i < (int) spiral.size(); i++)
{
int lft = spiral[i].fs.fs;
int up = spiral[i].fs.sc;
int rgt = spiral[i].sc.fs;
int down = spiral[i].sc.sc;
if (i == 0)
{
continue_answer(ldc);
continue_answer(luc);
continue_answer(ruc);
continue_answer(rdc);
continue_answer(ldc);
}
else
{
answer.back().fs = input[lft].fs;
if (input[lft].sc >= answer.back().sc)
{
continue_answer(luc);
continue_answer(ruc);
continue_answer(rdc);
continue_answer(ldc);
}
else
{
continue_answer(ldc);
continue_answer(rdc);
continue_answer(ruc);
continue_answer(luc);
}
}
}
}
continue_answer(chain[0]);
for (int i = 1; i < len; i++)
{
if (i % 2 xor interleave)
{
continue_answer(mp(chain[i].fs, chain[i - 1].sc));
}
CAPITOLUL 1. IOI 2019 1.4. BROKEN LINE 72
else
{
continue_answer(mp(chain[i - 1].fs, chain[i].sc));
}
}
if (len > 1)
{
continue_answer(chain.back());
}
}
void finalize()
{
cerr << "cerr : "<<n << ’ ’ << answer.size() - 1
<< ’ ’ << answer.size() - 1 - n << ’\n’;
cout << answer.size()-1 << ’\n’;
for (int i = 1; i < (int) answer.size(); i++)
{
cout << answer[i].fs << ’ ’ << answer[i].sc << ’\n’;
}
}
int main ()
{
auto t1 = clock();
cin >> n;
cerr<<"cerr : "<<n<<"\n";
auto t2 = clock();
while (true)
{
int lft = -1;
while (!xs.empty() && used[xs.begin()->sc])
{
xs.erase(xs.begin());
}
if (!xs.empty())
{
lft = xs.begin()->sc;
}
if (!xs.empty())
{
rgt = xs.rbegin()->sc;
}
int up = -1;
while (!ys.empty() && used[ys.rbegin()->sc])
{
ys.erase( *ys.rbegin());
}
if (!ys.empty())
{
up = ys.rbegin()->sc;
}
if (lft == down)
{
chain1.pb(input[lft]);
used[lft] = true;
continue;
}
if (lft == up)
{
chain2.pb(input[lft]);
used[lft] = true;
continue;
}
if (rgt == down)
{
chain2.pb(input[rgt]);
used[rgt] = true;
continue;
}
if (rgt == up)
{
chain1.pb(input[rgt]);
used[rgt] = true;
continue;
}
spiral.pb(mp(mp(lft, up), mp(rgt, down)));
used[lft] = true;
used[rgt] = true;
used[down] = true;
used[up] = true;
}
reverse(spiral.begin(), spiral.end());
vector <pair <int, int> > best_answer;
for (int flip1 = 0; flip1 < 8; flip1++)
{
for (int flip2 = 0; flip2 < 8; flip2++)
{
vector <int> parts = {0, 1, 2};
do
{
answer.clear();
last_volatile = false;
continue_answer(mp(0, 0));
for (int i = 0; i < (int) parts.size(); i++)
{
if (parts[i] == 0)
CAPITOLUL 1. IOI 2019 1.5. VISION PROGRAM 74
{
add_spiral(spiral);
}
else
if (parts[i] == 1)
{
add_chain(chain1, flip1 >> 2,
(flip1 >> 1) & 1, flip1 & 1);
}
else
{
add_chain(chain2, flip2 >> 2,
(flip2 >> 1) & 1, flip2 & 1);
}
}
if (best_answer.empty() ||
answer.size() < best_answer.size())
{
best_answer = answer;
}
} while (next_permutation(parts.begin(), parts.end()));
}
}
answer = best_answer;
auto t3 = clock();
finalize();
auto t4 = clock();
return 0;
}
Trebuie să implementaţi un program de interpretare pentru un robot. De fiecare dată când
robotul face o poză, aceasta este stocată ı̂n memoria robotului ca o imagine albnegru. Fiecare
imagine este o matrice cu H W pixeli, cu rândurile numerotate de la 0 la H 1 şi coloanele
numerotate de la 0 la W 1. Există exact doi pixeli negri ı̂n fiecare imagine şi toţi ceilalţi pixeli
sunt albi.
Robotul poate procesa fiecare imagine folosind un program format din instrucţiuni simple. Se
dau valorile H, W şi un ı̂ntreg pozitiv K. Scopul vostru este să scrieţi o funcţie care să producă
un program pentru robot care, pentru orice imagine primită, să determine dacă distanţa dintre
cei doi pixeli negri este exact K. Distanţa ı̂ntre un pixel de pe linia r1 şi coloana c1 , şi un pixel
de pe linia r2 şi coloana c2 este ¶r1 r2 ¶ ¶c1 c2 ¶. În această formulă, ¶x¶ reprezintă valoarea
absolută a lui x, care este x dacă x ' 0 şi x dacă x $ 0.
Acum vom descrie cum funcţionează robotul.
Memoria robotului este formată dintr-un vector suficient de mare de celule, indexat de la 0.
Fiecare celulă este sau 0, sau 1, iar această valoare odată setată, nu poate fi modificată. Imaginea
este memorată linie cu linie ı̂n celule indexate de la 0 la H W 1. Prima linie este stocată ı̂n
celulele de la 0 la W 1, iar ultima linie este stocată ı̂n celulele de la H 1 W la H W 1.
CAPITOLUL 1. IOI 2019 1.5. VISION PROGRAM 75
Mai exact, dacă pixelul de pe linia i şi coloana j este negru, valoarea celulei i W j este 1, altfel
0.
Programul robotului este format dintr-o serie de instrucţiuni, numerotate prin ı̂ntregi con-
secutivi ı̂ncepând de la 0. Când programul rulează, instrucţiunile sunt executate una câte una.
Fiecare instrucţiune citeşte valorile din una sau mai multe celule (numim aceste valori intrările
instrucţiunii) şi produc o singură valoare egală cu 0 sau 1 (numim această valoare ieşirea
instrucţiunii). Ieşirea instrucţiunii i este stocată ı̂n celula H W i. Intrările instrucţiunii ipot
fi celule care stochează fie pixeli, fie ieşirile instrucţiunilor precedente, adică celulele de la 0 la
H W i 1.
Există patru tipuri de instrucţiuni:
a NOT : are o singură intrare. Ieşirea este 1 dacă intrarea e 0, altfel ieşirea este 0.
a AND : are una sau mai multe intrări. Ieşirea este 1 dacă şi numai dacă toate intrările sunt
1.
a OR : are una sau mai multe intrări. Ieşirea este dacă şi numai dacă cel puţin una din
intrări este 1.
a XOR : are una sau mai multe intrări. Ieşirea este 1 dacă şi numai dacă un număr impar
de intrări sunt 1.
Ieşirea ultimei instrucţiuni a programului trebuie să fie 1 dacă distanţa dintre cei doi pixeli
negri este exact K, altfel ieşirea este 0.
Detalii de implementare
a Invalid index: indicele unei celule transmis ca intrare pentru una din funcţiile add_and,
add_or, add_xor sau add_not este incorect (posibil negativ).
a Too many instructions: funcţia voastră a ı̂ncercat să adauge mai mult de 10000 de
instrucţiuni.
a Too many inputs: instrucţiunile citesc mai mult de 1000000 de valori ı̂n total.
Exemple
Presupunem că H 2, W 3 şi K 3. Există doar două posibile imagini pentru care distanţa
dintre cei doi pixeli negri este 3.
Restricţii
Subtaskuri
Exemplu de grader
va afişa unul din mesajele de eroare menţionat la sfârşitul secţiunii de Implementare, iar apoi
iese.
Altfel, grader-ul produce două ieşiri.
În prima fază, grader-ul afişează rezultatul programului robotului ı̂n următorul format:
a linia 1 i (0 & i): ieşirea ultimei instrucţiuni din programul robotului pentru imaginea i (1
sau 0).
În a doua fază, grader-ul scrie ı̂n directorul curent un fişier log.txt cu următorul format:
a linia 1 i (0 & i): m0 m1 ... mc 1
Secvenţa de pe linia 1 i descrie valorile stocate ı̂n celulele din memoria robotului după ce
programul robotului a fost rulat, dându-se imaginea i ca intrare. Mai exact, mj reprezintă
valoarea celulei j. Remarcaţi că valoarea lui c (lungimea secvenţei) este egală cu H W plus
numărul de instrucţiuni din programul robotului.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 1024 MB
Let’s call a right diagonal a set of pixels that have coordinates r a, c a, where r, c is one
of the pixels on the diagonal and a is an integer assuming values in some range. The difference
between coordinates has the same value for all pixels lying on a diagonal: it’s equal to D r c.
For two right diagonals with such differences equal to D1 and D2 , we say that the diagonals are
at distance d if ¶D1 D2 ¶ d.
In a similar manner, let’s call a left diagonal a set of pixels that have coordinates r a, c a.
The sum of coordinates is equal to D r c for all pixels on a left diagonal. Just as with right
diagonals, two left diagonals are at distance d if ¶D1 D2 ¶ d.
Lemma. Distance between two pixels r1 , c1 and r2 , c2 is less than or equal to d if and
only if both the distance between the left diagonals that contain the pixels is less than or equal to
d and the distance between the right diagonals that contain the pixels is less than or equal to d.
Proof. The condition on diagonals can be written as follows:
¶ r1 c1 r2 c2 ¶ & d,
w
¶ r1 c1 r2 c2 ¶ & d.
~
d & r1 r2 c2 c1 & d,
d
& r2 r1 c1 c2 & d,
d & r1 r2 c1 c2 & d,
d
& r2 r1 c2 c1 & d.
Finally, this is equivalent to ¶r1 r2 ¶ ¶c1 c2 ¶ & d, where the LHS is the definition of distance
between pixels. The lemma has been proven.
The algorithm then is as follows:
1. Add an instruction for each diagonal (both left and right ones) indicating 1. whether there
is a black pixel within the diagonal.
2. Add an instruction for each diagonal (both left and right ones) indicating whether there are
two black pixels within the diagonal (combining OR and XOR might come in handy).
3. Using instructions from 1. and 2., for each block of K 1 consecutive left diagonals have an
instruction that reports whether there are two black pixels within the block.
4. Do the same for right diagonals.
CAPITOLUL 1. IOI 2019 1.5. VISION PROGRAM 78
5. Add a gate that returns true if and only if there is at least one gate from 3. and at least one
gate from 4. that both return true.
6. Repeat steps 3. - 5. for K instead of K 1.
7. The pixels are at distance K if and only if 5. reports true but 6. reports f alse.
problem=vision
"grader.cpp" "${problem}.cpp"
class InstructionNetwork
{
struct Instruction
{
int type;
vector<int> input_indexes;
int input_size;
int total_inputs;
vector<Instruction> instructions;
public:
instructions.emplace_back(type, input_indexes);
total_inputs += input_indexes.size();
CAPITOLUL 1. IOI 2019 1.5. VISION PROGRAM 80
return new_index;
}
int main()
{
int H, W, K;
assert(3 == scanf("%d%d%d", &H, &W, &K));
instructionNetwork.init(H * W);
construct_network(H, W, K);
while (true)
{
int rowA, colA, rowB, colB;
assert(1 == scanf("%d", &rowA));
if (rowA == -1)
break;
assert(3 == scanf("%d%d%d", &colA, &rowB, &colB));
vector<int> memory_cells;
for (int row = 0; row < H; row++)
for (int col = 0; col < W; col++)
{
bool active = (row == rowA && col == colA) ||
(row == rowB && col == colB);
memory_cells.push_back(active ? 1 : 0);
}
int computation_result = instructionNetwork.compute(memory_cells);
printf("%d\n", computation_result);
fflush(stdout);
int add_not(int N)
{
vector<int> Ns = {N};
return instructionNetwork.add_instruction(_NOT, Ns);
}
Kenan desenează un plan al clădirilor şi pasarelelor de-a lungul bulevardului principal din
Baku. Există clădiri numerotate de la 0 la n 1 şi m pasarele numerotate de la 0 la m 1.
Planul este desenat pe o suprafaţă bidimensională, unde clădirile şi pasarelele sunt segmente
verticale respectiv orizontale.
Partea de jos a clădirii i (0 & j & m 1) se află la punctul xi, 0, iar clădirea are ı̂nălţimea
hi. Prin urmare, este un segment care conectează punctele xi, 0 şi xi, hi.
Pasarela j (0 & j & m 1) are puncte terminale la clădirile numerotate cu lj şi rj , aflată
la o coordonată pozitivă y cu valoarea y j . Prin urmare, este un segment care uneşte punctele
xlj , y j şi xrj , y j .
O pasarelă şi o clădire se intersectează dacă au un punct comun. Prin urmare, o pasarelă
intersectează două clădiri ı̂n punctele ei terminale, şi deasemenea poate intersecta alte clădiri ı̂ntre
acestea.
Kenan ar dori să găsească lungimea celui mai scurt drum de la baza clădirii s la baza clădirii
g, presupunând că se poate merge doar prin clădiri şi pasarele, sau să se determine dacă o astfel
de cale nu există.
Reţineţi că nu este permis să mergeţi pe jos, adică de-a lungul liniei orizontale cu coordonata
y egală cu 0.
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 83
În orice intersecţie se poate merge de pe pasarelă ı̂n clădire sau invers. Dacă punctele terminale
pentru două pasarele sunt identice, atunci se poate merge de pe o pasarelă pe alta.
Sarcina voastră este să ı̂l ajutaţi pe Kenan să răspundă la ı̂ntrebarea lui.
Detalii de implementare
Trebuie să implementaţi următoarea funcţie. Aceasta va fi apelată de către grader câte o dată
pentru fiecare test.
int64 min_distance(int[] x, int[] h, int[] l, int[] r, int[] y,
int s, int g)
a x şi h: vectori cu numere ı̂ntregi de lungime n
a l, r şi y: vectori cu numere ı̂ntregi de lungime m
a s şi g: două numere ı̂ntregi
a Această funcţie trebuie să returneze lungimea celui mai scurt drum dintre baza clădirii s şi
baza clădirii g, dacă o astfel de cale există. În caz contrar, trebuie să se returneze 1.
Exemple
Exemplul 1
Consideraţi următorul apel:
min_distance([0, 3, 5, 7, 10, 12, 14],
[8, 7, 9, 7, 6, 6, 9],
[0, 0, 0, 2, 2, 3, 4],
[1, 2, 6, 3, 6, 4, 6],
[1, 6, 8, 1, 7, 2, 5],
1, 5)
Răspunsul corect este 27.
Imaginea de mai jos corespunde Exemplului 1:
Exemplul 2
min_distance([0, 4, 5, 6, 9],
[6, 6, 6, 6, 6],
[3, 1, 0],
[4, 3, 2],
[1, 3, 6],
0, 4)
Răspunsul corect este 21.
Restricţii
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 84
Subtaskuri
Exemplu de grader
Subtask 1
For each skywalk and each building, check if they intersect and if they do, add a new vertex
for the intersection point. Additionally, put a node on the bottom of each of the buildings s, and
g.
Add edges between consecutive nodes on each building and also for consecutive nodes on each
skywalk.
Use Dijkstra to find the shortest path from the node on the bottom of building s to the node
at the bottom of buildingg. Number of vertices and edges are O N M , so the total complexity is
O N M log N M .
Subtask 2
The solution for the previous subtask works here as well, however the graph must be built more
efficiently. To do that, iterate in increasing order over heights which either contain a skywalk or
the endpoint of a building. The goal is to keep a list of all buildings that are at least as tall as the
current height. Given such list, for each skywalk, start from its left endpoint and move through
the list. Each element is an intersection between that skywalk and a building. Hence you will
at most visit 10 elements before reaching the right endpoint. Add a vertex for each intersection.
The rest of the solution is the same as the last subtask. For maintaining the list of buildings, it is
enough to start from a list of all buildings. Then at each height, after processing the skywalks for
that height, remove the buildings that have an endpoint at that height. This can be done using
a linked-list or a BST.
Subtask 3
When s 0 and g n 1, it can be proven that skywalks are always traversed from left to
right. Additionally when all of the buildings have the same height, it can be shown that there
exists an optimal path where each skywalk is either not visited or is traversed completely until its
right endpoint (though the entrance point to that skywalk might not be its left endpoint).
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 85
Iterate over skywalks in increasing order of their right endpoint, breaking ties in favor of lower
skywalks. The goal is to maintain the minimum cost to reach each skywalk’s right endpoint.
During the iteration, for each skywalk, update this value for the skywalks just above, and just
below its right endpoint based on its own value. The answer is the minimum cost to reach the
right endpoint of one of skywalks ending at n 1 adding the cost of reaching to the bottom of the
building n 1.
Subtask 4
For this subtask, the solution is to use the same strategy as the first two subtasks and build
a graph. Consider the graph in those two subtasks. Let e be a vertical edge connecting points
x, y1 and x, y2 for some x, y1 , y2 (y1 $ y2 ). Edge e is called irrelevant if the point x, y2 lies
strictly inside of some skywalk. Since s 0 and g n 1, it can be proved that there exists a
shortest path that does not pass through irrelevant edges. Hence, after removing the irrelevant
edges from the graph, the length of the shortest path doesn’t change. In the new graph, for each
vertical edge, the top node is the endpoint of a skywalk. So, there are at most O M vertical
edges left in the graph. This means at most O M vertices have at least one edge connected to
them. Discarding the other vertices, the same approach as the first two subtasks can be followed
on the new graph.
Subtask 5
The solution for this subtask is almost the same as the last subtask. However, for the previous
theorem to hold, the skywalks must be adjusted. Specifically, for each skywalk between two
buildings such as l, and r where l $ s $ r, divide it into 3 parts as follows:
let a be the last building before s (including s) that is as tall as this skywalk.
let b be the first building after s (including s) that is as tall as this skywalk.
replace the skywalk with the following skywalks:
` skywalk connecting buildings l and a.
` skywalk connecting buildings a and b.
` skywalk connecting buildings b and r.
The same adjustment must be done for all skywalks that intersect or pass over building g.
Then the same solution as subtask 4 works.
problem=walk
"grader.cpp" "${problem}.cpp"
int main()
{
int n, m;
assert(2 == scanf("%d%d", &n, &m));
vector<int> x(n), h(n);
for (int i = 0; i < n; i++)
assert(2 == scanf("%d%d", &x[i], &h[i]));
vector<int> l(m), r(m), y(m);
for (int i = 0; i < m; i++)
assert(3 == scanf("%d%d%d", &l[i], &r[i], &y[i]));
int s, g;
assert(2 == scanf("%d%d", &s, &g));
fclose(stdin);
printf("%lld\n", result);
fclose(stdout);
return 0;
}
int vcnt = 0;
vector<pii> edges[MAXV];
set<pli> dij;
int last_x[MAXRM];
int last_vertex[MAXRM];
int last_height[MAXN];
int first_height[MAXN];
vector<pii> adds[MAXN];
vector<pii> removes[MAXN];
set<pii> walks;
assert(a != -1);
assert(b != (int)h.size() + 1);
if (x < a)
{
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 88
r[i] = a;
if (a < b)
{
l.push_back(a);
r.push_back(b);
y.push_back(y[i]);
}
}
else
{
assert(x == a);
r[i] = b;
}
if (q > b)
{
l.push_back(b);
r.push_back(q);
y.push_back(y[i]);
}
else
{
assert(q == b);
}
}
}
break_segments(l, r, y, s, h);
break_segments(l, r, y, g, h);
int m = l.size();
int vcnt = 0;
vector<pii> edges[MAXV];
set<pli> dij;
int last_x[MAXRM];
int last_vertex[MAXRM];
int last_height[MAXN];
int first_height[MAXN];
vector<pii> adds[MAXN];
vector<pii> removes[MAXN];
set<pii> walks;
int u = edges[v][i].first;
int w = edges[v][i].second;
if (dist[u] > dist[v] + w)
{
dij.erase(pli(dist[u], u));
dist[u] = dist[v] + w;
dij.insert(pli(dist[u], u));
}
}
}
return -1;
}
assert(a != -1);
assert(b != (int)h.size() + 1);
if (x < a)
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 91
{
r[i] = a;
if (a < b)
{
l.push_back(a);
r.push_back(b);
y.push_back(y[i]);
}
}
else
{
assert(x == a);
r[i] = b;
}
if (q > b)
{
l.push_back(b);
r.push_back(q);
y.push_back(y[i]);
}
else
{
assert(q == b);
}
}
}
break_segments(l, r, y, s, h);
break_segments(l, r, y, g, h);
int m = l.size();
if (i == s)
{
if (walks.empty() || walks.begin()->first > h[i])
return -1;
sv = make_vertex(walks.begin()->second, x[i]);
res += walks.begin()->first;
}
if (i == g)
{
if (walks.empty() || walks.begin()->first > h[i])
return -1;
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 92
gv = make_vertex(walks.begin()->second, x[i]);
res += walks.begin()->first;
}
assert(sv != -1);
assert(gv != -1);
if(dij_res == -1)
return -1;
return res + dij_res;
}
int main()
{
std::freopen("../tests/5-30.in", "r", stdin) ; // execution time : 3.199 s
std::freopen("walking.out", "w", stdout) ;
auto t1 = clock();
int n, m;
assert(2 == scanf("%d%d", &n, &m));
cerr<<"cerr : "<<n<<" "<<m<<"\n";
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
return 0;
}
//-------------- end grader ------------------
using ll = int64_t;
#ifdef LOCAL
#define cerr (cerr << "-- line " << __LINE__ << " -- ")
#else
class CerrDummy
{
} cerrDummy;
template <class T>
CerrDummy &operator<<(CerrDummy &cd, const T &)
{
return cd;
}
using charTDummy = char;
using traitsDummy = char_traits<charTDummy>;
CerrDummy &operator<<(CerrDummy &cd, basic_ostream<charTDummy,
traitsDummy> &(basic_ostream<charTDummy,
traitsDummy> &))
{
return cd;
}
#define cerr cerrDummy
#endif
ll read()
{
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 94
ll i;
scanf("%" SCNd64, &i);
return i;
}
void printSpace()
{
printf(" ");
}
void printEoln()
{
printf("\n");
}
string readString()
{
static char buf[3341000];
scanf("%s", buf);
return string(buf);
}
char *readCharArray()
{
static char buf[3341000];
static int bufUsed = 0;
char *ret = buf + bufUsed;
scanf("%s", ret);
bufUsed += strlen(ret) + 1;
return ret;
}
#ifdef int
const int inf = infLL;
#else
const int inf = INT_MAX / 2 - 100;
#endif
namespace Subtask4
{
ll Solve(vi x, vi h, vi l, vi r, vi y, int s, int g)
{
int n = x.size();
REP(k, 2)
{
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 95
int w = k == 0 ? s : g;
vector<pi> p{pi(h[w], w)}, q{pi(h[w], w)};
int m = l.size();
sort(ALL(xty));
multiset<int> ys;
for (auto q : xty)
{
int j=get<0>(q), t=get<1>(q), i = get<2>(q) * (t == 0 ? 1 : -1);
posYX.EB(i, j);
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 96
sort(ALL(posYX));
posYX.erase(unique(ALL(posYX)), posYX.end());
}
int vs = posYX.size();
vector<vector<pi>> graph(vs);
const auto AddEdge = [&](int a, int b, int c)
{
graph[a].EB(b, c);
graph[b].EB(a, c);
};
REP(i, m)
{
int k = Idx(y[i], x[l[i]]);
while (k + 1 < int(posYX.size()) && posYX[k + 1] <= pi(y[i], x[r[i]]))
{
AddEdge(k, k + 1, posYX[k + 1].second - posYX[k].second);
k++;
}
}
sort(ALL(posXY));
REP(i, vs - 1)
{
if (posXY[i].first == posXY[i + 1].first)
{
AddEdge(Idx(posXY[i].second, posXY[i].first),
Idx(posXY[i + 1].second, posXY[i + 1].first),
posXY[i + 1].second - posXY[i].second);
}
}
pq.pop();
if (dist[v] != d)
continue;
for (auto e : graph[v])
Reach(e.first, dist[v] + e.second);
}
int main()
{
std::freopen("../tests/5-30.in", "r", stdin) ;
std::freopen("walking.out", "w", stdout) ;
auto t1 = clock();
int n, m;
assert(2 == scanf("%d%d", &n, &m));
cerr<<"cerr : "<<n<<" "<<m<<"\n";
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
return 0;
}
//-------------- end grader ------------------
#include <ctime>
#include <cassert>
#define pb push_back
#define mp make_pair
st.pb(mp(H[idx], idx));
for (int i = idx - 1; i >= 0; i--)
{
if (H[i] > st.back().first)
st.push_back(mp(H[i], i));
for (int j = 0; j < neiL[i].size(); j++)
{
int cur = neiL[i][j];
if (R[cur] > idx)
{
int pos = upper_bound(st.begin(), st.end(),
mp(Y[cur], -1)) - st.begin();
a[cur] = st[pos].second;
}
}
}
st.clear();
st.pb(mp(H[idx], idx));
for (int i = idx + 1; i < n; i++)
{
if (H[i] > st.back().first)
st.push_back(mp(H[i], i));
for (int j = 0; j < neiR[i].size(); j++)
{
int cur = neiR[i][j];
if (L[cur] < idx)
{
int pos = upper_bound(st.begin(), st.end(),
mp(Y[cur], -1)) - st.begin();
b[cur] = st[pos].second;
}
}
}
m = sky.size();
for (int i = 0; i < m; i++)
{
L[i] = sky[i].first.first;
R[i] = sky[i].first.second;
Y[i] = sky[i].second;
neiL[L[i]].pb(i);
neiR[R[i]].pb(i);
}
}
if (dis[sink] == inf)
return -1;
return dis[sink];
}
if (x1 == x2)
{
adj[u].push_back(mp(v, abs(y2 - y1)));
adj[v].push_back(mp(u, abs(y2 - y1)));
}
else
{
adj[u].push_back(mp(v, abs(x2 - x1)));
adj[v].push_back(mp(u, abs(x2 - x1)));
}
}
void build_graph()
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 100
{
set<int> line;
line.insert(0);
set<int>::iterator it;
map<int, int> st;
vector<int> set_res;
}
}
}
bool cmp(pair<int, pair<int, int> > aa, pair<int, pair<int, int> > bb)
{
if(aa.first < bb.first)
return true;
if(aa.first > bb.first)
return false;
return aa.second.first < bb.second.first;
void init()
{
vector<pair<int, pair<int, int> > > tmp, nw;
for(int i = 0; i < m; i++)
tmp.push_back(mp(Y[i], mp(L[i], R[i])));
m = nw.size();
for (int i = 0; i < m; i++)
{
L[i] = nw[i].second.first;
R[i] = nw[i].second.second;
Y[i] = nw[i].first;
neiL[L[i]].pb(i);
neiR[R[i]].pb(i);
}
init();
all_y.push_back(0);
sort(all_y.begin(), all_y.end());
devide(S);
devide(G);
build_graph();
return dijkstra(add_map(X[S], 0), add_map(X[G], 0));
}
int main()
{
std::freopen("../tests/5-30.in", "r", stdin) ;
std::freopen("walking.out", "w", stdout) ;
auto t1 = clock();
int n, m;
assert(2 == scanf("%d%d", &n, &m));
cerr<<"cerr : "<<n<<" "<<m<<"\n";
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
return 0;
}
//-------------- end grader ------------------
#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
namespace input
{
template<class T> void re(complex<T>& x);
template<class T1, class T2> void re(pair<T1,T2>& p);
template<class T> void re(vector<T>& a);
template<class T, size_t SZ> void re(array<T,SZ>& a);
namespace output
{
template<class T1, class T2> void pr(const pair<T1,T2>& x);
template<class T, size_t SZ> void pr(const array<T,SZ>& x);
template<class T> void pr(const vector<T>& x);
template<class T> void pr(const set<T>& x);
template<class T1, class T2> void pr(const map<T1,T2>& x);
namespace io
{
void setIn(string s) { freopen(s.c_str(),"r",stdin); }
void setOut(string s) { freopen(s.c_str(),"w",stdout); }
modular(const ll& v)
{
val = (-MOD <= v && v <= MOD) ? v : v % MOD;
if (val < 0) val += MOD;
}
{
return a.val == b.val;
}
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int nex;
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 106
Dijkstra<10000000> D;
int N, M, S, G;
vi X,H;
vector<pair<int,vi>> bridge;
vi xx;
Z.pb(z.back());
swap(z,Z);
}
vpi cor[500000];
map<int,pi> mm;
vector<pair<int,pi>> BRIDGE;
{
int l = BRIDGE[seg].s.f, r = BRIDGE[seg].s.s;
while (1)
{
auto it = mm.lb(l);
if (it != begin(mm) && prev(it)->s.f >= l) it --;
if (it == end(mm) || it->f > r) break;
auto IT = *it; mm.erase(it);
if (IT.f < l) mm[IT.f] = {l-1,IT.s.s};
if (IT.s.f > r) mm[r+1] = {IT.s.f,IT.s.s};
}
mm[l] = {r,seg};
}
sort(bridge.rbegin(),bridge.rend());
F0R(i,N) xx.pb(i);
trav(z,bridge)
{
while (ind < sz(xx) && H[xx[ind]] >= z.f) cur.insert(xx[ind++]);
// ps("??",z.f,cur);
split(z.f,z.s,cur,S);
split(z.f,z.s,cur,G);
}
nex = 2*sz(BRIDGE);
F0R(i,sz(BRIDGE))
{
// ps("HUH",i,BRIDGE[i]);
tri(i,2*i,BRIDGE[i].s.f);
tri(i,2*i+1,BRIDGE[i].s.s);
ins(i);
}
mm.clear();
F0Rd(i,sz(BRIDGE))
{
tri(i,2*i,BRIDGE[i].s.f);
tri(i,2*i+1,BRIDGE[i].s.s);
ins(i);
}
D.init(special[0]);
auto res = D.dist[special[1]];
if (res == INF) res = -1;
return res;
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 108
int main()
{
std::freopen("../tests/5-30.in", "r", stdin) ; // execution time : 6.447 s
std::freopen("walking.out", "w", stdout) ;
auto t1 = clock();
int n, m;
assert(2 == scanf("%d%d", &n, &m));
cerr<<"cerr : "<<n<<" "<<m<<"\n";
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
return 0;
}
//-------------- end grader ------------------
#include "../walk.h"
#include <bits/stdc++.h>
struct intv
{
int s, e, x;
bool operator<(const intv &i) const
{
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 109
struct point
{
int x, y, idx;
};
int n, m;
vector<int> witness[MAXN];
vector<pi> event[MAXN];
vector<pi> gph[MAXV];
lint dist[MAXV];
void make_vertex(vector<intv> v)
{
for(auto &i : v)
{
event[i.s].emplace_back(i.x, +1);
event[i.e+1].emplace_back(i.x, -1);
}
multiset<int> swp;
for(int i=0; i<n; i++)
{
for(auto &j : event[i])
{
if(j.second == +1) swp.insert(j.first);
else swp.erase(swp.find(j.first));
}
sort(nxt.begin(), nxt.end());
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 110
witness[s].push_back(0);
witness[e].push_back(0);
vector<pi> points;
vector<intv> hors;
set<int> alive;
for(int i=0; i<n; i++)
{
points.emplace_back(h[i], i);
alive.insert(i);
}
sort(points.begin(), points.end());
sort(hors.begin(), hors.end());
int ptr = 0;
for(auto &i : hors)
{
while(ptr < sz(points) && points[ptr].first < i.x)
{
alive.erase(points[ptr++].second);
}
make_vertex(hors);
vector<point> ans;
for(int i=0; i<n; i++)
{
for(auto &j : witness[i])
{
int num = ans.size();
ans.push_back({x[i], j, num});
}
}
int main()
{
std::freopen("../tests/5-30.in", "r", stdin) ; // execution time : 5.501 s
std::freopen("walking.out", "w", stdout) ;
auto t1 = clock();
int n, m;
assert(2 == scanf("%d%d", &n, &m));
cerr<<"cerr : "<<n<<" "<<m<<"\n";
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", result);
fclose(stdout);
auto t4 = clock();
return 0;
}
CAPITOLUL 1. IOI 2019 1.6. SKY WALKING 112
2.1 Combo
Problema 1 - Combo 100 de puncte
Vă jucaţi un joc de acţiune. Controlerul jocului are 4 butoane, A, B, X, şi Y . În acest joc
acumulaţi monede cu diferite combo-uri. Puteţi obţine un combo apăsând o secvenţă de butoane.
Jocul are o secvenţă secretă a butoanelor, care poate fi reprezentată ca o secvenţă de caractere
S formată cu acele 4 caractere. Nu cunoaşteţi secvenţa S, dar ı̂i ştiţi lungimea N .
Ştiţi de asemenea că primul caracter al lui S nu reapare nicăieri ı̂n acesta. De
exemplu, S poate fi ”ABXYY” sau ”XYYAA”, dar nu poate fi ”AAAAA” sau ”BXYBX ”.
Puteţi apăsa o secvenţă de cel mult 4N butoane pentru a forma un combo. Fie p secvenţa de
caractere care reprezintă secvenţa de butoane apăsate. Numărul de monede pe care le veţi primi
pentru acest combo este calculat ca lungimea celui mai lung prefix al lui S care este şi subsecvenţă
a lui p.
O subsecvenţă a unei secvenţe de caractere t este o secvenţă (posibil vidă) de caractere aflate
pe poziţii consecutive ı̂n t.
Un prefix al lui t este o subsecvenţă a lui t care fie este vidă, fie conţine primul caracter din t.
De exemplu, dacă S este ”ABXYY” şi p este ”XXYYABYABXAY”, veţi primi 3 monede
deoarece ”ABX” este cel mai lung prefix al lui S care este şi subsecvenţă a lui p.
Sarcina voastră este să determinaţi secvenţa secretă de caractere S utilizând puţine combo-uri.
Detalii de implementare
30
argint: Alex Tatomir, Nicolae Bălcescu (Brăila),
. argint: Tiberiu-Ioan Muşat, Tudor Vianu (Bucureşti)
. argint: Ştefan Constantin-Buliga, CNI ”Tudor Vianu” Bucureşti
. bronz: Costin-Andrei Oncescu, Dinicu Golescu (Campulung).
113
CAPITOLUL 2. IOI 2018 2.1. COMBO 114
a Această funcţie va ı̂ntoarce numărul de monede pe care le veţi primi dacă apăsaţi secvenţa
de butoane reprezentată de secvenţa p.
Dacă vreuna din condiţiile de mai sus nu este satisfăcută, programul vostru va fi evaluat ca
Wrong answer. Altfel, programul vostru va fi evaluat ca Accepted, iar punctajul vostru va fi
calculat după numărul de apeluri ale funcţiei press (vezi Subtask-uri).
Exemple
Apel Întoarcere
press(”XXYYABYABXAY”) 3
press(”ABXYY”) 5
press(”ABXYYABXYY”) 5
press(””) 0
press(”X”) 0
press(”BXYY”) 0
press(”YYXBA”) 1
press(”AY”) 1
Pentru primul apel al funcţiei press, ”ABX” apare ı̂n ”XXYYABYABXAY” ca subsecvenţă,
dar ”ABXY” nu apare, deci se va ı̂ntoarce 3.
Pentru al treilea apel al funcţie press, ”ABXYY” apare ı̂n ”ABXYYABXYY” ca subsecvenţă,
deci se va ı̂ntoarce 5.
Pentru al şaselea apel al funcţiei press, niciun prefix de-al secvenţei ”ABXYY” ı̂n afară de
subsecvenţa vidă nu apare ı̂n ”BXYY” ca subsecvenţă, deci se va ı̂ntoarce 0.
La sfârşit, guess_sequence(5) ar trebui să ı̂ntoarcă ”ABXYY”.
Fişierul sample-01-in.txt din pachetul arhivat anexat corespunde acestui exemplu.
Restricţii
Subtaskuri
1. (5 puncte) N 3
2. (95 de puncte) Fără constrângeri adiţionale. Pentru acest subtask punctajul vostru este
calculat după cum urmează. Fie q numărul de apeluri ale funcţiei press.
` Dacă q & N 2, punctajul vostru este 95.
` Dacă N 2 $ q & N 10, punctajul vostru este 95 3 q N 2.
` Dacă N 10 $ q & 2N 1, punctajul vostru este 25.
` Dacă maxrN 10, 2N 1x $ q & 4N , punctajul vostru este 5.
` Altfel, punctajul vostru este 0.
Luaţi la cunoştinţă că punctajul pentru un subtask este minimul dintre punctajele testelor
care alcătuiesc acel subtask.
Exemplu de grader
CAPITOLUL 2. IOI 2018 2.1. COMBO 115
Dacă programul vostru este evaluat ca Accepted, atunci grader-ul local va afişa Accepted:
q unde q va reprezenta numărul de apeluri ale funcţiei press.
Daca programul vostru este evaluat ca Wrong answer, atunci grader-ul local va afişa
Wrong answer: M SG. Semnificaţia lui M SG este după cum urmează:
a invalid press: O valoare greşită a lui p a fost folosită ı̂n apelul funcţiei press. Mai
exact, lungimea lui p nu este ı̂ntre 0 şi 4N inclusiv, sau un caracter din p nu este ori A, ori B, ori
X ori Y .
a too many moves: Funcţia press a fost apelată de mai mult de de ori.
a wrong guess: Valoarea ı̂ntoarsă de funcţia guess_sequence nu este S.
There is a secret string S which consists of four characters ’A’, ’B’, ’X’, or ’Y’. The first character
of S never reappears in S. You know only N , the length of S.
You can ask a query as follows:
You specify a string of the above four characters whose length is not larger than 4N .
You get the maximum length of the prefixes of S which are also substrings of the specified
string.
Q=4N
Determine the characters of S from the beginning one by one.
For each position, try by all four characters one by one.
Q=2N+1 or 2N
Determine the characters of S from the beginning one by one.
For the first position, determine the character by three asks. For each position except the
first one, considering the constraint of S, determine the character by two asks.
Or for each position, using conditional branches, determine the character by two asks.
Q=N+2
Determine the characters of S from the beginning one by one.
Except the first or last position, determine the character by one ask as follows.
` Assume that the first character of S is, for example, ’A’.
` Let s be the prefix of S already known.
` Ask by s+’B’+s+’XB’+s+’XX’+s+’XY’.
` If the next character is ’B’, then ¶s¶ 1 is returned. If it is ’X’, then ¶s¶ 2 is returned.
If it is ’Y’, then ¶s¶ is returned.
Note that if Q & N 10, you can get nearly full points according as Q.
TASK=combo
std::string guess_sequence(int N)
{
std::string p = "";
for (int i = 0; i < 4 * N; ++i)
{
p += ’A’;
}
int coins = press(p);
std::string S = "";
for (int i = 0; i < N; ++i)
{
S += ’A’;
}
return S;
}
namespace
{
int N;
std::string S;
int num_moves;
} // namespace
int press(std::string p)
{
if (++num_moves > MAX_NUM_MOVES)
{
wrong_answer("too many moves");
}
int len = p.length();
if (len > 4 * N)
{
wrong_answer("invalid press");
CAPITOLUL 2. IOI 2018 2.1. COMBO 117
}
for (int i = 0; i < len; ++i)
{
if (p[i] != ’A’ && p[i] != ’B’ && p[i] != ’X’ && p[i] != ’Y’)
{
wrong_answer("invalid press");
}
}
int coins = 0;
for (int i = 0, j = 0; i < len; ++i)
{
if (j < N && S[j] == p[i])
{
++j;
} else if (S[0] == p[i])
{
j = 1;
}
else
{
j = 0;
}
coins = std::max(coins, j);
}
return coins;
}
int main()
{
char buffer[MAX_N + 1];
if (scanf("%s", buffer) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
S = buffer;
N = S.length();
num_moves = 0;
std::string answer = guess_sequence(N);
if (answer != S)
{
wrong_answer("wrong guess");
exit(0);
}
printf("Accepted: %d\n", num_moves);
return 0;
}
#include <algorithm>
#include <string>
//#include "combo.h"
namespace
{
constexpr int MAX_N = 2000;
constexpr int MAX_NUM_MOVES = 8000;
int N;
std::string S;
int num_moves;
int press(std::string p)
{
if (++num_moves > MAX_NUM_MOVES) { wrong_answer("too many moves"); }
string guess_sequence(int N)
{
string p = "";
if(press("AB") >= 1) p = press("A") ? "A" : "B";
else p = press("X") ? "X" : "Y";
while((int)p.size() <= N - 2)
{
int query = press(p+chr[0]+chr[0]+p+chr[0]+chr[1]+p+chr[1]+chr[0]);
if(query == p.size())
{
p.push_back(chr[2]);
}
else
if(query == p.size() + 1)
{
query = press(p + chr[1] + chr[2]);
if(query == p.size()) p = p + chr[0] + chr[2];
else if(query == p.size() + 1) p = p + chr[1] + chr[1];
else p = p + chr[1] + chr[2];
}
else
{
query = press(p + chr[0] + chr[1]);
if(query == p.size()) p = p + chr[1] + chr[0];
else if(query == p.size() + 1) p = p + chr[0] + chr[0];
else p = p + chr[0] + chr[1];
}
}
while(p.size() != N)
{
if(press(p + chr[0]) == p.size() + 1) p.push_back(chr[0]);
else if(press(p + chr[1]) == p.size() + 1) p.push_back(chr[1]);
else p.push_back(chr[2]);
}
return p;
}
int main()
{
std::freopen("../in/02-077.txt", "r", stdin);
//std::freopen("combo.out", "w", stdout) ;
}
S = buffer;
N = S.length();
num_moves = 0;
std::string answer = guess_sequence(N); // functia de implementat ... !!!
if (answer != S)
{
wrong_answer("wrong guess");
exit(0);
}
printf("Accepted: num_moves=%d N=%d\n", num_moves,N);
return 0;
}
#include <algorithm>
#include <string>
#include "combo.h"
namespace
{
constexpr int MAX_N = 2000;
constexpr int MAX_NUM_MOVES = 8000;
int N;
std::string S;
int num_moves;
int press(std::string p)
{
if (++num_moves > MAX_NUM_MOVES) { wrong_answer("too many moves"); }
int coins = 0;
for (int i = 0, j = 0; i < len; ++i)
{
if (j < N && S[j] == p[i]) { ++j; }
else if (S[0] == p[i]) { j = 1; }
else { j = 0; }
coins = std::max(coins, j);
}
return coins;
}
string guess_sequence(int N)
{
string p = "";
if(press("AB") >= 1) p = press("A") ? "A" : "B";
else p = press("X") ? "X" : "Y";
while((int)p.size() <= N - 2)
{
int query = press(p+chr[0]+chr[0]+p+chr[0]+chr[1]+p+chr[1]+chr[0]);
if(query == p.size())
{
p.push_back(chr[2]);
}
else
if(query == p.size() + 1)
{
query = press(p + chr[1] + chr[2]);
if(query == p.size()) p = p + chr[0] + chr[2];
else if(query == p.size() + 1) p = p + chr[1] + chr[1];
else p = p + chr[1] + chr[2];
}
else
{
query = press(p + chr[0] + chr[1]);
if(query == p.size()) p = p + chr[1] + chr[0];
else if(query == p.size() + 1) p = p + chr[0] + chr[0];
else p = p + chr[0] + chr[1];
}
}
while(p.size() != N)
{
if(press(p + chr[0]) == p.size() + 1) p.push_back(chr[0]);
else if(press(p + chr[1]) == p.size() + 1) p.push_back(chr[1]);
else p.push_back(chr[2]);
}
return p;
}
int main()
{
std::freopen("../in/02-077.txt", "r", stdin);
//std::freopen("combo.out", "w", stdout) ;
num_moves = 0;
if (answer != S)
{
wrong_answer("wrong guess");
exit(0);
}
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include "combo.h"
namespace
{
constexpr int MAX_N = 2000;
constexpr int MAX_NUM_MOVES = 8000;
int N;
std::string S;
int num_moves;
int press(std::string p)
{
if (++num_moves > MAX_NUM_MOVES) { wrong_answer("too many moves"); }
int coins = 0;
for (int i = 0, j = 0; i < len; ++i)
{
if (j < N && S[j] == p[i]) { ++j; }
else if (S[0] == p[i]) { j = 1; }
else { j = 0; }
coins = std::max(coins, j);
}
return coins;
}
static string r;
static char a[3];
string guess_sequence(int N)
{
int x = press(string("XY"));
int y = press(string("BY"));
if(r.length() < N)
{
int x = press(r + "X" + r + "Y");
int y = press(r + "B" + r + "Y");
r += b[2 * (x - r.length()) + (y - r.length())];
}
return r;
}
int main()
{
std::freopen("../in/02-077.txt", "r", stdin) ;
//std::freopen("combo.out", "w", stdout) ;
num_moves = 0;
if (answer != S)
{
wrong_answer("wrong guess");
exit(0);
}
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include "combo.h"
namespace
{
constexpr int MAX_N = 2000;
constexpr int MAX_NUM_MOVES = 8000;
int N;
std::string S;
int num_moves;
int press(std::string p)
{
if (++num_moves > MAX_NUM_MOVES) { wrong_answer("too many moves"); }
{
if (p[i] != ’A’ && p[i] != ’B’ && p[i] != ’X’ && p[i] != ’Y’)
{
wrong_answer("invalid press");
}
}
int coins = 0;
for (int i = 0, j = 0; i < len; ++i)
{
if (j < N && S[j] == p[i]) { ++j; }
else if (S[0] == p[i]) { j = 1; }
else { j = 0; }
coins = std::max(coins, j);
}
return coins;
}
std::string guess_sequence(int N)
{
char first = press("AB") == 0? "YX"[press("X")]:
"BA"[press("A")];
char a, b, c;
if(first == ’A’) a = ’B’, b = ’X’, c = ’Y’;
if(first == ’B’) a = ’A’, b = ’X’, c = ’Y’;
if(first == ’X’) a = ’A’, b = ’B’, c = ’Y’;
if(first == ’Y’) a = ’A’, b = ’B’, c = ’X’;
if (S.length() < N)
{
if (press(S + a) - S.length() == 1)
{
S += a;
}
else
if(press(S + b) - S.length() == 1)
{
S += b;
}
else
{
S += c;
}
}
return S;
}
int main()
{
std::freopen("../in/02-077.txt", "r", stdin) ;
//std::freopen("combo.out", "w", stdout) ;
num_moves = 0;
if (answer != S)
{
wrong_answer("wrong guess");
exit(0);
}
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include "combo.h"
namespace
{
constexpr int MAX_N = 2000;
constexpr int MAX_NUM_MOVES = 8000;
int N;
std::string S;
int num_moves;
}
}
int press(std::string p)
{
if (++num_moves > MAX_NUM_MOVES) { wrong_answer("too many moves"); }
int coins = 0;
for (int i = 0, j = 0; i < len; ++i)
{
if (j < N && S[j] == p[i]) { ++j; }
else if (S[0] == p[i]) { j = 1; }
else { j = 0; }
coins = std::max(coins, j);
}
return coins;
}
std::string guess_sequence(int N)
{
int sr = 0;
if (press("AB") > 0) sr += 2;
if (press("AX") > 0) sr++;
string sc[4] = {"Y", "X", "B", "A"};
string s = "";
s += sc[sr];
string c[3];
int cs = 0;
for (int i = 0; i < 4; i++)
if (i != sr)
{
c[cs] = sc[i];
cs++;
}
if (t == 0) s += c[0];
else if (t == 1)
{
string ps = s + c[1] + c[2];
int t1 = press(ps) - s.length();
if (t1 == 0) s += c[2] + c[1];
else if (t1 == 1) s += c[1] + c[1];
else s += c[1] + c[2];
i++;
}
else
{
string ps = s + c[2] + c[0];
int t1 = press(ps) - s.length();
if (t1 == 0) s += c[1] + c[0];
CAPITOLUL 2. IOI 2018 2.1. COMBO 126
return s;
}
int main()
{
std::freopen("../in/02-077.txt", "r", stdin) ;
//std::freopen("combo.out", "w", stdout) ;
num_moves = 0;
if (answer != S)
{
wrong_answer("wrong guess");
exit(0);
}
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include "combo.h"
namespace
{
constexpr int MAX_N = 2000;
constexpr int MAX_NUM_MOVES = 8000;
int N;
std::string S;
int num_moves;
int press(std::string p)
{
if (++num_moves > MAX_NUM_MOVES) { wrong_answer("too many moves"); }
wrong_answer("invalid press");
}
}
int coins = 0;
for (int i = 0, j = 0; i < len; ++i)
{
if (j < N && S[j] == p[i]) { ++j; }
else if (S[0] == p[i]) { j = 1; }
else { j = 0; }
coins = std::max(coins, j);
}
return coins;
}
std::string guess_sequence(int N)
{
std::string p = "";
if(press("AB") >= 1) p = press("A") ? "A" : "B";
else p = press("X") ? "X" : "Y";
std::vector<char> chr = {’A’, ’B’, ’X’, ’Y’};
chr.erase(find(chr.begin(), chr.end(), p[0]));
while((int)p.size() <= N - 2)
{
int query = press(p + chr[0] + chr[0] +
p + chr[0] + chr[1] +
p + chr[1] + chr[0]);
if(query == p.size())
{
p.push_back(chr[2]);
}
else
if(query == p.size() + 1)
{
query = press(p + chr[1] + chr[2]);
if(query == p.size()) p = p + chr[0] + chr[2];
else
if(query == p.size() + 1) p = p + chr[1] + chr[1];
else p = p + chr[1] + chr[2];
}
else
{
query = press(p + chr[0] + chr[1]);
if(query == p.size()) p = p + chr[1] + chr[0];
else
if(query == p.size() + 1) p = p + chr[0] + chr[0];
else p = p + chr[0] + chr[1];
}
}
while(p.size() != N)
{
if(press(p + chr[0]) == p.size() + 1) p.push_back(chr[0]);
else
if(press(p + chr[1]) == p.size() + 1) p.push_back(chr[1]);
else p.push_back(chr[2]);
}
return p;
}
int main()
{
std::freopen("../in/02-077.txt", "r", stdin) ;
//std::freopen("combo.out", "w", stdout) ;
num_moves = 0;
CAPITOLUL 2. IOI 2018 2.2. SEATS 128
if (answer != S)
{
wrong_answer("wrong guess");
exit(0);
}
2.2 Seats
Problema 2 - Seats 100 de puncte
Detalii de implementare
Exemple
0 3 4
1 2 5
Să presupunem că grader-ul apelează swap_seats(0, 5). După cererea 0, schema de am-
plasare este următoarea:
5 3 4
1 2 0
Mulţimile de locuri care corespund concurenţilor r0x, r0, 1, 2x, şi r0, 1, 2, 3, 4, 5x sunt drep-
tunghiulare şi frumoase. Astfel, gradul de frumuseţe al schemei de amplasare este 3, şi
swap_seats va returna 3.
Să zicem că grader-ul apelează swap_seats(0, 5) din nou. După cererea 1, schema de
amplasare revine la starea iniţială. Mulţimile de locuri care corespund concurenţilor r0x, r0, 1x,
r0, 1, 2, 3x, şi r0, 1, 2, 3, 4, 5x sunt dreptunghiulare şi frumoase. Prin urmare, gradul de frumuseţe
al schemei de amplasare este 4, şi swap_seats va ı̂ntoarce 4.
Fişierele sample-01-in.txt şi sample-01-out.txt ı̂n pachetul arhivat anexat corespund
acestui exemplu. Pachetul conţine şi alte exemple de intrări/ieşiri.
Restricţii
a 1&H
a 1&W
a H W & 1000000
a 0 & Ri & H 1 (0 & i & HW 1)
a 0 & Ci & W 1 (0 & i & HW 1)
a Ri , Ci j Rj , Cj (0 & i $ j & H W 1)
a 1 & Q & 50000
a 0 & a & H W 1 pentru orice apel swap_seats
a 0 & b & H W 1 pentru orice apel swap_seats
a a j b pentru orice apel swap_seats
Subtaskuri
Exemplu de grader
Manage the numbers of such two-times-two squares for all values of t and count the number
of t-s satisying the condition efficiently using a lazy propagation segment tree and deal with each
query in O log HW time.
CAPITOLUL 2. IOI 2018 2.2. SEATS 131
TASK=seats
std::vector<int> r;
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
int H = read_int();
int W = read_int();
int Q = read_int();
std::vector<int> R(H * W), C(H * W);
for (int i = 0; i < H * W; ++i)
{
R[i] = read_int();
C[i] = read_int();
}
std::vector<int> A(Q), B(Q);
for (int j = 0; j < Q; ++j)
{
A[j] = read_int();
B[j] = read_int();
}
CAPITOLUL 2. IOI 2018 2.2. SEATS 132
give_initial_chart(H, W, R, C);
for (int j = 0; j < Q; ++j)
{
int answer = swap_seats(A[j], B[j]);
printf("%d\n", answer);
}
return 0;
}
struct node
{
node()
{
sum = min = 0; cnt = 1;
}
node(int v)
{
sum = min = v; cnt = 1;
}
res.cnt = 0;
if (res.min == min) res.cnt += cnt;
if (res.min == sum + t.min) res.cnt += t.cnt;
return res;
}
void add(int p)
{
sum += p;
min += p;
}
} IT[Z*2];
int N, A[1001001];
bool chk[1001001];
int H, W;
vector<int> R, C;
void upd(int x)
{
x /= 2;
CAPITOLUL 2. IOI 2018 2.2. SEATS 133
while (x)
{
IT[x] = IT[x*2] * IT[x*2+1];
x /= 2;
}
}
set<int> ups;
int s = N, e = 0;
if (i < u[0] && i < u[1])
{
s = i + Z;
e = min(u[0],u[1]) + Z;
}
if (s < e)
{
IT[s].add(+p);
IT[e].add(-p);
if (up)
{
ups.insert(s);
ups.insert(e);
}
}
}
}
swap(R[a],R[b]);
swap(C[a],C[b]);
A[R[a]*W+C[a]] = a;
A[R[b]*W+C[b]] = b;
//======================================================================
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int H = read_int();
int W = read_int();
int Q = read_int();
auto t2 = clock();
give_initial_chart(H, W, R, C);
auto t3 = clock();
{
int answer = swap_seats(A[j], B[j]);
printf("%d\n", answer);
}
auto t4 = clock();
fclose(stdout);
return 0;
}
//======================================================================
/*
t2-t1 = 0.896
t3-t2 = 0.449
t4-t3 = 1.873
#include <ctime>
//#include <time.h> /* clock */
//#include <cstdio>
#include <stdio.h> // citire mai rapida !!!
#include <cstdlib>
#include <vector>
#include "seats.h"
#include <cstring>
#include <iostream>
#include <algorithm>
int h, w, n;
vector<int> R, C;
vector<vector<int>> idx;
struct segtree
{
struct node
{
llong mn, ct, lz;
node operator+(const node &p) const
{
node ret;
ret.mn = min(mn, p.mn);
ret.ct = 0;
if (ret.mn == mn) ret.ct += ct;
if (ret.mn == p.mn) ret.ct += p.ct;
ret.lz = 0;
return ret;
}
} seg[1 << 21];
if (s == e)
{
seg[i].mn = v[s];
seg[i].ct = 1;
seg[i].lz = 0;
return;
}
int m = (s + e) / 2;
init(i << 1, s, m, v);
init(i << 1 | 1, m + 1, e, v);
seg[i] = seg[i << 1] + seg[i << 1 | 1];
}
void spread(int i)
{
seg[i << 1].mn += seg[i].lz;
seg[i << 1].lz += seg[i].lz;
seg[i << 1 | 1].mn += seg[i].lz;
seg[i << 1 | 1].lz += seg[i].lz;
seg[i].lz = 0;
}
spread(i);
int m = (s + e) / 2;
update(i << 1, s, m, x, y, v);
update(i << 1 | 1, m + 1, e, x, y, v);
seg[i] = seg[i << 1] + seg[i << 1 | 1];
}
sort(ps.begin(), ps.end());
ps.erase(unique(ps.begin(), ps.end()), ps.end());
for (pii i : ps) update(i.first, i.second, -1);
swap(idx[R[a]][C[a]], idx[R[b]][C[b]]);
swap(R[a], R[b]); swap(C[a], C[b]);
for (pii i : ps) update(i.first, i.second, 1);
return seg.get();
}
// ----------------------------------------------
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int H = read_int();
int W = read_int();
int Q = read_int();
auto t2 = clock();
give_initial_chart(H, W, R, C);
auto t3 = clock();
auto t4 = clock();
fclose(stdout);
return 0;
}
/*
t2-t1 = 3.124
t3-t2 = 0.67
t4-t3 = 8.047
#include <ctime>
//#include <time.h> /* clock */
//#include <cstdio>
#include <stdio.h> // citire mai rapida !!!
#include <vector>
#include "seats.h"
#include <cstring>
#include <iostream>
#include <algorithm>
int H,W,NUM;
int val[maxn],presum[maxn];
vector<int> R,C;
int S[maxn],T[maxn];
struct node
{
int dta;
int s,cnt;
node *lc,*rc;
void downdate()
{
CAPITOLUL 2. IOI 2018 2.2. SEATS 139
if(dta)
{
if(lc)lc->tagdta(dta);
if(rc)rc->tagdta(dta);
dta=0;
}
}
void update()
{
if(lc->s<rc->s)
{
s=lc->s;
cnt=lc->cnt;
}
else if(rc->s<lc->s)
{
s=rc->s;
cnt=rc->cnt;
}
else
{
s=lc->s;
cnt=lc->cnt+rc->cnt;
}
}
void Add(int l,int r,const int &a,const int &b,const int &c)
{
if(l>=a&&r<=b)
{
tagdta(c);
return;
}
int mid=l+r>>1;
downdate();
if(a<=mid)lc->Add(l,mid,a,b,c);
if(b>mid)rc->Add(mid+1,r,a,b,c);
update();
}
} ndl[maxn*2],*ns=ndl,*root;
int res=0;
for(int k=0;k<4;k++)
if(w>>k&1)
{
int i=x-1+dx[k];
int j=y-1+dy[k];
int t=seat(s,x,y);
int a=seat(s,i+dx[kˆ1],j+dy[kˆ1]); // XOR
int b=seat(s,i+dx[kˆ2],j+dy[kˆ2]);
int c=seat(s,i+dx[k],j+dy[k]);
res+=ValTable[c<t][(a<t)+(b<t)];
}
//cout<<endl;
return res;
}
// ----------------------------------------------
namespace
{
CAPITOLUL 2. IOI 2018 2.2. SEATS 141
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int H = read_int();
int W = read_int();
int Q = read_int();
auto t2 = clock();
give_initial_chart(H, W, R, C);
auto t3 = clock();
auto t4 = clock();
fclose(stdout);
return 0;
}
/*
t2-t1 = 3.21
t3-t2 = 0.715
t4-t3 = 2.651
#include <ctime>
CAPITOLUL 2. IOI 2018 2.2. SEATS 142
//#include <cstdio>
#include <stdio.h> // citire mai rapida !!!
#include <algorithm>
#include <vector>
#include <set>
#include <iostream>
struct node
{
node()
{
sum = min = 0; cnt = 1;
}
node(int v)
{
sum = min = v; cnt = 1;
}
res.cnt = 0;
if (res.min == min) res.cnt += cnt;
if (res.min == sum + t.min) res.cnt += t.cnt;
return res;
}
void add(int p)
{
sum += p;
min += p;
}
} IT[Z*2];
int N, A[1001001];
bool chk[1001001];
int H, W;
vector<int> R, C;
void upd(int x)
{
x /= 2;
while (x)
{
IT[x] = IT[x*2] * IT[x*2+1];
x /= 2;
}
}
set<int> ups;
else
{
if (!chk[i]) return;
chk[i] = 0;
}
int s = N, e = 0;
if (i < u[0] && i < u[1])
{
s = i + Z;
e = min(u[0],u[1]) + Z;
}
if (s < e)
{
IT[s].add(+p);
IT[e].add(-p);
if (up)
{
ups.insert(s);
ups.insert(e);
}
}
}
}
swap(R[a],R[b]);
swap(C[a],C[b]);
A[R[a]*W+C[a]] = a;
A[R[b]*W+C[b]] = b;
// ----------------------------------------------
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int H = read_int();
int W = read_int();
int Q = read_int();
auto t2 = clock();
give_initial_chart(H, W, R, C);
auto t3 = clock();
auto t4 = clock();
fclose(stdout);
return 0;
}
CAPITOLUL 2. IOI 2018 2.2. SEATS 145
/*
t2-t1 = 3.182
t3-t2 = 0.458
t4-t3 = 4.476
//#include <cstdio>
#include <stdio.h> // citire mai rapida !!!
#include "seats.h"
#include <bits/stdc++.h>
int h,w;
int r[1000010];
int c[1000010];
pii arr[1000010];
//segtree
pii sum[8000000];
pii minimo[8000000];
int counter[8000000];
vector<vector<int> >table;
int x,y,z,w;
x=t[0][0]+t[0][1]+t[1][0]+t[1][1];
y=t[1][0]+t[1][1]+t[2][0]+t[2][1];
z=t[0][1]+t[0][2]+t[1][1]+t[1][2];
w=t[1][1]+t[1][2]+t[2][1]+t[2][2];
int cnt[5];
for(int i=0;i<5;i++)cnt[i]=0;
cnt[x]++;
cnt[y]++;
cnt[z]++;
cnt[w]++;
arr[table[a][b]].first=cnt[0]-cnt[1];
arr[table[a][b]].second=cnt[2]-cnt[3];
}
int mid=(a+b)/2;
build(a,mid,2*node);
build(mid+1,b,2*node+1);
sum[node]=Sum(sum[2*node],sum[2*node+1]);
minimo[node]=min(minimo[2*node],Sum(minimo[2*node+1],sum[2*node]));
counter[node]=0;
if(minimo[node]==minimo[2*node])
{
counter[node]+=counter[2*node];
}
if(minimo[node]==Sum(minimo[2*node+1],sum[2*node]))
{
counter[node]+=counter[2*node+1];
}
}
int mid=(a+b)/2;
update(a,mid,2*node,pos);
update(mid+1,b,2*node+1,pos);
sum[node]=Sum(sum[2*node],sum[2*node+1]);
minimo[node]=min(minimo[2*node],Sum(minimo[2*node+1],sum[2*node]));
counter[node]=0;
if(minimo[node]==minimo[2*node])
{
counter[node]+=counter[2*node];
}
if(minimo[node]==Sum(minimo[2*node+1],sum[2*node]))
{
counter[node]+=counter[2*node+1];
}
}
for(int i=0;i<w*h;i++)
{
r[i]=R[i];
c[i]=C[i];
table[R[i]][C[i]]=i;
}
for(int i=0;i<h;i++)
{
for(int j=0;j<w;j++)update_pos(i,j);
}
build(0,w*h-1,1);
//for(int i=0;i<h*w;i++)cout<<arr[i].second<<endl;
//cout<<counter[1]<<endl;
}
update_pos(r[b]+i,c[b]+j);
if(r[b]+i>=0 && r[b]+i<=h-1 && c[b]+j>=0 && c[b]+j<=w-1)
update(0,h*w-1,1,table[r[b]+i][c[b]+j]);
}
}
return counter[1];
}
// ----------------------------------------------
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
}
int main()
{
auto t1 = clock();
int H = read_int();
int W = read_int();
int Q = read_int();
auto t2 = clock();
give_initial_chart(H, W, R, C);
auto t3 = clock();
auto t4 = clock();
fclose(stdout);
return 0;
}
/*
t2-t1 = 0.87
t3-t2 = 0.859
t4-t3 = 4.672
//#include <cstdio>
#include <stdio.h> // citire mai rapida !!!
#include "seats.h"
#include <algorithm>
#include <bits/stdc++.h>
std::vector<int> r;
if(A[rt])
{
T[rt<<1] += A[rt];
A[rt<<1] += A[rt];
T[rt<<1|1] += A[rt];
A[rt<<1|1] += A[rt];
A[rt] = 0;
}
int m = (l + r) >> 1;
if(s <= m) add(rt<<1, l, m, s, e, c);
if(m < e) add(rt<<1|1, m+1, r, s, e, c);
pushup(rt);
}
int rval[1000010];
sort(rr, rr+4);
}
rval[(r-1)*M+(c-1)] = x;
for(int dx:{-1,0}) for(int dy:{-1,0})
{
int tt[4];
get_val(r+dx, c+dy, tt);
if(tt[0]<tt[1]) add(tt[0], tt[1]-1, 1);
if(tt[2]<tt[3]) add(tt[2], tt[3]-1, 100);
}
}
// ....................................................
std::vector<int> tC)
{
N = H; M = W;
P = N * M;
init(1, 1, P);
rep(i, P) R[i + 1] = tR[i] + 1, C[i + 1] = tC[i] + 1;
// ----------------------------------------------
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int H = read_int();
int W = read_int();
int Q = read_int();
auto t2 = clock();
give_initial_chart(H, W, R, C);
auto t3 = clock();
{
int answer = swap_seats(A[j], B[j]);
printf("%d\n", answer);
}
auto t4 = clock();
fclose(stdout);
return 0;
}
/*
t2-t1 = 0.875
t3-t2 = 2.781
t4-t3 = 3.508
2.3 Werewolf
Problema 3 - Werewolf 100 de puncte
În prefectura Ibaraki din Japonia există N oraşe şi M drumuri. Oraşele sunt numerotate de la
0 la N 1 ı̂n ordine crescătoare a populaţiei. Fiecare drum conectează o pereche de oraşe distincte
şi poate fi traversat ı̂n ambele direcţii. Puteţi călători din orice oraş ı̂n orice alt oraş utilizând
unul sau mai multe din aceste drumuri.
Planificaţi Q călătorii, numerotate de la 0 la Q 1. Călătoria i (0 && Q 1) este o călătorie
din oraşul Si către oraşul Ei .
Sunteţi un vârcolac. Puteţi lua două forme: forma unui om şi forma unui lup. La ı̂nceputul
fiecărei călătorii aveţi forma unui om. La sfârşitul fiecărei călătorii trebuie să aveţi forma unui
lup. Pe parcursul călătoriei trebuie să vă transformaţi (să vă schimbaţi din forma unui om ı̂n
forma unui lup) exact o dată. Vă puteţi transforma doar când sunteţi ı̂ntr-un oraş (posibil Si sau
Ei ).
Viaţa de vârcolac nu este una uşoară. Trebuie să evitaţi oraşele mai puţin populate atunci
când aveţi forma unui om şi oraşele mai populate atunci când aveţi forma unui lup. Pentru orice
călătorie i (0 & i & Q 1), există doi ı̂ntregi Li şi Ri (0 & Li & Ri & N 1), care indică oraşele ce
trebuie evitate. Mai exact, pentru călătoria i, trebuie să evitaţi oraşele 0, 1, ..., Li 1 când aveţi
forma unui om şi să evitaţi oraşele Ri 1, Ri 2, ..., N 1 când aveţi forma unui lup. Aceasta
ı̂nseamnă că, ı̂n călătoria i, vă veţi transforma ı̂n unul din oraşele Li , Li 1, ..., Ri .
Sarcina dumneavoastră este să determinaţi pentru fiecare călătorie dacă este posibil să ajungeţi
din oraşul Si ı̂n oraşul Ei , respectând condiţiile descrise mai sus. Drumul ales poate fi de orice
lungime.
Detalii de implementare
a X şi Y : tablouri unidimensionale de dimensiune M . Pentru fiecare j (0 & j & M 1), oraşul
X j este conectat printr-un drum direct cu oraşul Y j .
a S, E, L, şi R: tablouri unidimensionale de dimensiune Q, reprezentând călătoriile.
Luaţi la cunoştinţă că valorile M şi Q reprezintă dimensiunea tablourilor şi pot fi obţinute
după cum este indicat ı̂n Observaţiile de implementare.
Funcţia check_validity este apelată o singură dată pentru fiecare test. Această funcţie
trebuie să ı̂ntoarcă un tablou unidimensional A conţinând Q numere ı̂ntregi. Valoarea lui Ai
(0 & i & Q 1) trebuie să fie 1 dacă călătoria este posibilă satisfăcând constrângerile menţionate
anterior, sau 0 ı̂n caz contrar.
Exemple
Grader-ul apelează
check_validity(6, [5, 1, 1, 3, 3, 5], [1, 2, 3, 4, 0, 2],
[4, 4, 5], [2, 2, 4], [1, 2, 3], [2, 2, 4]).
Pentru călătoria 0, puteţi traversa din oraşul 4 către oraşul 2 ı̂n felul următor:
a Porniţi din oraşul 4 (aveţi forma unui om)
a Mergeţi către oraşul 3 (aveţi forma unui om)
a Mergeţi către oraşul 1 (aveţi forma unui om)
a Transformaţi-vă ı̂n forma unui lup (aveţi forma unui lup)
a Mergeţi către oraşul 2 (aveţi forma unui lup)
Pentru călătoriile 1 şi 2, nu puteţi traversa ı̂ntre oraşele indicate.
Prin urmare, programul dumneavoastră va ı̂ntoarce 1, 0, 0.
Fişierele sample-01-in.txt şi sample-01-out.txt din pachetul anexat sub forma de
arhivă corespund acestui exemplu. Un alt exemplu intrare/ieşire, este de asemenea disponibil ı̂n
pachet.
Restricţii
` Si j Ei
` Li & Ri
Subtaskuri
Exemplu de grader
Given a connected undirected graph with N vertices and M edges. The vertices are numbered
from 0 through N 1.
Q queries are given. The query i (0 & i & Q 1) is represented by four integers Si , Ei , Li ,
Ri satisfying Li & Si and Ei & Ri . You want to travel from the vertex Si to the vertex Ei . Your
route must satisfy the following condition:
Assume that you visit the vertices V0 , V1 , V2 , ..., Vp in this order (V0 Si , Vp Ei ). Then
there is an index q (0 & q & p) such that Li & V0 , V1 , ..., Vq and Vq , Vq1 , ..., Vp & Ri are
satisfied.
You start the travel in human form, transform yourself from human form to wolf form at
the vertex Vq , and finish the travel in wolf form.
Your task is to determine whether it is possible to travel from the vertex Si to the vertex Ei .
Subtasks and Solutions
Subtask 1 (7 points)
N & 100, M & 200, Q & 100
You choose a V vertex where you transform yourself from human form to wolf form.
For each choice of V , you need to decide whether it is possible to travel from Si to V in human
form (i.e. only using vertices whose indices are ' Li ), and to decide whether it is possible to travel
from V to Ei in wolf form (i.e. only using vertices whose indices are & Ri ).
The time complexity of this solution is O QN N M .
Subtask 2 (8 points)
N & 3 000, M & 6 000, Q & 3 000
Determine the set of vertices you can visit from Si in human form, and determine the set of
vertices you can visit from Ei in wolf form.
Then check whether these two sets intersect.
The time complexity of this solution is O Q N M .
Subtask 3 (34 points)
The cities are located on a line. In other words, M N 1 and no city is directly connected
to more than 2 cities.
Let Ui be the set of the vertices which are reachable from Si by passing only vertices with
index at least Li . Similarly, let Vi be the set of the vertices which are reachable from Ei by passing
only vertices with index at most Ri . Note that Ui forms a range on the line on which cities are
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 154
located. This range can be efficiently computed using doubling or segment tree. Vi can be similarly
computed. Then, we can answer the query by checking whether these two ranges interesect.
Subtask 4 (51 points)
No additional constraints
We can construct a rooted tree so that Ui forms a subtree. This can be done using adding
vertices to a disjoint set union structure in the descending order of indices.
Then, using Euler-Tour on this tree, we can obtain a sequence of vertices and every Ui corre-
sponds to a contiguous segment of this sequence. We can compute similar sequence for Vi . Then,
we can answer the query by checking whether two segments for Ui and Vi shares a vertex. This
can be done by the sweep line algorithm with a segment tree. The time complexity of this solution
is O Q M log N .
TASK=werewolf
std::vector<int> check_validity(int N,
std::vector<int> X, std::vector<int> Y,
std::vector<int> S, std::vector<int> E,
std::vector<int> L, std::vector<int> R);
std::vector<int> check_validity(int N,
std::vector<int> X, std::vector<int> Y,
std::vector<int> S, std::vector<int> E,
std::vector<int> L, std::vector<int> R)
{
int Q = S.size();
std::vector<int> A(Q);
for (int i = 0; i < Q; ++i)
{
A[i] = 0;
}
return A;
}
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 155
}
return x;
}
} // namespace
int main()
{
int N = read_int();
int M = read_int();
int Q = read_int();
std::vector<int> X(M), Y(M), S(Q), E(Q), L(Q), R(Q);
#include "werewolf.h"
#include <bits/stdc++.h>
int find(int x)
{
return x==r[x]?x:(r[x]=find(r[x]));
}
adj2[p[i]].push_back(j);
}
for(array<int, 2> c : b[p[i]])
anc[c[1]]=find(c[0]);
b[p[i]].clear();
d[p[i]]=1;
}
dfs(p[n-1], st, en);
}
int qry(int i)
{
int r=0;
for(; i; i-=i&-i)
r+=ft[i];
return r;
}
}
} // namespace
int main()
{
auto t1 = clock();
int N = read_int();
int M = read_int();
int Q = read_int();
std::vector<int> X(M), Y(M), S(Q), E(Q), L(Q), R(Q);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
fclose(stdout);
return 0;
}
//======================================================================
/*
t2-t1 = 2.685
t3-t2 = 1.384
t4-t3 = 0.071
int n, m, q;
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 158
vector<int> edge[200000];
struct UF
{
int par[200000];
UF()
{
for (int i = 0; i < 200000; ++i) par[i] = i;
}
int find(int x)
{
if (par[x] != x) return par[x] = find(par[x]);
return x;
}
} Luf, Ruf;
int Lpar[200000][20];
int Rpar[200000][20];
vector<int> Lchild[200000];
vector<int> Rchild[200000];
int Lst[200000];
int Led[200000];
int Rst[200000];
int Red[200000];
int LRd[200000];
void dfs(vector<int> child[], int st[], int ed[], int x, int &d)
{
st[x] = ++d;
for (int i : child[x])
{
dfs(child, st, ed, i, d);
}
ed[x] = d;
}
struct query
{
int i, t, x;
query(int i, int t, int x) : i(i), t(t), x(x) {}
bool operator<(const query &p) const
{
return t < p.t;
}
};
int seg[200001];
void update(int i)
{
while (i <= n)
{
++seg[i];
i += i & -i;
}
}
int sum(int i)
{
int ret = 0;
while (i)
{
ret += seg[i];
i -= i & -i;
}
return ret;
}
{
edge[U[i]].push_back(V[i]);
edge[V[i]].push_back(U[i]);
}
for (int i = 0; i < n; ++i) Lpar[i][0] = 0;
for (int i = n; i--; )
{
for (int j : edge[i])
{
if (j < i) continue;
int x = Luf.find(i);
int y = Luf.find(j);
if (x == y) continue;
Luf.par[y] = x;
Lpar[y][0] = x;
Lchild[x].push_back(y);
}
}
int ord;
ord = 0;
dfs(Lchild, Lst, Led, Luf.find(0), ord);
ord = 0;
dfs(Rchild, Rst, Red, Ruf.find(0), ord);
for (int i = 0; i < n; ++i) LRd[Lst[i] - 1] = Rst[i];
vector<query> qs;
for (int it = 0; it < q; ++it)
{
int x = X[it];
int y = Y[it];
int l = L[it];
int r = R[it];
for (int i = 20; i--; ) if (l <= Lpar[x][i]) x = Lpar[x][i];
for (int i = 20; i--; ) if (Rpar[y][i] <= r) y = Rpar[y][i];
qs.emplace_back(˜it, Lst[x] - 1, y);
qs.emplace_back(it, Led[x], y);
}
sort(qs.begin(), qs.end());
vector<int> ret(q, 0);
ord = 0;
for (query i : qs)
{
while (ord < i.t) update(LRd[ord++]);
int v = sum(Red[i.x]) - sum(Rst[i.x] - 1);
if (i.i < 0) ret[˜i.i] -= v;
else ret[i.i] += v;
}
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int N = read_int();
int M = read_int();
int Q = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.765
t3-t2 = 2.094
t4-t3 = 0.063
struct seg
{
int tree[MAXT], lim;
void init(int n)
{
fill(tree, tree + MAXT, -1e9);
for(lim = 1; lim <= n; lim <<= 1);
}
struct disj
{
int pa[MAXN];
void init(int n)
{
iota(pa, pa + n + 1, 0);
}
int find(int x)
{
return pa[x] = (pa[x] == x ? x : find(pa[x]));
}
struct graph
{
vector<int> gph[MAXN];
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 162
void dfs(int x)
{
din[x] = piv;
if(gph[x].empty()) piv++;
for(auto &i : gph[x]) dfs(i);
dout[x] = piv;
}
} g1, g2;
struct queries
{
int s, l, e, r;
int rs, re, idx;
} qr[MAXN];
struct edges
{
int s, e, x;
} ed[MAXN];
std::vector<int> check_validity(int N,
std::vector<int> X, std::vector<int> Y,
std::vector<int> S, std::vector<int> E,
std::vector<int> L, std::vector<int> R)
{
int M = X.size();
int Q = S.size();
for(int i=0; i<Q; i++)
qr[i] = {S[i], L[i], E[i], R[i], -1, -1, i};
// both done
g1.dfs(2 * N - 2);
g2.dfs(2 * N - 2);
vector<pi> points;
vector<int> ans(Q);
sort(points.begin(), points.end());
seg.init(N);
ptr = 0;
for(int i=0; i<Q; i++)
{
while(ptr < N && points[ptr].first < g1.dout[qr[i].rs])
{
seg.add(points[ptr].second, points[ptr].first);
ptr++;
}
return ans;
}
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 164
{
auto t1 = clock();
int N = read_int();
int M = read_int();
int Q = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.797
t3-t2 = 2.411
t4-t3 = 0.063
int find(int x)
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 165
{
return x==r[x]?x:(r[x]=find(r[x]));
}
int qry(int i)
{
int r=0;
for(; i; i-=i&-i)
r+=ft[i];
return r;
}
q=s.size();
for(int i=0; i<n; ++i)
p[i]=n-1-i;
for(int i=0; i<q; ++i)
b[l[i]].push_back({s[i], i});
memset(d, 0, n);
dt=0;
for(int i=0; i<q; ++i)
b[r[i]].push_back({e[i], i});
{
b[st[0][anc[0][i]]].push_back({i, -1});
b[en[0][anc[0][i]]].push_back({i, 1});
}
vector<int> ans=vector<int>(q);
for(int i=0; i<n; ++i)
{
for(int j=ta[i]+1; j<=n; j+=j&-j)
++ft[j];
for(array<int, 2> c : b[i+1])
ans[c[0]]+=c[1]*
(qry(en[1][anc[1][c[0]]])-qry(st[1][anc[1][c[0]]]));
}
return ans;
}
//-------------- start grader ------------------
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int N = read_int();
int M = read_int();
int Q = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 167
return 0;
}
/*
t2-t1 = 0.781
t3-t2 = 1.344
t4-t3 = 0.062
#define Fi first
#define Se second
#define pb(x) push_back(x)
#define szz(x) (int)x.size()
#define rep(i,n) for(int i=0;i<n;i++)
#define all(x) x.begin(),x.end()
struct tree
{
vector <int> F[200020];
int lv[200020], rv[200020], cs = 0;
int up[200020][18];
void dfs(int x)
{
lv[x] = ++cs;
for(int e : F[x])
{
up[e][0] = x;
for(int i=1;i<18;i++)
{
up[e][i] = up[ up[e][i-1] ][i-1];
}
dfs(e);
}
rv[x] = cs;
}
int pp[200020];
int Find(int x)
{
return pp[x] == x ? x : pp[x] = Find(pp[x]);
}
int val[200020];
vector <int> EE[200010];
int N;
T[0].dfs(N); T[1].dfs(1);
for(int i=1;i<=N;i++)
{
val[T[0].lv[i]] = T[1].lv[i];
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 169
int Q = szz(S);
rep(i, Q)
{
++S[i]; ++E[i]; ++L[i]; ++R[i];
pre_query(i, S[i], E[i], L[i], R[i]);
}
for(int i=1;i<=N;i++)
{
int x = val[i];
for(int j=x;j<200020;j+=(j&-j)) TT[j]++;
for(t3 e : pquery[i])
{
int y, idx, cc;
tie(y, idx, cc) = e;
int s = 0;
for(int j=y;j;j-=(j&-j)) s += TT[j];
cnt[idx] += cc * s;
}
}
return A;
}
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int N = read_int();
int M = read_int();
int Q = read_int();
fclose(stdin);
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 170
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.75
t3-t2 = 2.159
t4-t3 = 0.063
#define y0 ___y0
#define y1 ___y1
#define MP make_pair
#define MT make_tuple
#define PB push_back
#define PF push_front
#define fi first
#define se second
#define debug(x) cerr << #x << " = " << x << endl;
#define SZ(x) ((int) (x.size()))
int N, Q, T;
vector<int> edge[MAXN];
ppp quer[MAXN];
ppp range[MAXN];
vi ans;
int parent[2][MAXN];
int ord[2][MAXN];
int ancestor[2][20][MAXN];
int st[2][MAXN], ft[2][MAXN];
int pos[MAXN], arr[MAXN];
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 171
vector<int> edge1[2][MAXN];
struct dsu
{
int dsu[MAXN];
bool flag;
int get(int u)
{
return ((u == dsu[u]) ? u : dsu[u] = get(dsu[u]));
}
int fen[MAXN];
vector<ppp> queries[MAXN];
dsu d[2];
vi check_validity(int n, vi X, vi Y, vi s, vi e, vi l, vi r)
{
N = n;
d[0].flag = true;
for (int i = 0; i < N; i++)
{
d[0].dsu[i] = i;
d[1].dsu[i] = i;
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 172
parent[0][i] = N;
parent[1][i] = N;
}
Q = SZ(s);
ans.resize(Q);
for (int i = 0; i < Q; i++)
{
swap(s[i], e[i]);
quer[i] = MP(MP(l[i], r[i]), MP(s[i], e[i]));
}
// cerr << "starts at " << i << " goes to " << u << endl;
range[i].fi = MP(st[0][u], ft[0][u]);
u = quer[i].se.se;
for (int j = 19; j >= 0; j--)
{
if (ancestor[1][j][u] < quer[i].fi.fi ||
ancestor[1][j][u] == N) continue;
u = ancestor[1][j][u];
}
range[i].se = MP(st[1][u], ft[1][u]);
}
//idx, plusminus, l, r
//# of values between
CAPITOLUL 2. IOI 2018 2.3. WEREWOLF 174
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int N = read_int();
int M = read_int();
int Q = read_int();
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.843
t3-t2 = 2.047
t4-t3 = 0.063
O jucărie mecanică este o jucărie care repetă automat o secvenţă de mişcări. În Japonia multe
jucării mecanice au fost create ı̂ncă din vremuri antice.
Mişcările unei jucării mecanice sunt controlate de un circuit, constituit din dispozitive. Dis-
pozitivele sunt conectate prin tuburi. Fiecare dispozitiv are una sau două ieşiri şi un număr arbi-
trar (posibil zero) de intrări. Fiecare tub conectează ieşirea unui dispozitiv cu intrarea aceluiaşi
sau altui dispozitiv. Exact un tub este conectat cu fiecare intrare şi exact un tub este conectat cu
fiecare ieşire.
Pentru a descrie mişcările produse de jucărie, consideraţi o bilă plasată ı̂ntr-unul din dispozi-
tive. Bila se mişcă prin circuit. La fiecare moment al traseului acesteia, bila, părăseşte dispozitivul
folosind una din ieşiri, traversează tubul conectat de ieşire şi intră ı̂n dispozitivul de la capătul
celălalt al tubului.
Există trei tipuri de dispozitive: origine, ı̂ntrerupător şi comutator. Există exact o origine,
M ı̂ntrerupătoare şi S comutatoare (S poate fi zero). Voi trebuie să decideţi valoarea lui S. Fiecare
dispozitiv are un cod unic de ı̂nregistrare.
Originea este dispozitivul unde bila se află iniţial. Are exact o ieşire. Codul ei unic de
ı̂nregistrare este 0.
Un ı̂ntrerupător face bila să execute o mişcare specială de fiecare dată când bila intră ı̂n acesta.
Orice ı̂ntrerupător are exact o ieşire. Codurile unice de ı̂nregistrare ale ı̂ntrerupătoarelor sunt de
la 1 la M .
¬ ¬ ¬ ¬ ¬ ¬
Fiecare comutator are două ieşiri, denumite X şi Y . Starea unui comutator este fie X ,
¬ ¬
fie Y . După ce bila intră ı̂ntr-un comutator ı̂l părăseşte prin ieşirea dată de starea curentă a
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 176
¬ ¬
acestuia. După aceea, starea comutatorului se schimbă. Iniţial starea fiecărui comutator este X .
Codurile unice de ı̂nregistrare ale comutatoarelor sunt de la 1 la S.
Detalii de implementare
Dacă vreuna din condiţiile de mai sus nu este satisfăcută programul vostru va fi evaluat ca
Wrong answer. Altfel, programul vostru va fi evaluat ca Accepted, iar punctajul vostru va fi
calculat pe baza lui S (vedeţi Subtask-uri).
Exemple
¬ ¬
a Când bila intră prima oară ı̂n comutatorul 1 starea acestuia este X . Deci, bila va traversa
¬ ¬
câtre ı̂ntrerupătorul 2. Apoi, starea comutatorului 1 devine Y .
¬ ¬
a Când bila intră ı̂n comutatorul 1 pentru a doua oară starea acestuia este Y . Deci bila va
¬ ¬
traversa câtre ı̂ntrerupătorul 3. Apoi, starea comutatorului 1 devine X .
Când bila revine prima oară ı̂n origine aceasta a trecut prin ı̂ntrerupătoarele 1, 2, 1, 3. Starea
¬ ¬
comutatoarelor 1 şi 2 este X . Valoarea lui P este 4. Deci circuitul satisface condiţiile.
Fişierul sample-01-in.txt din pachetul arhivat ataşat corespunde acestui exemplu. Alte
exemple se găsesc ı̂n acest pachet.
Restricţii
Subtaskuri
Punctajele şi restricţiile pentru fiecare test sunt după cum urmează:
1. (2 puncte) Pentru fiecare i (1 & i & M ) numărul i apare cel mult o dată ı̂n secvenţa
A0 , A1 , ..., AN 1 .
2. (4 puncte) Pentru fiecare (1 & i & M ) numărul apare de cel mult de două ori ı̂n secvenţa
A0 , A1 , ..., AN 1 .
3. (10 puncte) Pentru fiecare i (1 & i & M ) numărul apare de cel mult patru ori ı̂n secvenţa
A0 , A1 , ..., AN 1 .
4. (10 puncte) N 16
5. (18 puncte) M 1
6. (56 puncte) Fără constrângeri adiţionale.
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 178
Pentru fiecare test, dacă programul vostru este evaluat ca Accepted, punctajul vostru este
calculat pe baza lui S:
a Dacă S & N log2 N veţi primi punctajul complet pentru acel test.
a Pentru fiecare test din subtask-urile 5 şi 6, dacă N log2 N $ S & 2N veţi primi un punctaj
parţial. Punctajul pentru acest test este 0.5 0.4 N2N S 2 multiplicat cu punctajul asociat
log2 N
subtask-ului.
a Altfel punctajul este 0.
Luaţi la cunoştinţă că punctajul pentru fiecare subtask este minimul punctajelor pentru fiecare
test din acel subtask.
Exemplu de grader
Grader-ul local citeşte datele de intrare de la intrarea standard ı̂n următoarea formă.
linia 1: M N
linia 2: A0 , A1 ,..., AN 1
Grader-ul local produce trei ieşiri.
Mai ı̂ntâi grader-ul local va afişa răspunsul vostru ı̂ntr-un fişier numit out.txt ı̂n următoarea
formă.
linia 1: S
linia 2 i (0 & i & M ): C i
linia 2 M j (1 & j & S): X j 1 Y j 1
Apoi, grader-ul local va simula mişcarea bilei. Va afişa codurile unice de ı̂nregistrare ale
dispozitivelor prin care trece bila ı̂n fişierul log.txt.
În sfârşit, grader-ul local va afişa evaluarea răspunsului vostru la ieşirea standard.
a Dacă programul vostru este evaluat ca Accepted grader-ul local va afişa S şi P ı̂n următoarea
formă Accepted: S P .
a Dacă programul vostru este evaluat ca Wrong Answer, grader-ul local va afişa
Wrong answer: M SG. Semnificaţia lui M SG este după cum urmează:
` answered not exactly once: Procedura answer nu a fost apelată exact o dată.
` wrong array length: Dimensiunea tabloului C nu este , sau dimensiunile lui X şi Y
sunt diferite.
` over 400000 switches: este mai mare decât.
` wrong serial number: Există cel puţin un element ı̂n ’C’, ’X’ sau ’Y’ care este mai
mic decât sau mai mare decât.
` over 20000000 inversions: Bila nu a revenit la origine ı̂n de schimbări de stare
ale comutatoarelor.
` state ’Y’: Există un comutator al cărui stare este ’Y’ când bila revine prima oară ı̂n
origine.
` wrong motion: ı̂ntrerupătoarele care determină mişcarea bilei sunt diferite de cele din
secvenţa.
Luaţi la cunoştinţă că grader-ul local nu creează out.txt şi/sau log.txt atunci când pro-
gramul vostru este evaluat ca Wrong Answer.
The score is determined according to the number of switches. Contestants get the full score
when N log2 N switches or less are used.
Subtask 2 (4 points)
Each trigger appears in A at most twice. N log2 N switches can be used.
Put a switch after each trigger which appears twice.
TASK=doll
namespace
{
int M, N;
std::vector<int> A;
bool answered;
int S;
std::vector<int> IC, IX, IY;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
void simulate()
{
if (S > S_MAX)
{
char str[50];
sprintf(str, "over %d switches", S_MAX);
wrong_answer(str);
}
for (int i = 0; i <= M; ++i)
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 181
{
if (!(-S <= IC[i] && IC[i] <= M))
{
wrong_answer("wrong serial number");
}
}
for (int j = 1; j <= S; ++j)
{
if (!(-S <= IX[j - 1] && IX[j - 1] <= M))
{
wrong_answer("wrong serial number");
}
if (!(-S <= IY[j - 1] && IY[j - 1] <= M))
{
wrong_answer("wrong serial number");
}
}
int P = 0;
std::vector<bool> state(S + 1, false);
int pos = IC[0];
int k = 0;
FILE *file_log = fopen("log.txt", "w");
fprintf(file_log, "0\n");
for (;;)
{
fprintf(file_log, "%d\n", pos);
if (pos < 0)
{
if (++P > P_MAX)
{
fclose(file_log);
char str[50];
sprintf(str, "over %d inversions", P_MAX);
wrong_answer(str);
}
state[-pos] = !state[-pos];
pos = state[-pos] ? IX[-(1 + pos)] : IY[-(1 + pos)];
}
else
{
if (pos == 0)
{
break;
}
if (k >= N)
{
fclose(file_log);
wrong_answer("wrong motion");
}
if (pos != A[k++])
{
fclose(file_log);
wrong_answer("wrong motion");
}
pos = IC[pos];
}
}
fclose(file_log);
if (k != N)
{
wrong_answer("wrong motion");
}
for (int j = 1; j <= S; ++j)
{
if (state[j])
{
wrong_answer("state ’Y’");
}
}
printf("Accepted: %d %d\n", S, P);
}
} // namespace
{
if (answered)
{
wrong_answer("answered not exactly once");
}
answered = true;
// check if input format is correct
if ((int)C.size() != M + 1)
{
wrong_answer("wrong array length");
}
if (X.size() != Y.size())
{
wrong_answer("wrong array length");
}
S = X.size();
IC = C;
IX = X;
IY = Y;
}
int main()
{
M = read_int();
N = read_int();
A.resize(N);
for (int k = 0; k < N; ++k)
{
A[k] = read_int();
}
answered = false;
create_circuit(M, A);
if (!answered)
{
wrong_answer("answered not exactly once");
}
FILE *file_out = fopen("out.txt", "w");
fprintf(file_out, "%d\n", S);
for (int i = 0; i <= M; ++i)
{
fprintf(file_out, "%d\n", IC[i]);
}
for (int j = 1; j <= S; ++j)
{
fprintf(file_out, "%d %d\n", IX[j - 1], IY[j - 1]);
}
fclose(file_out);
simulate();
return 0;
}
#include<fstream>
#include<iostream>
//#include <ctime>
#include <time.h> /* clock */
//#include <cstdio>
#include <stdio.h> // citire mai rapida !!!
#include <cstdio>
#include <cstdlib>
#include "doll.h"
int n;
int seg[1 << 19];
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 183
int SN = 0;
vector<int> X, Y;
for (int i = sz; --i; )
{
if (seg[i << 1] == seg[i << 1 | 1])
{
seg[i] = seg[i << 1];
continue;
}
int S = SN++;
seg[i] = -(S + 1);
X.push_back(seg[i << 1]);
Y.push_back(seg[i << 1 | 1]);
}
namespace
{
int M, N;
std::vector<int> A;
bool answered;
int S;
std::vector<int> IC, IX, IY;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 184
void simulate()
{
if (S > S_MAX)
{
char str[50];
sprintf(str, "over %d switches", S_MAX);
wrong_answer(str);
}
int P = 0;
std::vector<bool> state(S + 1, false);
int pos = IC[0];
int k = 0;
for (;;)
{
fprintf(file_log, "%d\n", pos);
if (pos < 0)
{
if (++P > P_MAX)
{
fclose(file_log);
char str[50];
sprintf(str, "over %d inversions", P_MAX);
wrong_answer(str);
}
state[-pos] = !state[-pos];
pos = state[-pos] ? IX[-(1 + pos)] : IY[-(1 + pos)];
}
else
{
if (pos == 0)
{
break;
}
if (k >= N)
{
fclose(file_log);
wrong_answer("wrong motion");
}
if (pos != A[k++])
{
fclose(file_log);
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 185
wrong_answer("wrong motion");
}
pos = IC[pos];
}
}
fclose(file_log);
if (k != N)
{
wrong_answer("wrong motion");
}
answered = true;
// check if input format is correct
if ((int)C.size() != M + 1)
{
wrong_answer("wrong array length");
}
if (X.size() != Y.size())
{
wrong_answer("wrong array length");
}
S = X.size();
IC = C;
IX = X;
IY = Y;
}
int main()
{
std::freopen("../in/03-04.txt", "r", stdin);
//std::freopen("doll.out", "w", stdout);
auto t1 = clock();
M = read_int();
N = read_int();
A.resize(N);
for (int k = 0; k < N; ++k)
{
A[k] = read_int();
}
fclose(stdin);
auto t2 = clock();
answered = false;
create_circuit(M, A);
if (!answered)
{
wrong_answer("answered not exactly once");
}
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 186
auto t3 = clock();
fclose(file_out);
auto t4 = clock();
simulate();
auto t5 = clock();
return 0;
}
//-------------- end grader ------------------
/*
Accepted: 200006 3836160
t2-t1 = 0.328
t3-t2 = 0.078
t4-t3 = 0.359
t5-t4 = 3.896
#include <bits/stdc++.h>
#include "doll.h"
{
X[cur_vtx] = -vtx_number - 1;
dfs(s, m, v, d + 1);
}
Y[cur_vtx] = -vtx_number - 1;
dfs(m+1, e, v ˆ (1 << d), d + 1);
}
int ptr = 0;
for(int i=0; i<(1<<K); i++)
{
if(mp[i])
{
mp[i] = A[ptr++];
}
}
namespace
{
constexpr int P_MAX = 20000000;
constexpr int S_MAX = 400000;
int M, N;
std::vector<int> A;
bool answered;
int S;
std::vector<int> IC, IX, IY;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 188
return x;
}
void simulate()
{
if (S > S_MAX)
{
char str[50];
sprintf(str, "over %d switches", S_MAX);
wrong_answer(str);
}
int P = 0;
std::vector<bool> state(S + 1, false);
int pos = IC[0];
int k = 0;
for (;;)
{
fprintf(file_log, "%d\n", pos);
if (pos < 0)
{
if (++P > P_MAX)
{
fclose(file_log);
char str[50];
sprintf(str, "over %d inversions", P_MAX);
wrong_answer(str);
}
state[-pos] = !state[-pos];
pos = state[-pos] ? IX[-(1 + pos)] : IY[-(1 + pos)];
}
else
{
if (pos == 0)
{
break;
}
if (k >= N)
{
fclose(file_log);
wrong_answer("wrong motion");
}
if (pos != A[k++])
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 189
{
fclose(file_log);
wrong_answer("wrong motion");
}
pos = IC[pos];
}
}
fclose(file_log);
if (k != N)
{
wrong_answer("wrong motion");
}
answered = true;
// check if input format is correct
if ((int)C.size() != M + 1)
{
wrong_answer("wrong array length");
}
if (X.size() != Y.size())
{
wrong_answer("wrong array length");
}
S = X.size();
IC = C;
IX = X;
IY = Y;
}
int main()
{
std::freopen("../in/03-04.txt", "r", stdin);
//std::freopen("doll.out", "w", stdout);
auto t1 = clock();
M = read_int();
N = read_int();
A.resize(N);
for (int k = 0; k < N; ++k)
{
A[k] = read_int();
}
fclose(stdin);
auto t2 = clock();
answered = false;
create_circuit(M, A);
if (!answered)
{
wrong_answer("answered not exactly once");
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 190
auto t3 = clock();
fclose(file_out);
auto t4 = clock();
simulate();
auto t5 = clock();
return 0;
}
//-------------- end grader ------------------
/*
Accepted: 200006 3836160
t2-t1 = 0.359
t3-t2 = 0.016
t4-t3 = 0.328
t5-t4 = 3.714
#include<fstream>
#include<iostream>
//#include <ctime>
#include <time.h> /* clock */
//#include <cstdio>
#include <stdio.h> // citire mai rapida !!!
#include <cstdio>
#include <cstdlib>
#include "doll.h"
#include <queue>
int sw[(int)4e5][2];
int trig[(int)2e5];
int N = A.size();
int lgN = 0;
while((1 << lgN) <= N)
{
lgN++;
}
lgN--;
sw[lgN + 1][1] = 0;
if(N & 1)
{
sw[lgN + 1][0] = 0;
}
else
{
sw[lgN + 1][0] = -1;
}
while(!switches.empty())
{
int s = switches.front().first;
int lvl = switches.front().second;
switches.pop();
if(lvl != 0)
{
sw[-s][0] = --last_switch;
switches.push({last_switch,lvl - 1});
sw[-s][1] = --last_switch;
switches.push({last_switch,lvl - 1});
}
else
{
sw[-s][0] = sw[-s][1] = 0;
}
}
int ind = 0;
int node = -1;
while(node != 0)
{
if(sw[-node][0] == 0)
{
if(ind == A.size())
{
swap(sw[-node][0],sw[-node][1]);
node = 0;
continue;
}
sw[-node][0] = A[ind++];
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 192
swap(sw[-node][0],sw[-node][1]);
node = -1;
}
else
{
swap(sw[-node][0],sw[-node][1]);
node = sw[-node][1];
}
}
answer(C,X,Y);
}
//-------------- start grader ------------------
namespace
{
int M, N;
std::vector<int> A;
bool answered;
int S;
std::vector<int> IC, IX, IY;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
void simulate()
{
if (S > S_MAX)
{
char str[50];
sprintf(str, "over %d switches", S_MAX);
wrong_answer(str);
}
int P = 0;
std::vector<bool> state(S + 1, false);
int pos = IC[0];
int k = 0;
for (;;)
{
fprintf(file_log, "%d\n", pos);
if (pos < 0)
{
if (++P > P_MAX)
{
fclose(file_log);
char str[50];
sprintf(str, "over %d inversions", P_MAX);
wrong_answer(str);
}
state[-pos] = !state[-pos];
pos = state[-pos] ? IX[-(1 + pos)] : IY[-(1 + pos)];
}
else
{
if (pos == 0)
{
break;
}
if (k >= N)
{
fclose(file_log);
wrong_answer("wrong motion");
}
if (pos != A[k++])
{
fclose(file_log);
wrong_answer("wrong motion");
}
pos = IC[pos];
}
}
fclose(file_log);
if (k != N)
{
wrong_answer("wrong motion");
}
} // namespace
answered = true;
// check if input format is correct
if ((int)C.size() != M + 1)
{
wrong_answer("wrong array length");
}
if (X.size() != Y.size())
{
wrong_answer("wrong array length");
}
S = X.size();
IC = C;
IX = X;
IY = Y;
}
int main()
{
std::freopen("../in/03-04.txt", "r", stdin);
//std::freopen("doll.out", "w", stdout);
auto t1 = clock();
M = read_int();
N = read_int();
A.resize(N);
for (int k = 0; k < N; ++k)
{
A[k] = read_int();
}
fclose(stdin);
auto t2 = clock();
answered = false;
create_circuit(M, A);
if (!answered)
{
wrong_answer("answered not exactly once");
}
auto t3 = clock();
fclose(file_out);
auto t4 = clock();
simulate();
auto t5 = clock();
return 0;
}
//-------------- end grader ------------------
/*
Accepted: 200006 3836160
t2-t1 = 0.406
t3-t2 = 0.219
t4-t3 = 0.296
t5-t4 = 3.227
#include <bits/stdc++.h>
#include "doll.h"
int lastid;
vector<int> X, Y;
vector<pair<int, pair<bool, int> > > poz;
int dfs(int depth, int N, int p, bool branch, int papa, int bit = 0)
{
if(depth >= 0)
{
int id = -((int)X.size()) - 1;
X.push_back(0);
Y.push_back(0);
if((1 << depth) > N)
{
X[-id - 1] = -1;
int r1 = dfs(depth - 1, N, p | (1 << bit), 1, id, bit + 1);
Y[-id - 1] = r1;
}
else
{
int r1 = dfs(depth - 1, (1 << depth), p, 0, id, bit + 1);
int r2 = dfs(depth - 1, N ˆ (1 << depth), p | (1 << bit), 1, id, bit +
1);
X[-id - 1] = r1;
Y[-id - 1] = r2;
}
return id;
}
else
{
if((1 << bit) - 1 == p)
{
return 0;
}
else
if(N == 0)
{
return -1;
}
else
{
poz.push_back(make_pair(p, make_pair(branch, papa)));
return 2;
}
}
}
CAPITOLUL 2. IOI 2018 2.4. MECHANICAL DOLL 196
int maxlg = 0;
int N = A.size();
while((1 << maxlg) <= N)
++maxlg;
lastid = -maxlg;
dfs(maxlg - 1, N, 0, 0, 0);
sort(poz.begin(), poz.end());
answer(C, X, Y);
}
namespace
{
int M, N;
std::vector<int> A;
bool answered;
int S;
std::vector<int> IC, IX, IY;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
void simulate()
{
if (S > S_MAX)
{
char str[50];
sprintf(str, "over %d switches", S_MAX);
wrong_answer(str);
}
{
if (!(-S <= IX[j - 1] && IX[j - 1] <= M))
{
wrong_answer("wrong serial number");
}
if (!(-S <= IY[j - 1] && IY[j - 1] <= M))
{
wrong_answer("wrong serial number");
}
}
int P = 0;
std::vector<bool> state(S + 1, false);
int pos = IC[0];
int k = 0;
for (;;)
{
fprintf(file_log, "%d\n", pos);
if (pos < 0)
{
if (++P > P_MAX)
{
fclose(file_log);
char str[50];
sprintf(str, "over %d inversions", P_MAX);
wrong_answer(str);
}
state[-pos] = !state[-pos];
pos = state[-pos] ? IX[-(1 + pos)] : IY[-(1 + pos)];
}
else
{
if (pos == 0)
{
break;
}
if (k >= N)
{
fclose(file_log);
wrong_answer("wrong motion");
}
if (pos != A[k++])
{
fclose(file_log);
wrong_answer("wrong motion");
}
pos = IC[pos];
}
}
fclose(file_log);
if (k != N)
{
wrong_answer("wrong motion");
}
answered = true;
// check if input format is correct
if ((int)C.size() != M + 1)
{
wrong_answer("wrong array length");
}
if (X.size() != Y.size())
{
wrong_answer("wrong array length");
}
S = X.size();
IC = C;
IX = X;
IY = Y;
}
int main()
{
std::freopen("../in/03-04.txt", "r", stdin);
//std::freopen("doll.out", "w", stdout);
auto t1 = clock();
M = read_int();
N = read_int();
A.resize(N);
for (int k = 0; k < N; ++k)
{
A[k] = read_int();
}
fclose(stdin);
auto t2 = clock();
answered = false;
create_circuit(M, A);
if (!answered)
{
wrong_answer("answered not exactly once");
}
auto t3 = clock();
fclose(file_out);
auto t4 = clock();
simulate();
auto t5 = clock();
return 0;
}
//-------------- end grader ------------------
/*
Accepted: 200006 3836160
t2-t1 = 0.343
t3-t2 = 0.36
t4-t3 = 0.312
t5-t4 = 3.656
În Japonia, oraşele sunt conectate de o reţea de autostrăzi. Reţeaua este formată din N oraşe
şi M autostrăzi. Fiecare autostradă conectează o pereche de oraşe distincte. Nu există două
autostrăzi distincte care conectează aceeaşi pereche de oraşe. Oraşele sunt numerotate de la 0 la
N 1 şi autostrăzile sunt numerotate de la 0 la M 1. Puteţi conduce pe oricare autostradă ı̂n
ambele direcţii. Puteţi călători, folosind autostrăzile, ı̂ntre oricare două oraşe.
O taxă este percepută pentru conducerea pe fiecare din autostrăzi. Taxa pe autostradă depinde
de condiţiile de trafic. Traficul poate fi relaxat sau intens. Când traficul este relaxat taxa este
de A yen (valută japoneză). Când traficul este intens taxa este de B yen. Se garantează că A $ B.
Luaţi la cunoştinţă că valorile A şi B sunt cunoscute.
Aveţi un dispozitiv, care, pentru condiţii date ale traficului pe toate autostrăzile calculează
taxa totală minimă pe care cineva trebuie să o achitate pentru a călători ı̂ntre oraşele S şi T
(S j T ), ı̂n condiţii de trafic specificate.
Totuşi, dispozitivul este doar un prototip. Valorile S şi T sunt fixate (adică ı̂n echipament)
şi necunoscute. Trebuie să determinaţi valorile S şi T . Pentru a realiza aceasta, planificaţi să
specificaţi dispozitivului anumite condiţii de trafic şi să folosiţi valorile taxelor calculate de acesta
pentru a deduce S şi T . Deoarece specificarea condiţiilor de trafic costă, nu doriţi să folosiţi
dispozitivul de multe ori.
Detalii de implementare
a Pentru fiecare i (0 & i & M 1), w i descrie condiţiile de trafic pe autostrada i. Valoarea
wi trebuie să fie 0 sau 1.
` w[i] = 0 ı̂nseamnă că traficul pe autostrada i este relaxat.
` w[i] = 1 ı̂nseamnă că traficul pe autostrada i este intens.
a Această funcţie ı̂ntoarce taxa totală minimă pentru călătoria ı̂ntre oraşele S şi T , ı̂n condiţiile
de trafic specificate de w.
a Această funcţie poate fi apelată de cel mult 100 de ori (pentru fiecare test).
Exemple
În figura de mai sus, muchia cu numărul i corespunde autostrăzii i. Unele apeluri posibile
către ask şi valorile corespunzătoare ı̂ntoarse sunt descrise mai jos:
La apelul funcţiei ask([0, 0, 0, 0]), traficul pe fiecare autostradă este relaxat şi taxa de
autostradă este 1. Ruta de cost minim de la S 1 la T 3 este 1 0 3.
Taxa totală pentru această rută este 2. Astfel, funcţia ı̂ntoarce 2.
Pentru un răspuns corect, procedura find_pair ar trebui să apeleze answer(1, 3) sau
answer(3, 1).
Fişierul sample-01-in.txt din pachetul arhivat anexat corespunde acestui exemplu.
Alte exemple sunt disponibile ı̂n acelaşi pachet.
Restricţii
CAPITOLUL 2. IOI 2018 2.5. HIGHWAY TOLLS 201
Subtaskuri
Exemplu de grader
We are given an undirected and unweighted graph G with N vertices and M edges, and constants
1 & A $ B.
Two vertices s and t are fixed but they are unknown to us.
We want to find s and t by calling the following function fewer times:
For each edge in G, you arbitrarily assign the weight of A or B to turn G into a weighted
graph. Then, the function returns the length of a shortest path between s and t on (weighted)
G.
Subtask 2 (7 points)
at most 60 function calls, G is a tree, s is known
Sort the vertices 0 by the distance from s. Then t can be found using binary search
Subtask 3 (6 points)
at most 60 function calls, G is a path
Binary search
Solution B: 31 points
Find an edge e on a shortest path between s and t as in Subtask 4.
et e uv. Without loss of generality, we can assume s, u, v and t appears in this order on
this shortest path.
CAPITOLUL 2. IOI 2018 2.5. HIGHWAY TOLLS 203
Then we can prove that s is strictly closer to u than to v. Similarly, t is closer to v than to
u.
Thus we have disjoint candidate sets S and T such that s and t are contained in S and T ,
respectively. At the same time, we can construct BFS trees of vertex sets S and T with
roots u and v, respectively. We can suppose a shortest path goes only through e and edges
in the BFS trees.
Now we can find s and t as in the last part of Subtask 4.
TASK=highway
namespace
{
constexpr int MAX_NUM_CALLS = 100;
constexpr long long INF = 1LL << 61;
int N, M, A, B, S, T;
std::vector<int> U, V;
std::vector<std::vector<std::pair<int, int>>> graph;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
if (current_dist[vv] > d + A)
{
current_dist[vv] = d + A;
qa.push(vv);
}
}
else
{
if (current_dist[vv] > d + B)
{
current_dist[vv] = d + B;
qb.push(vv);
}
}
}
}
}
return -1;
}
answered = true;
}
int main()
{
N = read_int();
M = read_int();
A = read_int();
B = read_int();
S = read_int();
T = read_int();
U.resize(M);
V.resize(M);
graph.assign(N, std::vector<std::pair<int, int>>());
answered = false;
wrong_pair = false;
num_calls = 0;
find_pair(N, U, V, A, B);
if (!answered)
{
wrong_answer("answered not exactly once");
}
if (wrong_pair)
{
wrong_answer("{s, t} is wrong");
}
printf("Accepted: %d\n", num_calls);
return 0;
}
// https://oj.uz/submission/74962
//#include <ctime>
#include <time.h> /* clock */
//#include <cstdio>
#include <stdio.h> // citire mai rapida !!!
#include<bits/stdc++.h>
#include "highway.h"
#define X first
#define Y second
int n, m, a, b, p;
ll def, dis[NN];
bool ban[NN], v1[NN], v2[NN];
queue<int> q;
ll query ()
{
vector<int> V;
for(int i=0;i<m;i++)
{
V.push_back(ban[edg[i].X] || ban[edg[i].Y]);
}
return ask(V);
}
int getpiv ()
{
int S = 0, E = (int)ord.size() - 1;
while(S<E)
{
int Z = (S+E)/2;
for(int i=0;i<=Z;i++)
{
ban[ord[i]] = true;
}
query() != def ? E = Z : S = Z+1;
for(int i=0;i<=Z;i++)
{
ban[ord[i]] = false;
}
}
return ord[S];
}
if(v2[C]) return;
v2[C] = true;
for(auto &T : dij[C])
{
dfs2(T);
}
}
void find_pair(int _N, vector<int> _U, vector<int> _V, int _A, int _B)
{
n = _N;
m = (int)_U.size();
a = _A;
b = _B;
for(int i=0;i<m;i++)
{
edg.push_back({_U[i]+1, _V[i]+1});
adj[_U[i]+1].push_back(_V[i]+1);
adj[_V[i]+1].push_back(_U[i]+1);
}
def = query();
for(int i=1;i<=n;i++)
{
ord.push_back(i);
}
p = getpiv();
ord.clear();
for(int i=1;i<p;i++)
{
ban[i] = true;
}
for(int i=1;i<=n;i++)
{
dis[i] = inf;
}
dis[p] = 0;
q.push(p);
while(!q.empty())
{
int C = q.front();
q.pop();
ord.push_back(C);
for(auto &T : adj[C])
{
if(T < p) continue;
if(dis[T] == inf)
{
dis[T] = dis[C] + 1;
q.push(T);
}
if(dis[T] == dis[C] - 1)
{
dij[T].push_back(C);
drv[C].push_back(T);
}
}
}
reverse(ord.begin(), ord.end());
int PA = getpiv();
ord.clear();
dfs1(PA);
for(int i=p;i<=n;i++)
{
if(v1[i]) dfs2(i);
}
for(int i=p;i<=n;i++)
{
if(!v2[i] && dis[i] + dis[PA] == def / a) ord.push_back(i);
}
int PB = getpiv();
ord.clear();
answer(PA-1, PB-1);
}
namespace
{
constexpr int MAX_NUM_CALLS = 100;
constexpr long long INF = 1LL << 61;
int N, M, A, B, S, T;
std::vector<int> U, V;
std::vector<std::vector<std::pair<int, int>>> graph;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
return d;
}
for (auto e : graph[v])
{
int vv = e.first;
int ei = e.second;
if (!visited[vv])
{
if (w[ei] == 0)
{
if (current_dist[vv] > d + A)
{
current_dist[vv] = d + A;
qa.push(vv);
}
}
else
{
if (current_dist[vv] > d + B)
{
current_dist[vv] = d + B;
qb.push(vv);
}
}
}
}
}
return -1;
}
answered = true;
}
int main()
{
auto t1 = clock();
N = read_int();
M = read_int();
A = read_int();
B = read_int();
S = read_int();
T = read_int();
U.resize(M);
V.resize(M);
auto t2 = clock();
answered = false;
wrong_pair = false;
CAPITOLUL 2. IOI 2018 2.5. HIGHWAY TOLLS 210
num_calls = 0;
find_pair(N, U, V, A, B);
auto t3 = clock();
if (!answered)
{
wrong_answer("answered not exactly once");
}
if (wrong_pair)
{
wrong_answer("{s, t} is wrong");
}
printf("Accepted: %d\n", num_calls);
auto t4 = clock();
fclose(stdout);
return 0;
}
/*
Accepted: 39
t2-t1 = 0.328
t3-t2 = 3.834
t4-t3 = 0
//#include <ctime>
#include <time.h> /* clock */
//#include <cstdio>
#include <stdio.h> // citire mai rapida !!!
#include <bits/stdc++.h>
#include "highway.h"
int dist[MAXN];
vector<int> gph[MAXN];
}
vector<int> v(M);
lint stdist = ask(v) / A;
int s = 0, e = M - 1;
while(s != e){
int m = (s + e) / 2;
fill(v.begin() + m + 1, v.end(), 0);
fill(v.begin(), v.begin() + m + 1, 1);
if(ask(v) != A * stdist) e = m;
else s = m + 1;
}
vector<int> bord[2], dist(N, 1e9);
queue<pi> que;
que.emplace(0, U[s]);
que.emplace(1, V[s]);
dist[U[s]] = dist[V[s]] = 0;
while(!que.empty()){
auto x = que.front(); que.pop();
bord[x.first].push_back(x.second);
for(auto &i : gph[x.second]){
if(dist[i] > dist[x.second] + 1){
dist[i] = dist[x.second] + 1;
que.emplace(x.first, i);
}
}
}
int S = -1, T = -1;
for(int i=0; i<2; i++){
s = 0, e = (int)bord[i].size() - 1;
while(s != e){
int m = (s + e + 1) / 2;
vector<int> C(bord[i].begin() + m, bord[i].end());
if(cut_ask(M, C, U, V) != stdist * A) s = m;
else e = m - 1;
}
if(i) S = bord[i][s];
else T = bord[i][s];
}
answer(S, T);
}
namespace
{
constexpr int MAX_NUM_CALLS = 100;
constexpr long long INF = 1LL << 61;
int N, M, A, B, S, T;
std::vector<int> U, V;
std::vector<std::vector<std::pair<int, int>>> graph;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
CAPITOLUL 2. IOI 2018 2.5. HIGHWAY TOLLS 212
if (answered)
{
wrong_answer("answered not exactly once");
}
answered = true;
}
int main()
{
auto t1 = clock();
N = read_int();
M = read_int();
A = read_int();
B = read_int();
S = read_int();
T = read_int();
U.resize(M);
V.resize(M);
auto t2 = clock();
answered = false;
wrong_pair = false;
num_calls = 0;
find_pair(N, U, V, A, B);
auto t3 = clock();
if (!answered)
{
wrong_answer("answered not exactly once");
}
if (wrong_pair)
{
wrong_answer("{s, t} is wrong");
}
printf("Accepted: %d\n", num_calls);
auto t4 = clock();
fclose(stdout);
return 0;
}
/*
Accepted: 45
t2-t1 = 0.343
CAPITOLUL 2. IOI 2018 2.5. HIGHWAY TOLLS 214
t3-t2 = 4.009
t4-t3 = 0
//#include <ctime>
#include <time.h> /* clock */
//#include <cstdio>
#include <stdio.h> // citire mai rapida !!!
#include <bits/stdc++.h>
#include "highway.h"
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define f first
#define s second
#define all(a) (a).begin(),(a).end()
#define For(i,a,b) for(auto i=(a);i<(b);i++)
#define FOR(i,b) For(i,0,b)
#define Rev(i,a,b) for(auto i=(a);i>(b);i--)
#define REV(i,a) Rev(i,a,-1)
#define FORE(i,a) for(auto&&i:a)
#define sz(a) (int((a).size()))
#define MIN(a,b) ((a)=min((a),(b)))
#define MAX(a,b) ((a)=max((a),(b)))
using pii=pair<int,int>;
using pll=pair<ll,ll>;
using pill=pair<int,ll>;
using plli=pair<ll,int>;
using pdd=pair<double,double>;
using pld=pair<ld,ld>;
fill(tr, tr + M, 0);
ll DA = ask(Q);
while (lo < hi)
{
mid = lo + (hi - lo) / 2;
FOR(i, M) Q[i] = i <= mid;
if (ask(Q) == DA) lo = mid + 1;
else hi = mid;
}
fill(to, to + N, -1);
queue<pii> q;
q.emplace(U[lo], 0);
q.emplace(V[lo], 1);
tr[lo] = 1;
to[U[lo]] = to[V[lo]] = -INT_INF;
while (!q.empty())
{
pii v = q.front();
q.pop();
verts[v.s].pb(v.f);
FORE(e, adj[v.f])
{
int w = v.f ˆ U[e] ˆ V[e];
if (to[w] != -1) continue;
q.emplace(w, v.s);
tr[to[w] = e] = 1;
}
}
FOR(i, 2)
{
lo = 1, hi = sz(verts[i]) - 1;
while (lo <= hi)
{
mid = lo + (hi - lo) / 2;
FOR(j, M) Q[j] = !tr[j];
For(j, mid, sz(verts[i])) Q[to[verts[i][j]]] = 1;
if (ask(Q) == DA) hi = mid - 1;
else lo = mid + 1;
}
ans[i] = verts[i][hi];
}
answer(ans[0], ans[1]);
}
namespace
{
constexpr int MAX_NUM_CALLS = 100;
constexpr long long INF = 1LL << 61;
int N, M, A, B, S, T;
std::vector<int> U, V;
std::vector<std::vector<std::pair<int, int>>> graph;
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
}
}
return -1;
}
answered = true;
}
int main()
{
auto t1 = clock();
N = read_int();
M = read_int();
A = read_int();
B = read_int();
S = read_int();
T = read_int();
U.resize(M);
V.resize(M);
auto t2 = clock();
answered = false;
wrong_pair = false;
num_calls = 0;
find_pair(N, U, V, A, B);
auto t3 = clock();
if (!answered)
{
wrong_answer("answered not exactly once");
}
if (wrong_pair)
{
wrong_answer("{s, t} is wrong");
}
printf("Accepted: %d\n", num_calls);
auto t4 = clock();
fclose(stdout);
return 0;
}
/*
Accepted: 45
t2-t1 = 0.343
t3-t2 = 4.04
t4-t3 = 0
2.6 Meetings
Problema 6 - Meetings 100 de puncte
Pentru fiecare şedinţă doriţi să găsiţi costul minim posibil de organizare a ei.
Luaţi la cunoştinţă că după fiecare şedinţă fiecare participant se ı̂ntoarce la muntele lui; deci
costul unei şedinţe nu este influenţat de şedinţele precedente.
Detalii de implementare
Exemple
Şedinţa j 0 are Lj 0 şi Rj 2, deci participanţii vor fi de la munţii 0, 1 şi 2. Dacă muntele
0 este ales ca munte de organizare a şedinţei, atunci costul şedinţei 0 este calculat astfel:
a Costul participantului din muntele 0 este maxrH0 x 2.
a Costul participantului din muntele 1 este maxrH0 , H1 x 4.
a Costul participantului din muntele 2 este maxrH0 , H1 , H2 x 4.
a Deci, costul şedinţei este 2 4 4 10.
Este imposibil de organizat şedinţa cu un cost mai mic, deci costul minim al şedinţei 0 este 10.
Şedinţa j 1 are Lj 1 şi Rj 3, deci participanţii vor fi de la munţii 1, 2 şi 3. Dacă muntele
2 este ales ca munte de organizare a şedinţei, atunci costul şedinţei 1 este calculat astfel:
a Costul participantului din muntele 1 este maxrH1 , H2 x 4.
a Costul participantului din muntele 2 este maxrH2 x 3.
a Costul participantului din muntele 3 este maxrH2 , H3 x 5.
a Deci, costul şedinţei este 4 3 5 12.
Este imposibil de organizat şedinţa 1 cu un cost mai mic, deci costul minim al şedinţei 1 este
12.
Fişierele sample-01-in.txt şi sample-01-out.txt din pachetul anexat sub forma de
arhivă corespund acestui exemplu. Alte exemple sunt de asemenea disponibile ı̂n pachet.
Restricţii
Subtaskuri
Exemplu de grader
There are N mountains, numbered from 0 through N 1 from left to right. The height of the
mountain i is Hi (0 & i & N 1). Exactly one person lives on each mountain.
You are going to hold Q meetings, numbered from 0 through Q 1. To the meeting j (0 &
j & Q 1), you will invite all people living on the mountains between the mountain Lj and the
mountain Rj , inclusive.
For each meeting, you can choose a mountain as the meeting place. If the mountain x is chosen
as the meeting place, the cost of the meeting is calculated as follows:
The cost of the meeting is the sum of the costs of all participants.
The cost of the participant from the mountain y is the maximum height of mountains between
the mountain x and the mountain y, inclusive. Particularly, the cost of the participant from
the mountain x is Hx .
equal to argmaxL&i&R Hi , because by reversing the array H and solving the same problem we
can get a real answer.
We denote the problem of calculating the minimum cost of a meeting with the range L, R
as query L, R.
Let Cost L, R be the answer to the query L, R.
Let RangeL v be the smallest x such that .
Similarly, let be the largest such that argmaxL&i&R Hi v.
Also let S v be the array of length
RangeR v RangeL v 1
We are going to compute S v for all v, and then it is easy to get answers to all queries. The
order of indices in which we compute S v is very important. Here, we use depth-first-search
post-order of the cartesian tree of H.
We define the cartesian tree of H as the rooted tree such that lowest-common-ancestor of nodes
u and v is the node argmaxu&i&v Hi .
The cartesian tree can be obtained in linear time by an iteration with a stack data structure.
It can be easily seen that every node of the cartesian tree has at most two children, one to the
left and another to the right. Let lc v be the left child of the node v and rc v be the right child
of the node v (here we assume that the node v has two children).
Now the remaining task is to somehow merge S lc v and S rc v into S v . Clearly, first
some elements of S v is exactly S lc v .
All we need is to compute Cost RangeL v , p, for all p (v & p).
Since Hv is the maximum value in the range RangeL v , RangeR v , you can see
Cost RangeL v , p
minrCost RangeL v , v p v Hv , v RangeL v 1 Hv Cost v 1, px
and
Cost RangeL v , v p v Hv v RangeL v 1 Hv Cost v 1, p
& Cost RangeL v, v p 1 v Hv v RangeL v 1 Hv Cost v 1, p 1
where p 1 & RangeR v .
The inequality follows from the observation that
for all z $ p.
Therefore, you can get S v in the following way:
Let T be the array obtained by adding a certain value to all elements of S rc v .
Update first some elements of T with a certain linear funtion.
Concatenate S lc v , Cost RangeL v , v , and T .
Getting the answer to a query requires one lower bound operation of the set. Thus in
O Q log N time we can get answers to all queries.
The total time complexity is O N Q log N .
TASK=meetings
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
int N = read_int();
int Q = read_int();
CAPITOLUL 2. IOI 2018 2.6. MEETINGS 223
std::vector<int> H(N);
for (int i = 0; i < N; ++i)
{
H[i] = read_int();
}
std::vector<int> L(Q), R(Q);
for (int j = 0; j < Q; ++j)
{
L[j] = read_int();
R[j] = read_int();
}
#include "meetings.h"
#include <algorithm>
#include <ctime>
#include <iostream>
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
struct minseg
{
pii T[2202020];
int sz = 1 << 20;
for(i=sz-1; i; i--)
{
T[i] = max(T[i << 1], T[i << 1 | 1]);
}
}
l += sz; r += sz;
CAPITOLUL 2. IOI 2018 2.6. MEETINGS 224
for(; l<=r; )
{
if(l & 1) ret = max(ret, T[l]);
if(˜r & 1) ret = max(ret, T[r]);
l = l + 1 >> 1;
r = r - 1 >> 1;
}
return ret.second;
}
};
struct line
{
ll x, a, b;
line() {}
line(ll x, ll a, ll b) : x(x), a(a), b(b) {}
};
struct deq
{
line D[808080];
int S[808080], E[808080];
ll V[808080];
int n;
bool t;
void addval(int p, ll v)
{
if(t) p = n - 1 - p;
V[p] += v;
}
void addline(int p, ll x, ll a, ll b)
{
if(t)
{
p = n - 1 - p, x = n - 1 - x;
b = (n - 1) * a + b; a = -a;
}
b -= V[p];
ll getval(int p, ll x)
{
if(t) p = n - 1 - p, x = n - 1 - x;
}) - D - 1;
int i;
minseg T;
deq DL, DR;
vector <int> H, L, R;
vector <int> Q[808080];
vector <ll> A;
int n;
int m, l, r;
ll v, h;
return m;
}
CAPITOLUL 2. IOI 2018 2.6. MEETINGS 226
vector <ll> minimum_costs(vector <int> _H, vector <int> _L, vector <int> _R)
{
int i;
dnc(0, n - 1);
return A;
}
// =======================================================================
int main()
{
auto t1 = clock();
int N = read_int();
int Q = read_int();
std::vector<int> H(N);
for (int i = 0; i < N; ++i) {
H[i] = read_int();
}
std::vector<int> L(Q), R(Q);
for (int j = 0; j < Q; ++j)
{
L[j] = read_int();
R[j] = read_int();
}
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
fclose(stdout);
return 0;
}
// =======================================================================
/*
t2-t1 = 4.192
t3-t2 = 2.416
t4-t3 = 0.97
// https://oj.uz/submission/76204
#include <bits/stdc++.h>
int n;
struct query
{
int i, l, r;
query(int i, int l, int r) : i(i), l(l), r(r) {}
};
vector<query> qs[750001];
pii arr[750001];
struct line
{
int s, e;
llong m, b;
line() {}
line(int s, int e, llong m, llong b) : s(s), e(e), m(m), b(b) {}
struct que
{
int s, e;
llong add;
que(int s, int e) : s(s), e(e), add(0) {}
llong getRight() const
{
if (s > e) return 0;
return ls[e].get(ls[e].e) + add;
}
CAPITOLUL 2. IOI 2018 2.6. MEETINGS 228
{
while (L.size())
{
R.push_front(L.back());
L.pop_back();
}
return R;
}
else
{
while (R.size())
{
L.push_back(R.front());
R.pop_front();
}
return L;
}
}
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
std::freopen("../in/05-12.txt", "r", stdin);
std::freopen("meetings.out", "w", stdout);
auto t1 = clock();
int N = read_int();
int Q = read_int();
std::vector<int> H(N);
for (int i = 0; i < N; ++i)
{
H[i] = read_int();
CAPITOLUL 2. IOI 2018 2.6. MEETINGS 230
}
std::vector<int> L(Q), R(Q);
for (int j = 0; j < Q; ++j)
{
L[j] = read_int();
R[j] = read_int();
}
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 1.205
t3-t2 = 11.063
t4-t3 = 0.765
//#include <ctime>
#include <time.h> /* clock */
#include <algorithm>
struct minseg
{
pii T[2202020];
int sz = 1 << 20;
for(i=sz-1; i; i--)
{
T[i] = max(T[i << 1], T[i << 1 | 1]);
CAPITOLUL 2. IOI 2018 2.6. MEETINGS 231
}
}
l += sz; r += sz;
for(; l<=r; )
{
if(l & 1) ret = max(ret, T[l]);
if(˜r & 1) ret = max(ret, T[r]);
l = l + 1 >> 1;
r = r - 1 >> 1;
}
return ret.second;
}
};
struct line
{
ll x, a, b;
line() {}
line(ll x, ll a, ll b) : x(x), a(a), b(b) {}
};
struct deq
{
line D[808080];
int S[808080], E[808080];
ll V[808080];
int n;
bool t;
t = _t; n = _n;
void addval(int p, ll v)
{
if(t) p = n - 1 - p;
V[p] += v;
}
void addline(int p, ll x, ll a, ll b)
{
if(t)
{
p = n - 1 - p, x = n - 1 - x;
b = (n - 1) * a + b; a = -a;
}
b -= V[p];
ll getval(int p, ll x)
{
if(t) p = n - 1 - p, x = n - 1 - x;
int i;
minseg T;
deq DL, DR;
vector <int> H, L, R;
vector <int> Q[808080];
vector <ll> A;
int n;
int m, l, r;
ll v, h;
return m;
}
swap(H, _H);
swap(L, _L);
swap(R, _R);
n = H.size();
A.resize(L.size());
T.init(H);
DL.init(0, n);
DR.init(1, n);
dnc(0, n - 1);
return A;
}
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
std::freopen("../in/05-12.txt", "r", stdin);
std::freopen("meetings.out", "w", stdout);
auto t1 = clock();
int N = read_int();
int Q = read_int();
std::vector<int> H(N);
for (int i = 0; i < N; ++i)
{
H[i] = read_int();
}
std::vector<int> L(Q), R(Q);
for (int j = 0; j < Q; ++j)
{
L[j] = read_int();
R[j] = read_int();
}
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 4.295
t3-t2 = 5.205
t4-t3 = 1.148
#include <bits/stdc++.h>
struct lichao
{
int A, l, r;
long long B, lazy;
lichao() : A(0), l(0), r(0), B(0x3fffffffffffffffLL), lazy(0) {}
};
return;
}
add_line(tree,n1,n2,A,B,2*bit,s,m);
add_line(tree,n1,n2,A,B,2*bit+1,m+1,e);
}
long long get_y(lichao *tree, int x, int bit=1, int s=0, int e=SZ-1)
{
int m=(s+e)>>1;
lazy_propagation(tree,bit,s,e);
if(s==e) return 1LL*tree[bit].A*x+tree[bit].B;
return min(x<=m ? get_y(tree,x,2*bit,s,m):
get_y(tree,x,2*bit+1,m+1,e),1LL*tree[bit].A*x+tree[bit].B);
}
solve(1,N);
return res;
}
namespace
{
int read_int()
{
int x;
if (scanf("%d", &x) != 1)
{
fprintf(stderr, "Error while reading input\n");
exit(1);
}
return x;
}
} // namespace
int main()
{
auto t1 = clock();
int N = read_int();
int Q = read_int();
std::vector<int> H(N);
for (int i = 0; i < N; ++i)
{
H[i] = read_int();
}
std::vector<int> L(Q), R(Q);
for (int j = 0; j < Q; ++j)
{
L[j] = read_int();
R[j] = read_int();
}
fclose(stdin);
auto t2 = clock();
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 1.109
t3-t2 = 11.448
t4-t3 = 0.75
https://cp-algorithms.com/geometry/convex_hull_trick.html
3.1 Nowruz
Problema 1 - Nowruz 100 de puncte
Au rămas doar câteva zile până la Nowruz (Anul Nou persan) şi bunicul a invitat ı̂ntreaga
familie la o petrecere ı̂n grădina sa. Printre invitaţi sunt şi k copii. Pentru a face petrecerea mai
distractivă pentru copii bunicul vrea să organizeze o joacă de-a v-aţi ascunselea.
Grădina este reprezentată printr-o matrice m n de celule unitare. Unele celule (posibil nici
una) sunt blocate de pietre, iar celelalte celule se numesc libere. Două celule se numesc vecine
dacă au o latură comună. Astfel, fiecare celulă poate avea până la patru vecini: doi pe orizontală
şi doi pe verticală.
Bunicul doreşte să transforme grădina ı̂ntr-un labirint. ı̂n acest scop el poate bloca unele celule
libere plantând ı̂n ele arbuşti. Celulele ı̂n care au fost plantaţi arbuşti nu mai sunt libere.
Labirintul trebuie să posede următoarea proprietate: pentru fiecare pereche de celule libere a
şi b ı̂n labirint va exista un drum simplu unic, care să le unească.
Un drum simplu ı̂ntre celulele a şi b este o secvenţă de celule libere ı̂n care prima celulă este
a, ultima - b, toate celulele sunt distincte şi fiecare două celule consecutive sunt vecine.
Un copil se poate ascunde ı̂ntr-o celulă dacă şi numai dacă celula este liberă şi are exact un
vecin liber. Nu se pot ascunde doi sau mai mulţi copii ı̂n aceeaşi celulă.
Se dă harta grădinii. Se cere ajutarea bunicului ı̂n realizarea unui labirint ı̂n care să se ascundă
cât mai mulţi copii.
Particularităţi de implementare
Aceasta este o problemă tip output-only cu scoruri parţiale. Primiţi 10 fişiere de intrare, fiecare
dintre ele descriind o grădină a bunicului. Pentru fiecare fişier de intrare trebuie să submitaţi un
fişier de ieşire, care să conţină o hartă a labirintului. Pentru fiecare fişier de ieşire veţi primi
puncte ı̂n funcţie de numărul de copii, care se pot ascunde ı̂n labirintul vostru.
Nu trebuie să submitaţi nici o sursă pentru această problemă.
Format Input
Fiecare fişier de intrare va descrie o matrice reprezentând grădina şi numărul de copii k invitaţi
de bunic. Formatul fişierului este următorul:
a linia 1: m n k
a linia 1 i (pentru 1 & i & m): linia i a matricei, formată dintr-un şir de caractere de lungime
n, format din următoarele caractere (fără spaţii):
` ’.’: o celulă liberă,
` ’#’: piatră.
Format Output
31
aur: Ştefan Constantin-Buliga, CNI ”Tudor Vianu” Bucureşti
. aur: Tamio-Vesa Nakajima, Liceul Vocaţional Pedagogic ”Nicolae Bolcaş”, Beiuş,
. bronz: Costin-Andrei Oncescu, Dinicu Golescu (Campulung),
. bronz: Andrei-Costin Constantinescu, ICHB (Bucureşti).
238
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 239
a linia i (pentru 1 & i & m): linia i a labirintului (grădinii, după plantarea arbuştilor). Este
un şir de caractere de lungime n, format din următoarele caractere (fără spaţii):
` ’.’: o celulă liberă,
` ’#’: piatră,
` ’X’: arbust. (De remarcat că litera X trebuie să fie majusculă.)
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 240
Restricţii
a 1 & m, n & 1024
Punctaje
Fişierul output se consideră a fi valid dacă respectă toate condiţiile următoare:
a Harta de ieşire va coincide cu harta de intrare cu unica excepţie că un număr arbitrar de
caractere ’.’ din harta de intrare pot fi transformate ı̂n caractere ’X’ (celule blocate cu
arbuşti).
a Harta de ieşire va avea proprietatea de labirint, după cum acesta a fost definit ı̂n enunţul
problemei.
Dacă fişierul output pentru un test nu va fi valid, scorul acordat pentru acest test va fi 0. ı̂n
caz contrar, scorul va fi calculat ca min 10, 10 l©k puncte, trunchiat până la două cifre zecimale
după virgulă. Aici, l este numărul copiilor care se pot ascunde ı̂n labirintul submitat, k fiind
numărul dat ı̂n fişierul de intrare. Veţi primi câte 10 puncte doar pentru acele teste ı̂n care harta
de ieşire le va permite să se ascundă la k sau mai mulţi copii. Pentru fiecare test există o soluţie
care permite acordarea a 10 puncte.
De menţionat, că ı̂n cazul ı̂n care aveţi o soluţie validă dar care acumulează 0 puncte conform
formulei de mai sus, mesajul evaluatorului afişat ı̂n CMS va fi ’Wrong Answer’.
Exemplu
Considerăm următorul input:
4 5 5
....#
.#..#
...#.
....#
.X.X#
.#..#
...#X
XX..#
Deoarece copii se pot ascunde ı̂n acest labirint, soluţia va primi puncte. Celulele ı̂n care se
ascund copiii sunt marcate mai jos cu O :
OXOX#
.#.O#
...#X
XX.O#
În output-ul din stânga nu există un drum simplu ı̂ntre celula liberă din colţul stâng-sus şi
celula liberă din cea mai de dreapta coloană. ı̂n celelalte două output-uri, pentru fiecare pereche
de celule libere distincte există exact câte două drumuri simple diferite, care le unesc.
Timp maxim de executare/test: Output-only
Memorie: Output-only
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 241
Unexpectedly, the following code generates a nice Sierpinski fractal with 148 leaves:
mark[1][1] = true
scan the whole grid, starting from (1,1):
mark each cell that has exactly 1 marked neighbor
return mark
But the optimal solution we have so far for this grid can be obtained by a simple change on
the above code. It is a nice fractal with 408 leaves:
mark[1][1] = true
loop
scan the whole grid:
mark each cell that has exactly 1 marked neighbor
until mark values are not changed
return mark
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 242
This solution could score for 86 points with the actual test data of the contest.
Another idea is to pick a random free cell to initiate the tree, and keep expanding it as long
as possible. Expanding operation: Pick a free cell that is adjacent to exactly one of the tree cells
so far, add this cell and all of its adjacent cells that can be added and become leaves to the tree.
At each moment, expand the tree where it adds the highest number of leaves. Note that in each
operation, 1 to 5 cells will be added to the tree. This solution gets 99+ percent.
#include <vector>
#include <set>
#include <string>
#include <queue>
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 243
#include <iostream>
#include <fstream>
ifstream fin("../tests/02.in");
ofstream fout("02.out.txt");
////////////////////////////////////////////////////////////////////////////
struct solver
{
const int dx[4] = {0, -1, 0, 1};
const int dy[4] = {-1, 0, 1, 0};
int n, m;
string grid[maxn];
set<pair<int, pii>> s;
int cnt = 0;
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 244
return cnt;
}
void add(pii p)
{ // add node p and extension options around p
grid[p.X][p.Y] = TREE;
rep(d, 4)
if(open(pii(p.X + dx[d], p.Y + dy[d])))
{
int cnt = extend(pii(p.X + dx[d], p.Y + dy[d]), 0);
if(cnt != -1)
s.insert({cnt, pii(p.X + dx[d], p.Y + dy[d])});
}
}
while(!q.empty())
{
pii p = q.front();
q.pop();
rep(dir, 4)
if(open(adj(p, dir)) &&
mark[p.X + dx[dir]][p.Y + dy[dir]] != vmark)
mark[p.X + dx[dir]][p.Y + dy[dir]] = vmark,
q.push(adj(p, dir)),
size++;
}
return size;
}
void init()
{
rep(x, n) mark[x].resize(maxn, 0);
pii start;
int best_cnt = -1;
rep(x, n) rep(y, m) if(!mark[x][y] && grid[x][y] == OPEN)
{
int cnt = cnt_size(x, y);
if(cnt > best_cnt)
best_cnt = cnt, start = pii(x, y);
}
add(start);
}
bool is_path;
int dfs(int x, int y, bool st = true)
{
if(!open(pii(x, y)) ||
(!st && around(pii(x, y), TREE) > 0) ||
mark[x][y] == vmark)
return 0;
mark[x][y] = vmark;
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 245
int res = 1;
int cnt = 0;
rep(dir, 4)
{
int ores = res;
res += dfs(x + dx[dir], y + dy[dir], false);
if(res > ores) cnt++;
}
void solve()
{
init();
while(true)
{
while(!s.empty())
{
auto t = *s.rbegin();
s.erase( *s.rbegin());
if(cnt == t.first)
extend(t.second, 1);
else if(cnt != -1)
s.insert({cnt, t.second});
}
rep(x, n)
if(!changed)
rep(y, m)
if(!changed &&
grid[x][y] == OPEN &&
around(pii(x, y), TREE) == 1)
{
add(pii(x, y));
changed = true;
}
rep(x, n)
if(!changed)
rep(y, m)
if(!changed &&
grid[x][y] == OPEN &&
around(pii(x, y), TREE) == 2)
{
int cnt = 0;
rep(dir, 4)
{
pii q = adj(pii(x, y), dir);
if(inside(q) &&
grid[q.X][q.Y] == OPEN &&
around(q, TREE) == 0)
cnt++;
}
rep(dir, 4)
{
pii q = adj(pii(x, y), dir);
if(inside(q) &&
grid[q.X][q.Y] == TREE &&
around(q, TREE) == 1)
{
grid[q.X][q.Y] = OPEN;
add(pii(x, y));
changed = true;
break;
}
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 246
}
}
rep(x, n)
if(!changed)
rep(y, m)
if(!changed && grid[x][y] == OPEN && around(pii(x, y), TREE) == 2)
{
vmark++; is_path = true;
int size = dfs(x, y);
int cnt = 0;
rep(dir, 4)
{
pii q = adj(pii(x, y), dir);
if(inside(q) &&
grid[q.X][q.Y] == TREE &&
around(q, TREE) == 1)
cnt++;
}
rep(dir, 4)
{
pii q = adj(pii(x, y), dir);
if(inside(q) &&
grid[q.X][q.Y] == TREE &&
around(q, TREE) == 1)
{
grid[q.X][q.Y] = OPEN;
add(pii(x, y));
changed = true;
break;
}
}
}
if(!changed) break;
}
}
void read()
{
fin >> n >> m; // ***
int tmp;
fin >> tmp; // ***
rep(x, n) fin >> grid[x]; // ***
}
void write()
{
rep(x, n)
rep(y, m)
if(grid[x][y] == ’.’ || grid[x][y] == ’X’)
grid[x][y] ˆ= ’X’ ˆ ’.’;
int main()
{
ios_base::sync_with_stdio(false);
fin.tie(0);
solver f;
f.read();
f.solve();
f.write();
return 0;
}
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 247
#include<iostream>
#include "testlib.h"
struct node
{
node(int _r, int _c, int _pr, int _pc)
{
r = _r; c = _c; pr = _pr; pc = _pc;
}
int r, c, pr, pc;
};
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/02.in", // input
(char*)"../tests/02.out", // rezultat corect
(char*)"02.out.txt", // rezultat de verificat si acordat punctaj
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 248
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
m = inf.readInt();
inf.readSpace();
n = inf.readInt();
inf.readSpace();
answer = inf.readInt();
inf.readEoln();
32
OBS: Este folosită biblioteca testlib.h
#include <string>
#include <vector>
#include<ctime>
int main()
{
auto t1 = clock();
ios_base::sync_with_stdio(false); cin.tie(0);
auto t2 = clock();
for(; addleaves(1,1););
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0
t3-t2 = 0.796
t4-t3 = 0
argc = 4
checker
../tests/07.in
../tests/07.out
07.out.txt
----------------------
0.828
Partially Correct
number of leaves: 27639/33363
#include<ctime>
int main()
{
auto t1 = clock();
ios_base::sync_with_stdio(false); cin.tie(0);
auto t2 = clock();
addleaves(0,0);
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.015
t3-t2 = 0.047
t4-t3 = 0
argc = 4
checker
../tests/07.in
../tests/07.out
07.out.txt
----------------------
0.080
Partially Correct
number of leaves: 2687/33363
#include<ctime>
int count_leaves()
{
int c = 0;
For(i, m)
For(j, n)
if (table[i][j] == ’X’ && neighbors(i, j) == 1) c++;
return c;
}
if (! found)
for (int i = 1; i < m - 1; i++)
for (int j = 1; j < n - 1; j++)
found |= break_tie(i, j);
return found;
}
int main()
{
auto t1 = clock();
ios_base::sync_with_stdio(false); cin.tie(0);
auto t2 = clock();
first = table;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
try_add_leaves(i, j, false);
For(i, m)
For (j, n)
if (best[i][j] == ’.’ || best[i][j] == ’X’)
best[i][j] = ’.’ + ’X’ - best[i][j];
auto t3 = clock();
For (i, m)
cout << best[i] << endl;
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.031
t3-t2 = 8.369
t4-t3 = 0
argc = 4
checker
../tests/07.in
../tests/07.out
07.out.txt
----------------------
0.796
Partially Correct
number of leaves: 26588/33363
#include <bitset>
#include <algorithm>
#include<ctime>
int m, n;
double leaf_prob = 0.2;
vector <string> table;
int counter;
void rand_perm(int* p)
{
for (int i = 0; i < 4; i++)
{
p[i] = i;
swap(p[i], p[rand() % (i + 1)]);
}
}
void add_leaves() {
For(i, m)
For(j, n)
if (table[i][j] == ’.’ && neighbors(i, j) == 1) table[i][j] = ’X’;
}
{
auto t1 = clock();
ios_base::sync_with_stdio(false); cin.tie(0);
// leaf_prob = atof(argv[1]);
// cerr << leaf_prob << endl;
cin >> m >> n;
int tmp; cin >> tmp;
string s;
int blocks = 0;
For(i, m)
{
cin >> s;
table.push_back(s);
blocks += count(s.begin(), s.end(), ’#’);
}
auto t2 = clock();
add_leaves();
For(i, m)
For (j, n)
if (table[i][j] == ’.’ || table[i][j] == ’X’)
table[i][j] = ’.’ + ’X’ - table[i][j];
auto t3 = clock();
For (i, m)
cout << table[i] << endl;
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.015
t3-t2 = 0.078
t4-t3 = 0
argc = 4
checker
../tests/07.in
../tests/07.out
07.out.txt
----------------------
0.497
Partially Correct
number of leaves: 16602/33363
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 257
#include<ctime>
int m, n, k;
vector <string> table;
ios_base::sync_with_stdio(false); cin.tie(0);
string s;
For(i, m)
{
cin >> s;
table.push_back(s);
}
auto t2 = clock();
int i = 0, j;
for (; i < n && table[0][i] != ’.’; i++);
if (k > 1 && (j + k) % 2 == 0)
{
if (j > 1 && table[k][j-1] == ’.’)
table[k][j-1] = ’X’;
if (j < n - 1 && table[k][j+1] == ’.’)
table[k][j+1] = ’X’;
}
}
For(i, m)
For (j, n)
if (table[i][j] == ’.’ || table[i][j] == ’X’)
table[i][j] = ’.’ + ’X’ - table[i][j];
auto t3 = clock();
For (i, m)
cout << table[i] << endl;
auto t4 = clock();
CAPITOLUL 3. IOI 2017 3.1. NOWRUZ 258
return 0;
}
/*
t2-t1 = 0.015
t3-t2 = 0
t4-t3 = 0.016
argc = 4
checker
../tests/07.in
../tests/07.out
07.out.txt
----------------------
0.001
Partially Correct
number of leaves: 47/33363
#include <bits/stdc++.h>
ifstream fin("../tests/02.in");
ofstream fout("02.out.txt");
ll n, m, k;
char grid[1200][1200];
char grid2[1200][1200];
char bestGrid[1200][1200];
ll visited[1200][1200];
ll printed[1200];
int main()
{
//ios_base::sync_with_stdio(0); cin.tie(NULL);
//cerr << setprecision(5) << endl;
if(visited[i+1][j ]+
visited[i-1][j ]+
visited[i ][j+1]+
visited[i ][j-1] > 1)
{
grid[i][j] = ’X’;
continue;
}
else
{
visited[i][j]=1;
grid[i][j]=’.’;
q.push({i+1, j });
q.push({i , j+1});
q.push({i-1, j });
q.push({i , j-1});
}
}
ll cnt = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(grid[i][j]==’.’ &&
visited[i ][j-1]+
visited[i-1][j ]+
visited[i+1][j ]+
visited[i ][j+1] == 1)
cnt++;
}
}
if(score>bestScore)
{
bestScore = score;
for(int i = 0; i <= n+1; i++)
for(int j = 0; j <= m+1; j++)
bestGrid[i][j] = grid[i][j];
}
if((ll)(((ld)toDo/totalToDo*100))/10 >
(ll)(((ld)(toDo-1)/totalToDo*100))/10)
{
cerr << (ll)((ld)toDo/totalToDo*100) << "%: " << bestScore<<endl;
}
ll done = (((ld)I*m)+J)/(((ld)n*m)+m)*100;
//if((ll)lastDone/10<(ll)done/10)
lastDone = done;
}
argc = 4
checker
../tests/02.in
../tests/02.out
02.out.txt
----------------------
0.983
Partially Correct
number of leaves: 1316/1338
3.2 Wiring
Problema 2 - Wiring 100 de puncte
Maryam este inginer. Ea vrea să contruiască un turn de comunicaţie. Turnul conţine multe
puncte de conectare plasate la diferite inaltimi. Un cablu poate fi folosit pentru a conecta oricare
CAPITOLUL 3. IOI 2017 3.2. WIRING 261
două puncte de conectare. Toate punctele de conetare pot fi conectate cu un număr arbitrar de
cabluri.
Sunt doua tipuri de cabluri: roşii si albastre.
In corcondanta cu scopul acestei probleme, turnul poate fi văzut ca o linie, iar punctele de
conetare albastre si roşii ca puncte pe aceasta linie având coordonate intregi ne-negative. Lungimea
unui cablu este distanţa dintre cele doua puncte pe care le uneşte.
Scopul vostru este de a o ajuta pe Maryam pentru a găsi o schema de cablare astfel ı̂ncât:
1. Fiecare punct de conetare are cel puţin un cablu către o culoare diferită.
2. Lungimea totala a cablurilor este minima.
Detalii de Implementare
Se cere implementarea următoarei proceduri:
Exemplu
Evaluator local
Evaluatorul local citeşte datele din input ı̂n următorul format:
linia 1: n m
linia 2: r0 r1 ... rn 1
linia 3: b0 b1 ... bm 1
Evaluatorul afişează o singură linie, care conţine valoarea returnată de min_total_length.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 256 MB
Subtask 1
2 3
There are many different O n or O n dp solutions for this subtask. The simplest one is
to define dpi,j as the minimum cost needed for wiring the first i red points and the first j blue
points. Update is like dpi,j min dpi1,j , dpi,j 1 , dpi1,j 1 ¶redi bluej ¶.
Subtask 2
This subtask is to find the pattern of wiring. The simple solution to this subtask is to calculate
n1 m1
= redn1 redi = bluei blue0 max n, m blue0redn1
0 0
Subtask 3
Consider the consecutive clusters of points with the same color. The idea is each wire will
2
have endpoints in two consecutive clusters, so the O n solutions could be optimized to O n
M axBlockSize.
Subtask 4
This subtask could be solve greedily, halving each cluster and connecting left half to the left
cluster and right half to the right cluster. The middle point of clusters with odd number of points
should be considered separately.
Full solution
There is O n m dp solution: Let dpi be the minimum total distance of a valid wiring scheme
for the set of points that are less than or equal to a given point i. This could be updated with
amortized time complexity O 1.
#include<iostream>
#include<algorithm>
#include "wiring.h"
struct Point
{
int x, color;
bool operator <(const Point &p) const { return x < p.x; }
};
int n = nb + nr;
int st = 1, lastSz = 0;
lastSz = i - st;
st = i;
}
else
sum[i] = sum[i - 1] - p[i - 1].x;
if(st == 1)
{
dp[i] = 1e18;
continue;
}
int sz = i - st + 1;
long long curSum = sum[st] - sum[i] + p[i].x;
return dp[n];
}
return 0;
}
#include <cassert>
#include <cstdio>
#include<iostream>
#include<algorithm>
#include <fstream>
#include<ctime>
#include "wiring.h"
struct Point
{
int x, color;
bool operator <(const Point &p) const { return x < p.x; }
};
}
merge(tmp, tmp + nb, tmp + nb, tmp + nb + nr, p + 1);
int n = nb + nr;
int st = 1, lastSz = 0;
for(int i = 1; i <= n; i++)
{
if(p[i].color != p[i - 1].color)
{
for(int j = i; p[j].color == p[i].color; j++)
sum[i] += p[j].x;
for(int j = i - 1; j >= st; j--)
{
f[j] = -sum[j] + min(dp[j - 1], dp[j]) + 1LL * (i - j) * p[i - 1].x;
if(j < i - 1)
f[j] = min(f[j], f[j + 1]);
}
for(int j = st; j < i; j++)
{
g[j] = -sum[j] + min(dp[j - 1], dp[j]) + 1LL * (i - j) * p[i].x;
if(j > st)
g[j] = min(g[j], g[j - 1]);
}
lastSz = i - st;
st = i;
}
else
sum[i] = sum[i - 1] - p[i - 1].x;
if(st == 1)
{
dp[i] = 1e18;
continue;
}
int sz = i - st + 1;
long long curSum = sum[st] - sum[i] + p[i].x;
if(sz >= lastSz)
dp[i] = f[st - lastSz] + curSum - 1LL * sz * p[st - 1].x;
else
dp[i] = min(g[st - sz - 1] + curSum - 1LL * sz * p[st].x,
f[st - sz] + curSum - 1LL * sz * p[st - 1].x);
}
return dp[n];
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.491
t3-t2 = 0.043
t4-t3 = 0
vector<pie> points;
long long d[max_n + 1], ps[max_n + 1];
int head[max_n], cnt[max_n];
n = points.size();
for (int i = 1; i <= n; i++) ps[i] = ps[i-1] + points[i-1].first;
cnt[i] = cnt[i-1];
int j = head[i] - cnt[i];
if (cnt[i-1] == i - head[i])
if (j > head[j] && d[j-1] + val(j, i) > d[j-2] + val(j-1, i))
cnt[i]++, j--;
d[i] = min(d[j], d[j-1]) + val(j, i);
}
}
return d[n-1];
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.493
t3-t2 = 0.307
t4-t3 = 0
vector<pie> points;
long long d[max_n + 1], ps[max_n + 1];
int head[max_n];
n = points.size();
for (int i = 0; i < n - 1; i++)
assert(points[i].first != points[i + 1].first);
for (int i = 1; i <= n; i++) ps[i] = ps[i-1] + points[i-1].first;
return d[n-1];
}
int main()
{
auto t1 = clock();
CAPITOLUL 3. IOI 2017 3.2. WIRING 269
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.462
t3-t2 = 0.432
t4-t3 = 0
#include "wiring.h"
struct Point
{
int x, color;
bool operator <(const Point &p) const { return x < p.x; }
};
int nr = red.size();
for(int i = 0; i < nb; i++)
{
tmp[i].x = blue[i];
tmp[i].color = BLUE;
}
int n = nb + nr;
int st = 1, lastSz = 0;
for(int i = 1; i <= n; i++)
{
if(p[i].color != p[i - 1].color)
{
for(int j = i; p[j].color == p[i].color; j++)
sum[i] += p[j].x;
lastSz = i - st;
st = i;
}
else
sum[i] = sum[i - 1] - p[i - 1].x;
if(st == 1)
{
dp[i] = 1e18;
continue;
}
int sz = i - st + 1;
long long curSum = sum[st] - sum[i] + p[i].x;
if(sz >= lastSz)
dp[i] = f[st - lastSz] + curSum - 1LL * sz * p[st - 1].x;
else
dp[i] = min(g[st - sz - 1] + curSum - 1LL * sz * p[st].x,
f[st - sz] + curSum - 1LL * sz * p[st - 1].x);
}
return dp[n];
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.464
t3-t2 = 0.037
t4-t3 = 0
////////////////////////////////////////////////////////////////////////////
int n;
pii p[maxn];
int st[maxn], ed[maxn];
ll ps[maxn];
ll dp[maxn][2];
n = nb + nr;
CAPITOLUL 3. IOI 2017 3.2. WIRING 272
sort(p, p+n);
ps[0] = 0;
rep(i, n) ps[i+1] = ps[i] + p[i].X;
return dp[n][0];
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.438
t3-t2 = 0.194
t4-t3 = 0
#include <iostream>
#include <vector>
#include <algorithm>
#include<ctime>
#include <cassert>
int nex[MAXN];
long long sum[MAXN], dp[MAXN], f[MAXN];
int nm = n + m;
sum[nm] = 0, f[nm] = 0;
dp[nm-1] = inf, nex[nm-1] = nm, sum[nm-1] = q[nm-1].first;
for (int i = nm - 2; i >= 0; i--)
{
dp[i] = inf;
sum[i] = sum[i+1] + q[i].first;
nex[i] = q[i].second == q[i+1].second ? nex[i+1] : i+1;
if (nex[i] == i+1)
{
for (int j = nex[i+1]-1; j >= i+1; j--)
f[j] = min(dp[j], q[j].first - q[i].first + f[j+1]);
}
if (nex[i] == nm)
continue;
dp[i] = min(inf, dp[i+1] + q[nex[i]].first - q[i].first);
int sz = nex[i] - i;
if (nex[i]+sz-1 < nex[nex[i]])
dp[i] = min(dp[i],
get_sum(nex[i],
nex[i]+sz-1) - get_sum(i, nex[i]-1) + f[nex[i]+sz]);
}
return dp[0];
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.457
t3-t2 = 0.091
t4-t3 = 0
#include <bits/stdc++.h>
#include "wiring.h"
#define pb push_back
#define mp make_pair
long long n,dp[200001],presum[200001];
vector<pair<int,int> > arr;
int prevv[200001];
long long min_total_length(vector<int> r,vector<int> b)
{
n=r.size()+b.size();
int rid=0,bid=0;
while (rid<r.size() || bid<b.size())
{
if (rid==r.size())
{
arr.pb(mp(b[bid],1));
bid++;
}
else
if (bid==b.size())
{
arr.pb(mp(r[rid],0));
rid++;
}
else
{
if (r[rid]<=b[bid])
{
arr.pb(mp(r[rid],0));
rid++;
}
else
CAPITOLUL 3. IOI 2017 3.2. WIRING 275
{
arr.pb(mp(b[bid],1));
bid++;
}
}
}
dp[0]=1e15;
prevv[0]=-1;
presum[0]=arr[0].first;
if (prevv[i]==-1) continue;
dp[i]=min(dp[i],dp[i-1]+arr[i].first-arr[prevv[i]].first);
if (prevv[prevv[i]]<=prevv[i]-(i-prevv[i]))
{
long long cur=presum[i]-presum[prevv[i]];
cur-=(presum[prevv[i]]-presum[prevv[i]-(i-prevv[i])]);
if (prevv[i]-(i-prevv[i])!=-1)
cur+=dp[prevv[i]-(i-prevv[i])];
dp[i]=min(dp[i],cur);
}
}
return dp[n-1];
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.406
t3-t2 = 0.062
t4-t3 = 0
#include <bits/stdc++.h>
using namespace std;
typedef long long ll; /// dont use define int long long
ll min_total_length(vector<int> r, vector<int> b)
{
vector<vector<ll>> dp(0), prf(0);
vector<pair<ll, ll>> vt;
for(auto i: r) vt.emplace_back(i, 0);
for(auto i: b) vt.emplace_back(i, 1);
sort(vt.begin(), vt.end());
int cur = 0;
while(cur < vt.size())
{
int nxt = cur;
vector<ll> nprf = {0};
for(; nxt < vt.size() && vt[nxt].second == vt[cur].second; nxt++)
{
nprf.push_back(vt[nxt].first + nprf.back());
}
cur = nxt;
vector<ll> blank(nprf.size(), (ll)1e17);
dp.push_back(blank);
prf.push_back(nprf);
}
dp[0][0] = 0;
for(int i = 0; i < dp.size(); i++)
{
for(int j = 0; j + 1 < dp[i].size(); j++)
{
if(i > 0)
Minimize(dp[i][j + 1],
dp[i][j] + Get(i, j + 1) - Get(i - 1,
prf[i - 1].size() - 1));
Minimize(dp[i][j + 1],
dp[i][j] - Get(i, j + 1) + Get(i + 1, 1));
CAPITOLUL 3. IOI 2017 3.2. WIRING 277
}
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.391
t3-t2 = 0.5
t4-t3 = 0
#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define sz(x) (int)x.size()
#define f first
#define s second
#define all(x) x.begin(), x.end()
#define forn(i, a, b) for(int i = a; i <= b; i++)
#define forev(i, a, b) for(int i = a; i >= b; i--)
for(auto x : v)
{
i--;
if(was[!x.s] != -1) go[i] = min(go[i], was[!x.s] - x.f);
was[x.s] = x.f;
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
CAPITOLUL 3. IOI 2017 3.2. WIRING 279
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.406
t3-t2 = 0.5
t4-t3 = 0
#include "wiring.h"
#include <algorithm>
#include <vector>
#include<ctime>
#include<iostream>
#include<cassert>
vector<char> a(n);
vector<int> b(n);
sort(temp.begin(), temp.end());
vector<int> lone(n);
for (int i = 0; i < n; ++i)
{
int j = i;
while (j + 1 < n && a[j + 1] == a[i]) ++j;
for (int k = i; k <= j; ++k)
lone[k] = min(i ? b[k]-b[i-1] : inf,
j+1 < n ? b[j+1]-b[k] : inf);
i = j;
CAPITOLUL 3. IOI 2017 3.2. WIRING 280
vector<llong> dp(n);
dp[0] = lone[0];
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.39
t3-t2 = 0.453
t4-t3 = 0
CAPITOLUL 3. IOI 2017 3.2. WIRING 281
#include<ctime>
#include<cassert>
#include<iostream>
#define X first
#define Y second
#define PB push_back
ll prf[N];
map < int , ll > dp[N];
int n, L[N], R[N], G[N], rv[N];
vp v;
ll ret = INF;
if(lst > 0)
CAPITOLUL 3. IOI 2017 3.2. WIRING 282
ll min_total_length(vi r, vi b)
{
for(int i = 0;i < N;i++) dp[i].clear();
ll S_r = 0, S_b = 0;
for(int x : r) v.PB({x, 1});
for(int x : b) v.PB({x, 0});
sort(v.begin(), v.end());
int l = 0, ll = 0, gr = 0;
for(int i = 0;i < v.size();i++)
{
prf[i] = (long long)(v[i].X) + (i ? prf[i - 1] : 0);
if(v[i].Y != l && i != 0)
{
if(gr)
rv[gr] = G[gr - 1] + rv[gr - 1];
G[gr] = i - ll;
L[gr] = ll;
R[gr++] = i - 1;
ll = i;
}
l = v[i].Y;
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.438
t3-t2 = 1.265
t4-t3 = 0
#include<bits/stdc++.h>
using namespace std;
#include "wiring.h"
LL min_total_length(vector<int> r, vector<int> b)
{
vector<PII> p;
for(int x : r) p.emplace_back(x, 1);
for(int x : b) p.emplace_back(x, 2);
sort(p.begin(), p.end());
int n = size(p);
vector<int> s(n);
FOR(i, 1, n - 1)
s[i] = (p[i].ND != p[i - 1].ND ? i : s[i - 1]);
LL inf = 1e18;
vector<LL> dp(n, inf), x(n), y(n, inf), sum(n);
REP(i, n) sum[i] = (i != 0 ? sum[i - 1] : 0) + p[i].ST;
REP(i, n)
{
if(s[i] == 0) continue;
int u = s[i] - 1, v = s[i];
auto rel = [&](int l, int r)
{
return abs(get(l, r) - LL(r - l + 1) * p[v].ST);
};
if(v == i)
{
LL cur = inf;
FOR(j, s[u], u)
{
cur = min(cur, (j == 0 ? 0 : dp[j - 1]) + rel(j, u));
x[j] = cur;
}
cur = inf;
CAPITOLUL 3. IOI 2017 3.2. WIRING 284
if(s[i] - s[s[i] - 1] == 1)
dp[i] = min(dp[u],
(u == 0 ? 0 : dp[u - 1]))
+ rel(v, i)
+ LL(i - u) * (p[v].ST - p[u].ST);
else
{
dp[i] = y[i];
if(i - u <= u - s[u] + 1)
dp[i] = min(dp[i], x[u - (i - v)] + rel(v, i));
}
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.421
t3-t2 = 0.485
t4-t3 = 0
ll min_total_length(vector<int> r, vector<int> b)
{
int n = r.size(), m = b.size();
vector<pair<int, bool>> p;
for(int i: r)
{
p.push_back({i, 0});
}
for(int i: b)
{
p.push_back({i, 1});
}
sort(p.begin(), p.end());
vector<vector<ll>> block;
for(int i=0; i<n+m; ++i)
{
if(i==0 || p[i].nd!=p[i-1].nd)
{
block.push_back({});
}
block.back().push_back(p[i].st);
}
auto prev=block[0];
block.erase(block.begin());
bool type = 1;
int nr=0;
for(auto i: block)
{
dp[type][0] = dp[!type][(int)prev.size()];
vector<ll> suf(prev.size()+1);
for(int j=1; j<=(int)prev.size(); ++j)
{
suf[j] = suf[j-1]+prev[(int)prev.size()-j];
}
ll pref=0;
int k = 0;
if(nr==0) k=(int)prev.size();
for(int j=1; j<=(int)i.size(); ++j)
{
pref+=i[j-1];
while(k<(int)prev.size())
{
ll v1 = pref - suf[k]
- max(0LL, (ll)j-k)*prev.back()
+ max(0LL, (ll)k-j)*i[0]
+ dp[!type][(int)prev.size()-k];
ll v2 = pref - suf[k+1]
- max(0LL, (ll)j-k-1)*prev.back()
+ max(0LL, (ll)k+1-j)*i[0]
+ dp[!type][(int)prev.size()-k-1];
CAPITOLUL 3. IOI 2017 3.2. WIRING 286
if(v2<=v1)
k++;
else
break;
}
prev = i;
type ˆ= 1;
nr++;
}
return dp[!type][(int)prev.size()];
}
int main()
{
auto t1 = clock();
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
return 0;
}
/*
res = 15991144105164
t2-t1 = 0.422
t3-t2 = 0.516
t4-t3 = 0
Arezou şi fratele ei Borzou sunt gemeni. Cei doi au primit ca şi cadou de ziua lor un set cu
trenuri de jucărie. Cei doi au construit cu ajutorul cadoului un sistem de cale ferată cu n staţii
şi m linii orientate. Staţiile sunt numerotate de la 0 la n 1. Fiecare linie pleacă dintr-o staţie si
ajunge in aceeasi sau alta staţie. Exista cel putin o linie care pleaca din fiecare staţie.
Unele statii sunt staţii de ı̂ncărcare. Cand un tren ajunge ı̂ntr-o staţie de incărcare, se ı̂ncarcă
complet. Un tren incărcat complet are destulă energie sa parcurgă n linii consecutive. Astfel,
cand trenul ajunge pe a n 1 - a linie de la ultima incărcare, va ramâne fără energie şi se va opri.
Fiecare staţie are un macaz care se poate indrepta către una din liniile care pornesc din staţia
curentă. Cand un tren se află ı̂ntr-o staţie, pleaca din acea staţie prin linia spre care e ı̂ndreptat
macazul.
Gemenii vor să se joace cu trenul lor. Acestia şi-au ı̂mparţit staţiile ı̂ntre ei: fiecare staţie este
deţinuta de Arezou sau de Borzou. Există un singur tren. La ı̂nceputul jocului trenul se află ı̂n
staţia s şi e ı̂ncărcat complet. Pentru a ı̂ncepe jocul, proprietarul staţiei s ı̂ndreapta macazul din
staţie către una din staţiile care pornesc din staţia s. Apoi dau drumul la tren şi trenul işi ı̂ncepe
traseul dealungul liniilor.
De fiecare data cănd trenul intra ı̂ntr-o staţie pentru prima data, proprietarul acelei staţii
fixează macazul din acea staţie.
Odată ce macazul a fost fixat, acesta rămâne ı̂ndreptat spre aceeasi linie pentru restul jocului.
Astfel, daca un tren reintra ı̂ntr-o staţie pe care a vizitat-o ı̂nainte, o va părăsi pe aceeaşi linie ca
data precedentă.
Din moment ce există un număr finit de staţii, trenul eventual va intra intr-un ciclu. Un ciclu
este o secvenţa de staţii distincte c0, c1, ..., ck 1, astfel ı̂ncât trenul pleacă din staţia ci
(pentru 0 & i $ k 1) pe o linie către staţia ci 1, şi pleacă din staţia ck 1 pe o linie către
staţia c0. Un ciclu poate fi format şi dintr-o singură staţie (ex. k 1) dacă trenul pleacă din
staţia c0 pe o linie care se indreaptă ı̂napoi spre c0.
Arezou câştigă jocul dacă trenul merge incontinuu, şi Borzou cı̂stigă dacă trenul rămâne fără
energie. Altfel spus, dacă există cel puţin o staţie de ı̂ncărcare printre c0, c1, ..., ck 1,
trenul se poate reincărca, ceea ce ı̂nseamna că va merge incontinuu şi Arezou va câştiga. ı̂n caz
contrar, trenul va rămâne fără energie (probabil dupa ce va parcurge ciclul de câteva ori), ceea ce
inseamnă că va castiga Borzou.
Se dă sistemul de cale de ferata. Arezou şi Borzou vor juca n jocuri. ı̂n al s -lea joc, pentru
0 & s & n 1, trenul va fi iniţial in statia s. Se cere pentru fiecare joc sa se afle daca exista o
strategie pentru Arezou care sa ı̂i garanteze victoria indiferent cum joaca Borzou.
Detalii de implementare
Se cere să se implementeze următoarea procedură:
a a: un sir de lungime n Daca Arezou deţine a i -a staţie, ai 1. Altfel, Borzou deţine a
i -a staţie si ai 0. . a r: un şir de lungime n. Dacă a i -a statie este o staţie de ı̂ncărcare,
atunci ri 1. Altfel, ri 0.
a u şi v: doua şiruri de lungime m. Pentru toate 0 & i & m 1, există o linie orientată care
pleacă din staţia ui şi ajunge ı̂n staţia v i.
a Această procedură ar trebui să returneze un şir w de lungime n. Pentru toate 0 & i & n 1,
valoarea lui wi ar trebui sa fie 1 daca Arezou poate câştiga jocul care incepe ı̂n staţia i, neluand
ı̂n considerare cum joacă Borzou. Altfel, valoare lui wi ar trebui să fie 0.
Exemplu
a Sunt 2 statii. Borzou este proprietarul staţiei 0, care este o staţie de ı̂ncărcare. Arezou este
proprietarul staţiei 1, care nu este o staţie de ı̂ncărcare.
a Sunt 4 linii (0,0), (0,1), (1,0), si (1,1), unde (i,j) semnifica o linie orientata de la staţia i la
staţia j.
a Considerăm jocul ı̂n care trenul este iniţial ı̂n staţia 0. Daca Borzou fixează macazul staţiei 0
către linia (0,0), trenul va merge incontinuu prin această linie (de luat ı̂n considerare că staţiaeste
o staţie de ı̂ncărcare). ı̂n acest caz, Arezou castigă. ı̂n caz contrar, daca Borzou fixează macazul
staţiei 0 către linia (0,1), Arezou poate ı̂ndrepta macazul staţiei 1 către linia (1,0). ı̂n acest caz
va merge incontinuu prin ambele staţii. Din nou Arezou câştigă, din moment ce staţia 0 este o
statie de ı̂ncărcate şi trenul nu se va opri. Asadar, Arezou câştigă jocul, indiferent ce face Borzou.
a Similar, ı̂n jocul care incepe ı̂n staţia 1 Arezou de asemenea poate câştiga, indiferent cum
joaca Borzou. Asadar, procedura ar trebui să returneze [1,1].
Restricţii si precizări
a 1 & n & 5 000.
a n & m & 20 000.
a Există cel puţin o staţie de ı̂ncărcare.
a Există cel puţin o linie care porneşte din fiecare staţie.
a Pot exista linii care pornesc şi se termină ı̂n aceeaşi staţie (ex. ui v i).
a Fiecare linie este distinctă. In alte cuvinte, nu există doua poziţii i si j (0 & i $ j & m 1)
astfel incăt ui uj si v i v j .
a 0 & ui, v i & n 1 (pentru toate 0 & i & m 1).
Subtask-uri
1. (5 puncte) Pentru fiecare 0 & i & m 1, avem v i ui ori v i ui 1.
2. (10 puncte) n & 15.
3. (11 puncte) Arezou deţine toate staţiile.
4. (11 puncte) Borzou deţine toate staţiile.
5. (12 puncte) Exista o singură staţie de ı̂ncărcare.
6. (51 puncte) Nu exista restricţii adiţionale.
Evaluator local
Evaluatorul local citeşte inputul ı̂n următorul format:
a linia 1: n m
a linia 2: a0, a1, ..., an 1
a linia 3: r 0, r 1, ..., r n 1,
a linia 4+i (pentru 0 & i & m 1): ui v i
Evaluatorul local printează valoarea returnată de who_wins ı̂n următorul format:
a linia 1: w 0, w 1, ..., w n 1
For a set of stations S, define fA S as the set of all stations such that if the train is placed on
them, Arezou can play in a way that the train reaches one of the stations in S at some point
regardless of Borzou’s moves (therefore S N fA S by definition). We define fB S similarly.
Initially let T S, and we iteratively add stations to T such that eventually T equals fA S .
While there exists a station v that satisfies one of the following conditions, we add v to set T .
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 289
1. v is owned by Arezou, and there exists an outgoing track from v that leads to a station
already in T .
2. v is owned by Borzou, and all of the outgoing tracks from v leads to the stations already in
T . Similarly we can compute fB S . Notice that both fA S and fB S can be computed
iteratively in time O n m.
Now let R be the set of all the charging stations. By definition, for every station v fA R,
Borzou can win the game if the train is initially placed on v.
Therefore, we can solve the problem as follows:
If fA R is the set of all remaining stations, Arezou can win the game for all initial stations.
Otherwise:
1. Let X be set of stations not in fA R.
2. Borzou can win the game if the initial stations is in fB X .
3. Remove fB X from the graph and solve the problem recursively.
#include "train.h"
#include <vector>
#include <algorithm>
////////////////////////////////////////////////////////////////////////////
vector<int> radj[maxn];
int deg[maxn], need[maxn];
rep(i, n)
if(r[i] && res[i])
dfs(i, r); // dfs from yet-has-a-chance-to-win wells
rep(i, n)
if(r[i] && res[i] && need[i] > 0)
res[i] = false, cng = true; // and see if they had no chance
}
rep(i, n)
res[i] &= (need[i] <= 0); // look, more fopdoodles
return res;
}
return 0;
}
#include <cstdio>
#include <vector>
#include <cassert>
#include <string>
#include <algorithm>
#include<ctime>
#include<iostream>
// BEGIN SECRET
const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
const string output_secret = "d16905a4427c193ad87ae7fa91a2bb55";
// END SECRET
// -----------------------------------------------------------
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 291
////////////////////////////////////////////////////////////////////////////
vector<int> radj[maxn];
int deg[maxn], need[maxn];
rep(i, n)
res[i] &= (need[i] <= 0); // look, more fopdoodles
return res;
}
// -----------------------------------------------------------
int main()
{
auto t1 = clock();
// BEGIN SECRET
char secret[1000];
assert(1 == scanf("%s", secret));
if (string(secret) != input_secret)
{
printf("%s\n", output_secret.c_str());
printf("SV\n");
return 0;
}
// END SECRET
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 292
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
printf("%s\n", output_secret.c_str());
if((int)res.size() != n)
{
printf("WA\n");
printf("Wrong returned array size\n");
}
else
printf("OK\n");
// END SECRET
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.063
t3-t2 = 2.7
t4-t3 = 0
#include<iostream>
int main()
{
int argc=4;
char* argv[] =
{
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 293
(char*)"checker",
(char*)"../tests/6-25.in", // input
(char*)"../tests/6-25.out", // rezultat corect
(char*)"train.out.txt", // rezultat de verificat si acordat punctaj
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
readBothSecrets(output_secret);
readBothGraderResults();
compareRemainingLines(3);
}
/*
argc = 4
checker
../tests/6-25.in
../tests/6-25.out
train.out.txt
----------------------
1
Correct
#include <cstdio>
#include <vector>
#include <cassert>
#include <string>
#include <algorithm>
#include<ctime>
#include<iostream>
#include <queue>
#include <cstring>
// BEGIN SECRET
const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
const string output_secret = "d16905a4427c193ad87ae7fa91a2bb55";
// END SECRET
// -----------------------------------------------------------
///////////////////////////////////////////////////////////////////////////
vector<int> radj[maxn];
int deg[maxn], need[maxn];
rep(i, n)
res[i] &= (need[i] <= 0); // look, more fopdoodles
return res;
}
// -----------------------------------------------------------
int main()
{
auto t1 = clock();
// BEGIN SECRET
char secret[1000];
assert(1 == scanf("%s", secret));
if (string(secret) != input_secret)
{
printf("%s\n", output_secret.c_str());
printf("SV\n");
return 0;
}
// END SECRET
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 295
// BEGIN SECRET
printf("%s\n", output_secret.c_str());
if((int)res.size() != n)
{
printf("WA\n");
printf("Wrong returned array size\n");
}
else
printf("OK\n");
// END SECRET
auto t4 = clock();
return 0;
}
// -----------------------------------------------------------
/*
t2-t1 = 0.054
t3-t2 = 2.731
t4-t3 = 0.008
#include <cstdio>
#include <vector>
#include <cassert>
//#include <string>
#include <algorithm>
#include<ctime>
#include<iostream>
#include <queue>
#include <cstring>
// BEGIN SECRET
const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
const string output_secret = "d16905a4427c193ad87ae7fa91a2bb55";
// END SECRET
// -----------------------------------------------------------
const int B = 0;
const int A = 1;
{
for (int i = 0; i < (int)u.size(); i++)
{
adj[u[i]].push_back(v[i]);
bak[v[i]].push_back(u[i]);
}
int n = (int)a.size();
for (int i = 0; i < n; i++)
f[i] = A;
while (true)
{
for (int i = 0; i < n; i++) if (f[i] != B)
{
mark[i] = false;
checked[i] = false;
need[i] = a[i] == A ? 1 : (int)adj[i].size();
}
queue<int> q;
for (int i = 0; i < n; i++) if (r[i] && f[i] == A)
q.push(i);
while (!q.empty())
{
int front = q.front();
q.pop();
if (checked[front] == true)
continue;
checked[front] = true;
for (int i = 0; i < (int)bak[front].size(); i++)
{
int temp = bak[front][i];
--need[temp];
if (need[temp] == 0 && mark[temp] == false && f[temp] == A)
{
q.push(temp);
mark[temp] = true;
}
}
}
if (!flag)
break;
}
vector<int> res;
for (int i = 0; i < n; i++)
res.push_back(f[i]);
return res;
}
// -----------------------------------------------------------
int main()
{
auto t1 = clock();
// BEGIN SECRET
char secret[1000];
assert(1 == scanf("%s", secret));
if (string(secret) != input_secret)
{
printf("%s\n", output_secret.c_str());
printf("SV\n");
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 297
return 0;
}
// END SECRET
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
printf("%s\n", output_secret.c_str());
if((int)res.size() != n)
{
printf("WA\n");
printf("Wrong returned array size\n");
}
else
printf("OK\n");
// END SECRET
auto t4 = clock();
return 0;
}
// -----------------------------------------------------------
/*
t2-t1 = 0.054
t3-t2 = 3.325
t4-t3 = 0
#include <bits/stdc++.h>
#include "train.h"
// BEGIN SECRET
const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 298
while (true)
{
vector<int> ans = r;
{
queue<int> q;
vector<int> cdeg = deg;
for (int i = 0; i < n; ++i)
{
if (ans[i])
{
q.push(i);
}
}
while (!q.empty())
{
int u = q.front(); q.pop();
for (int v : g[u])
{
if (!ans[v])
{
if (a[v] || (--cdeg[v]) == 0)
{
ans[v] = 1;
q.push(v);
}
}
}
}
}
{
queue<int> q;
vector<int> cdeg = deg;
for (int i = 0; i < n; ++i)
{
if (!ans[i])
{
q.push(i);
}
}
while (!q.empty())
{
int u = q.front(); q.pop();
for (int v : g[u])
{
if (ans[v])
{
if (!a[v] || (--cdeg[v]) == 0)
{
ans[v] = 0;
q.push(v);
}
}
}
}
}
if (finish)
{
return ans;
}
}
}
// -----------------------------------------------------------
int main()
{
auto t1 = clock();
// BEGIN SECRET
char secret[1000];
assert(1 == scanf("%s", secret));
if (string(secret) != input_secret)
{
printf("%s\n", output_secret.c_str());
printf("SV\n");
return 0;
}
// END SECRET
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
printf("%s\n", output_secret.c_str());
if((int)res.size() != n)
{
printf("WA\n");
printf("Wrong returned array size\n");
}
else
printf("OK\n");
// END SECRET
auto t4 = clock();
return 0;
}
// -----------------------------------------------------------
/*
t2-t1 = 0.078
t3-t2 = 5.147
t4-t3 = 0
#include <bits/stdc++.h>
#include "train.h"
// BEGIN SECRET
const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
const string output_secret = "d16905a4427c193ad87ae7fa91a2bb55";
// END SECRET
void dfs(int u)
{
loop(i, 0, ba[u].size())
{
int v=ba[u][i];
req[v]--;
if(!req[v] && !po[v])
dfs(v);
}
};
bool cn=1;
while(cn)
{
cn=0;
loop(i, 0, n) req[i]=(A[i])? 1:fo[i].size();
loop(i, 0, n) if(po[i]&&ans[i]) dfs(i);
loop(i, 0, n) if(ans[i]!=(req[i]<1)) ans[i]=(req[i]<1), cn=1;
}
return ans;
}
// -----------------------------------------------------------
int main()
{
auto t1 = clock();
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 301
// BEGIN SECRET
char secret[1000];
assert(1 == scanf("%s", secret));
if (string(secret) != input_secret)
{
printf("%s\n", output_secret.c_str());
printf("SV\n");
return 0;
}
// END SECRET
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
printf("%s\n", output_secret.c_str());
if((int)res.size() != n)
{
printf("WA\n");
printf("Wrong returned array size\n");
}
else
printf("OK\n");
// END SECRET
auto t4 = clock();
return 0;
}
// -----------------------------------------------------------
/*
t2-t1 = 0.062
t3-t2 = 2.386
t4-t3 = 0
// https://oj.uz/submission/160375
#include "train.h"
#include <bits/stdc++.h>
// BEGIN SECRET
const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
const string output_secret = "d16905a4427c193ad87ae7fa91a2bb55";
// END SECRET
int N, M;
vector<int> station, owner;
vector<vector<int>> G, G_inverse;
vector<int> out_degree;
vector<int> visited;
vector<int> charging_set;
vector<int> new_charging_set;
void initialize_charging_set()
{
visited.assign(N, !VISITED);
out_degree.assign(N, 0);
charging_set.assign(N, !CHARGING_SET);
queue<int> q;
for (int i = 0; i < N; i++)
if (station[i] == CHARGING_STATION &&
new_charging_set[i] == CHARGING_SET)
q.push(i), visited[i] = VISITED;
while (!q.empty())
{
int u = q.front(); q.pop();
charging_set[u] = CHARGING_SET;
for (auto v : G_inverse[u])
{
if (visited[v] == VISITED) continue;
switch (owner[v])
{
case AREZOU:
if (visited[v] == !VISITED)
{
visited[v] = VISITED;
q.push(v);
}
break;
case BORZOU:
out_degree[v]++;
if (out_degree[v] == G[v].size() &&
visited[v] == !VISITED)
{
visited[v] = VISITED;
q.push(v);
}
break;
}
}
}
N = owner.size(), M = u_.size();
G.resize(N), G_inverse.resize(N);
new_charging_set.resize(N, CHARGING_SET);
break;
case BORZOU:
new_charging_set[i] = CHARGING_SET;
for (auto v : G[i])
if (charging_set[v] == !CHARGING_SET)
new_charging_set[i] = !CHARGING_SET;
break;
}
}
vector<int> res(N);
for (int i = 0; i < N; i++)
res[i] = (charging_set[i] == CHARGING_SET);
return res;
}
// -----------------------------------------------------------
int main()
{
auto t1 = clock();
// BEGIN SECRET
char secret[1000];
assert(1 == scanf("%s", secret));
if (string(secret) != input_secret)
{
printf("%s\n", output_secret.c_str());
printf("SV\n");
return 0;
}
// END SECRET
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
printf("%s\n", output_secret.c_str());
if((int)res.size() != n)
{
printf("WA\n");
printf("Wrong returned array size\n");
}
else
printf("OK\n");
// END SECRET
auto t4 = clock();
return 0;
}
// -----------------------------------------------------------
/*
t2-t1 = 0.078
t3-t2 = 6.343
t4-t3 = 0
#include "train.h"
#include <bits/stdc++.h>
// BEGIN SECRET
const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
const string output_secret = "d16905a4427c193ad87ae7fa91a2bb55";
// END SECRET
tmp[i] = deg[i];
}
queue<int> q;
for (int x : v)
{
used[x] = 1;
q.push(x);
}
while (!q.empty())
{
int node = q.front();
q.pop();
vector<int> ans;
for (int i = 0; i < n; i++)
{
if (used[i])
ans.push_back(i);
}
return ans;
}
while (work)
{
work = false;
vector<int> sts;
for (int i = 0; i < n; i++)
{
if (r[i])
sts.push_back(i);
}
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 306
return res;
}
// -----------------------------------------------------------
int main()
{
auto t1 = clock();
// BEGIN SECRET
char secret[1000];
assert(1 == scanf("%s", secret));
if (string(secret) != input_secret)
{
printf("%s\n", output_secret.c_str());
printf("SV\n");
return 0;
}
// END SECRET
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
printf("%s\n", output_secret.c_str());
if((int)res.size() != n)
{
printf("WA\n");
printf("Wrong returned array size\n");
}
else
printf("OK\n");
// END SECRET
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 307
auto t4 = clock();
return 0;
}
// -----------------------------------------------------------
/*
t2-t1 = 0.078
t3-t2 = 7.346
t4-t3 = 0
#include "train.h"
#include <algorithm>
#include <vector>
#include<string>
#include<ctime>
#include<cassert>
#include<iostream>
// BEGIN SECRET
const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
const string output_secret = "d16905a4427c193ad87ae7fa91a2bb55";
// END SECRET
std::vector<int> undet;
std::vector<int> removing;
bool toRemove[MAXN], removed[MAXN];
int currentDeg[MAXN];
void reset()
{
for (int node : undet)
{
toRemove[node] = false;
removed[node] = false;
currentDeg[node] = degree[node];
}
}
void flipowners()
{
for (int node : undet)
owner[node] = 1 - owner[node];
}
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 308
void removal()
{
for (int node : undet)
if (toRemove[node])
{
removing.emplace_back(node);
removed[node] = true;
}
while (!removing.empty())
{
int rm = removing.back();
removing.pop_back();
void findlosers()
{
reset();
for (int node : undet)
toRemove[node] = charge[node];
removal();
std::vector<int> losers;
for (int node : undet)
if (!removed[node])
losers.emplace_back(node);
reset();
flipowners();
while (!undet.empty())
{
findlosers();
std::vector<int> losers;
if (losers.empty())
{
for (int node : undet)
winner[node] = 1;
undet.clear();
}
else
{
for (int node : losers)
{
for (int next : graph[node])
degree[next]--;
undet.erase(std::find(undet.begin(), undet.end(), node));
}
}
}
return winner;
}
// -----------------------------------------------------------
int main()
{
auto t1 = clock();
// BEGIN SECRET
char secret[1000];
assert(1 == scanf("%s", secret));
if (string(secret) != input_secret)
{
printf("%s\n", output_secret.c_str());
printf("SV\n");
return 0;
}
// END SECRET
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
printf("%s\n", output_secret.c_str());
if((int)res.size() != n)
{
printf("WA\n");
printf("Wrong returned array size\n");
}
else
printf("OK\n");
// END SECRET
auto t4 = clock();
return 0;
}
// -----------------------------------------------------------
/*
t2-t1 = 0.062
t3-t2 = 3.797
t4-t3 = 0
#include <vector>
#include <cstring>
#include <queue>
#include<string>
#include<ctime>
#include<cassert>
#include<iostream>
#define PB push_back
// BEGIN SECRET
const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
const string output_secret = "d16905a4427c193ad87ae7fa91a2bb55";
// END SECRET
vi v[N], r[N];
int cnt[N], izb[N];
queue < int > Q;
{
memset(spas, 0, sizeof(spas));
memset(smrt, 0, sizeof(smrt));
memset(cnt, 0, sizeof(cnt));
for(;!Q.empty();Q.pop())
{
int cur = Q.front();
for(int x : r[cur])
{
if(izb[x]) continue;
cnt[x]--;
if(cnt[x] == 0 && !smrt[x])
{
smrt[x] = 1;
Q.push(x);
}
}
}
for(;!Q.empty();Q.pop())
{
int cur = Q.front();
for(int x : r[cur])
{
if(izb[x]) continue;
cnt[x]--;
if(cnt[x] == 0 && !spas[x])
{
spas[x] = 1;
Q.push(x);
}
}
}
int cc = 0;
for(int i = 0;i < n;i++)
if(spas[i] && !izb[i]) cc++, izb[i] = 1;
if(cc == 0) break;
}
vi sol;
int main()
{
auto t1 = clock();
// BEGIN SECRET
char secret[1000];
assert(1 == scanf("%s", secret));
if (string(secret) != input_secret)
{
printf("%s\n", output_secret.c_str());
printf("SV\n");
return 0;
}
// END SECRET
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
printf("%s\n", output_secret.c_str());
if((int)res.size() != n)
{
printf("WA\n");
printf("Wrong returned array size\n");
}
else
printf("OK\n");
// END SECRET
auto t4 = clock();
return 0;
}
// -----------------------------------------------------------
/*
t2-t1 = 0.062
t3-t2 = 3.562
t4-t3 = 0
*/
#include "train.h"
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
#include<ctime>
#include<cassert>
// BEGIN SECRET
const string input_secret = "3d2051c242fe2ae63792f9868123a5eb";
const string output_secret = "d16905a4427c193ad87ae7fa91a2bb55";
// END SECRET
vector<int> nei[maxN];
int charge[maxN], a[maxN];
int ans[maxN];
int col[maxN], isCyc[maxN];
int n;
vector<int> rnei[maxN];
bool used1[maxN];
void DFS1(int v, vector<int>& sorted)
{
used1[v] = true;
for (int to: nei[v])
if (!used1[to])
DFS1(to, sorted);
sorted.push_back(v);
}
void SCC()
{
vector<int> sorted;
for (int i = 0; i < n; ++i)
if (!used1[i])
DFS1(i, sorted);
reverse(sorted.begin(), sorted.end());
int cols = 0;
for (int v: sorted)
if (!col[v])
DFS2(v, ++cols);
}
bool used3[maxN];
void DFS3(int v)
{
used3[v] = true;
ans[v] = 1;
for (int to: rnei[v])
if (!used3[to])
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 314
DFS3(to);
}
vector<int> Solve3()
{
SCC();
vector<bool> goodcol(n);
for (int v = 0; v < n; ++v)
if (charge[v])
goodcol[col[v]] = true;
for (int v = 0; v < n; ++v)
if (goodcol[col[v]] && isCyc[col[v]] && !used3[v])
DFS3(v);
return vector<int>(ans, ans + n);
}
if (a[u])
{
g = true;
for (int to: nei[u])
if (!mask[to] && ans[to] != 0)
g = false;
}
else
{
g = false;
for (int to: nei[u])
if (mask[to] || ans[to] == 0)
g = true;
}
if (!g)
{
--cnt;
mask[u] = 0;
for (int to: rnei[u])
if (mask[to])
cycle.push(to);
}
}
return cnt;
}
while (cycle.size())
{
int u = cycle.front();
cycle.pop();
if (!ans[u]) continue;
bool g = false;
if (a[u])
{
g = true;
for (int to: nei[u])
if (ans[to] != 0)
CAPITOLUL 3. IOI 2017 3.3. TOY TRAIN 315
g = false;
}
else
{
g = false;
for (int to: nei[u])
if (ans[to] == 0)
g = true;
}
if (g)
{
ans[u] = 0;
for (int to: rnei[u])
if (ans[to])
cycle.push(to);
}
}
}
vector<int> Solve()
{
for (int i = 0; i < n; ++i)
ans[i] = 1;
vector<char> stmask(n);
while (true)
{
auto mask = stmask;
if (!OK(mask))
break;
for (int i = 0; i < n; ++i)
if (mask[i])
{
ans[i] = 0;
stmask[i] = 0;
}
Add(mask);
}
// BEGIN SECRET
char secret[1000];
assert(1 == scanf("%s", secret));
if (string(secret) != input_secret)
{
printf("%s\n", output_secret.c_str());
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 316
printf("SV\n");
return 0;
}
// END SECRET
int n, m;
assert(2 == scanf("%d %d", &n, &m));
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
printf("%s\n", output_secret.c_str());
if((int)res.size() != n)
{
printf("WA\n");
printf("Wrong returned array size\n");
}
else
printf("OK\n");
// END SECRET
auto t4 = clock();
return 0;
}
// -----------------------------------------------------------
/*
t2-t1 = 0.062
t3-t2 = 2.719
t4-t3 = 0
Jocul ”Marele premiu” este un renumit show de televiziune. Sunteţi norocosul participant care
s-a calificat ı̂n runda finală. Staţi ı̂n faţa unui rând de n cutii, numerotate de la stânga la dreapta
de la 0 până la n 1. Fiecare cutie conţine un premiu care nu poate fi văzut până când cutia nu
este deschisă. Există v ' 2 diferite tipuri de premii. Tipurile de premii sunt numerotate de la 1 la
v ı̂n ordinea descrescătoare a valorii.
Premiul de tipul 1 este cel mai scump: un diamant. Există un singur diamant ı̂n cutii. Premiul
de tip v este cel mai ieftin: o acadea. Pentru a face jocul cât mai captivant, numărul premiilor
ieftine este mult mai mare decât numărul premiilor scumpe. Mai exact, pentru toate t cu 2 & t & v
2
se ştie: dacă există k premii de tip t 1 , atunci există strict mai mult decât k premii de tip t.
Aveţi scopul să câştigaţi diamantul. La sfârşitul jocului va trebui să deschideţi cutia şi să luaţi
premiul din cutie. ı̂nainte de a deschide cutia aleasă trebuie să ı̂l ı̂ntrebaţi pe Rambod, gazda
show- ului, câteva ı̂ntrebări. Pentru fiecare ı̂ntrebare, veţi alege o cutie i. Ca răspuns, Rambod
vă va oferi un şir a care conţine doi ı̂ntregi. Semnificaţia acestor ı̂ntregi este:
a Printre cutiile din stânga cutiei i sunt exact a0 cutii care conţin premii mai scumpe decât
premiul din cutia i .
a Printre cutiile din dreapta cutiei i sunt exact a1 cutii care conţin premii mai scumpe decât
premiul din cutia i.
De exemplu, presupunem că n 8 şi alegeti cutia i 2 ca ı̂ntrebare pusă. Ca răspuns Rambod
vă dă şirul a 1, 2. Semnificaţia acestui răspuns este:
a Exact una din cutiile 0 şi 1 conţine un premiu mai scump decât premiul din cutia 2.
a Exact două din cutiile 3, 4, ..., 7 conţin premii mai scumpe decât premiul din cutia 2.
Sarcina voastră este să găsiţi cutia care conţine diamantul punând un număr mic de ı̂ntrebări.
Detalii de implementare
Trebuie să implementaţi următoarea procedură:
int find_best(int n)
int[] ask(int i)
a i: numărul cutiei despre care vreţi să ı̂ntrebaţi. Valoarea lui i trebuie să fie ı̂ntre 0 şi n 1,
inclusiv.
a Această procedură returnează un şir a cu 2 elemente. a0 este numărul premiilor mai
scumpe din cutiile din stânga cutiei i şi a1 este numărul premiilor mai scumpe din cutiile din
dreapta cutiei i.
Exemplu
Evaluatorul execută următorul apel al procedurii:
find_best(8)
Există n 8 cutii. Presupunem că premiile sunt de următoarele tipuri [3,2,3,1,3,3,2,3]. Toate
cazurile posibile de apel a procedurii ask şi respectiv valorile returnate sunt:
ask(0) returnează [0,3]
ask(1) returnează [0,1]
ask(2) returnează [1,2]
ask(3) returnează [0,0]
ask(4) returnează [2,1]
ask(5) returnează [2,1]
ask(6) returnează [1,0]
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 318
Exemplul este ilustrat ı̂n figura de mai sus. Partea de sus arată valorile premiilor ı̂n fiecare
cutie. Partea de jos arată interogarea ask(2). Cutiile marcate conţin premii mai scumpe decât
cutia cu numărul 2.
Restricţii şi precizări
3 & n & 200 000.
a
Tipul premiilor ı̂n fiecare cutie este ı̂ntre 1 şi v, inclusiv.
a
a Există un singur premiu de tipul 1.
a Pentru toate 2 & t & v, dacă există k premii de tipul t 1, atunci există strict mai mult de
2
k premii de tipul t.
Subtask-uri şi punctaj
În unele teste comportamentul evaluatorului este adaptiv. Adică, ı̂n aceste teste, evaluatorul
nu are o secvenţă fixă de premii. ı̂n schimb, răspunsurile oferite de evaluator poate depinde de
ı̂ntrebările transmise de soluţia voastră. Se garantează că evaluatorul răspunde ı̂n aşa fel ı̂ncât
după fiecare răspuns există cel puţin o secvenţă consistentă de premii cu toate răspunsurile date
până acum.
1. (20 puncte) Există exact 1 diamant şi n 1 acadele (prin urmare, v 2). Puteţi apela
procedura ask de cel mult 10 000 de ori.
În subtask-ul 2 puteţi obţine un scor parţial. Fie q numărul maxim de apeluri a procedurii
ask pentru toate testele din acest subtask. Punctajul pentru acest subtask este calculat conform
următorului tabel:
ı̂ntrebări Punctaj
10 000 ¡ q 0 (raportat ı̂n CMS ca ’Wrong Answer’)
6 000 $ q & 10 000 70
5 000 $ q & 6 000 80 - (q - 5 000) / 100
q & 5 000 80
Evaluator local
Evaluatorul local nu este adaptiv. ı̂n schimb, el citeşte şi utilizează un şir fix p de tipuri de
premii. Pentru toate 0 & b & n 1, tipul premiului din cutia b este dat ca pb. Formatul intrării
pentru evaluatorul local este:
a linia 1: n
a linia 2: p0 p1 ... pn 1
Evaluatorul local afişează o singură linie care conţine valoarea returnată de find_best şi
numărul de apeluri a procedurii ask.
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 319
Subtask 1
In this subtask, We can find the diamond with a simple binary search.
Subtask 2
First we query the first 474 prize in the line. Its sufficient to find at least a lollipops prize
(cheapest). When we have found a lollipop, we can use binary search to find all prize except Ó
lollipops. This approach needs less than 9000 queries. The number of queries required is O n
log n but there are exists another way which leads to less queries:
Find a lollipop. Then use devide and conquer: ask the middle of segment until finding new
lollipop. then devide the segment into two segment and keep the number of prizes which aren’t
lollipop. choose another random frog. If they are both young we know with the current information
if there are any older frogs between them. If there exists we can recursively solve the interval
between them. This approach needs at most 3000 queries.
#include <vector>
#include <cmath>
#include <cstring>
#include "prize.h"
#define X first
#define Y second
int numb;
pii P[210000];
bool mark[210000];
vector<int>vtmp;
pii query(int x)
{
if(mark[x]) return P[x];
mark[x]=true;
vtmp=ask(x);
pii tmp=pii(vtmp[0],vtmp[1]);
if(tmp.X+tmp.Y==0) throw x;
return P[x]=tmp;
}
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 320
int find_best(int n)
{
if(n==1) return 0;
try{
numb=0;
memset(mark,false,sizeof mark);
int p=0;
for(int i=0;i<sqrt(n)+30 && i<n && numb<=26;i++)
{
pii tmp=query(i);
if(tmp.X+tmp.Y>numb) p=i;
numb=max(numb,tmp.X+tmp.Y);
}
bs(p,n-1,p,0);
}
catch(int ans){
return ans;
}
return -1;
}
// -------------------------------------------------
static const int max_q = 10000;
static int n;
static int query_count = 0;
static vector<int> g;
static vector<vector<int> > rank_count;
vector<int> ask(int i) {
query_count++;
if(query_count > max_q) {
cerr << "Query limit exceeded" << endl;
exit(0);
}
vector<int> res(2);
res[0] = rank_count[g[i] - 1][i + 1];
res[1] = rank_count[g[i] - 1][n] - res[0];
return res;
}
int main()
{
cinf >> n; // ***
g.resize(n);
for(int i = 0; i < n; i++)
{
cinf >> g[i]; // ***
if(g[i] < 1) {
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 321
cerr << "Invalid rank " << g[i] << " at index " << i << endl;
exit(0);
}
}
return 0;
}
#include <iostream>
#include <vector>
#include <algorithm>
#include<ctime>
#include <string>
#include <cmath>
#include <cstring>
#define X first
#define Y second
int numb;
pii P[210000];
bool mark[210000];
vector<int>vtmp;
pii query(int x)
{
if(mark[x]) return P[x];
mark[x]=true;
vtmp=ask(x);
pii tmp=pii(vtmp[0],vtmp[1]);
if(tmp.X+tmp.Y==0) throw x;
return P[x]=tmp;
}
int mid,midl=(l+r)/2-i/2,midr=(l+r)/2+(i+1)/2;
if(i%2==0) mid=midl;
else mid=midr;
pii tmp=query(mid);
if(tmp.X+tmp.Y==numb)
{
int tmpl=(i%2==0?0:midr-midl);
int tmpr=(i%2==1?0:midr-midl);
if(tmp.X-tmpl>nl) bs(l,midl-1,nl,tmp.Y+tmpl);
if(tmp.Y-tmpr>nr) bs(midr+1,r,tmp.X+tmpr,nr);
break;
}
}
}
int find_best(int n)
{
if(n==1) return 0;
try
{
numb=0;
memset(mark,false,sizeof mark);
int p=0;
for(int i=0;i<sqrt(n)+30 && i<n && numb<=26;i++)
{
pii tmp=query(i);
if(tmp.X+tmp.Y>numb) p=i;
numb=max(numb,tmp.X+tmp.Y);
}
bs(p,n-1,p,0);
}
catch(int ans)
{
return ans;
}
return -1;
}
vector<int> ask(int i)
{
query_count++;
if(query_count > max_q)
{
cerr << "Query limit exceeded" << endl;
exit(0);
}
vector<int> res(2);
res[0] = rank_count[g[i] - 1][i + 1];
res[1] = rank_count[g[i] - 1][n] - res[0];
return res;
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
//cin >> n;
scanf("%d",&n);
//cout<<"n = "<<n<<"\n";
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 323
g.resize(n);
for(int i = 0; i < n; i++)
{
cin >> g[i];
if(g[i] < 1)
{
cerr << "Invalid rank " << g[i] << " at index " << i << endl;
exit(0);
}
}
auto t2 = clock();
auto t3 = clock();
cout << res << endl << "Query count: " << query_count << endl;
auto t4 = clock();
return 0;
}
/*
res = 111111 Query count = 555
t2-t1 = 0.244
t3-t2 = 0.082
t4-t3 = 0
#include <iostream>
#include <vector>
#include <algorithm>
#include<ctime>
#include <string>
static int n;
static int query_count = 0;
static vector<int> g;
static vector<vector<int> > rank_count;
#define fi first
#define se second
#define ryan bear
int N;
set<pair<int, pii> > S[10];
int val[10], tp;
int f(int v)
{
for (int i=0; i<tp; i++) if (val[i]==v) return i;
val[tp]=v; return tp++;
}
int md=(s+e)/2;
if (chk[md]) return ;
chk[md]=1;
vim res=ask(md);
ar[md]=res[0]+res[1];
if (res[0]==0&&res[1]==0)
{
ans=md;
fl=1;
return ;
}
int ind=f(ar[md]);
S[ind].insert({md, make_pair(res[0], res[1])});
int find_best(int n)
{
N=n;
myfind(0, n-1);
return ans;
}
vector<int> ask(int i)
{
query_count++;
if(query_count > max_q)
{
cerr << "Query limit exceeded" << endl;
exit(0);
}
vector<int> res(2);
res[0] = rank_count[g[i] - 1][i + 1];
res[1] = rank_count[g[i] - 1][n] - res[0];
return res;
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
//cin >> n;
scanf("%d",&n);
//cout<<"n = "<<n<<"\n";
g.resize(n);
for(int i = 0; i < n; i++)
{
cin >> g[i];
if(g[i] < 1)
{
cerr << "Invalid rank " << g[i] << " at index " << i << endl;
exit(0);
}
}
auto t2 = clock();
auto t3 = clock();
cout << res << endl << "Query count: " << query_count << endl;
auto t4 = clock();
return 0;
}
/*
res = 111111 Query count = 85
t2-t1 = 0.258
t3-t2 = 0.071
t4-t3 = 0
#include <iostream>
#include <vector>
#include <algorithm>
#include<ctime>
#include <string>
static int solve(int l, int r, int numl, int numr, int mx)
{
if(l > r) return -1;
int mid = (l + r) / 2;
return ans;
}
int find_best(int n)
{
srand(time(NULL));
vector<int> ask(int i)
{
query_count++;
if(query_count > max_q)
{
cerr << "Query limit exceeded" << endl;
exit(0);
}
vector<int> res(2);
res[0] = rank_count[g[i] - 1][i + 1];
res[1] = rank_count[g[i] - 1][n] - res[0];
return res;
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
//cin >> n;
scanf("%d",&n);
//cout<<"n = "<<n<<"\n";
g.resize(n);
for(int i = 0; i < n; i++)
{
cin >> g[i];
if(g[i] < 1)
{
cerr << "Invalid rank " << g[i] << " at index " << i << endl;
exit(0);
}
}
auto t2 = clock();
auto t3 = clock();
cout << res << endl << "Query count: " << query_count << endl;
auto t4 = clock();
return 0;
}
/*
res = 111111 Query count = 324
t2-t1 = 0.253
t3-t2 = 0.074
t4-t3 = 0
#include <iostream>
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 329
#include <vector>
#include <algorithm>
#include<ctime>
#include <string>
if (tot == 0) {return(mid);}
else if (l == r) {return(-1);}
int find_best(int n)
{
return(slv(0, n-1));
}
vector<int> ask(int i)
{
query_count++;
if(query_count > max_q)
{
cerr << "Query limit exceeded" << endl;
exit(0);
}
vector<int> res(2);
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 330
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
//cin >> n;
scanf("%d",&n);
//cout<<"n = "<<n<<"\n";
g.resize(n);
for(int i = 0; i < n; i++)
{
cin >> g[i];
if(g[i] < 1)
{
cerr << "Invalid rank " << g[i] << " at index " << i << endl;
exit(0);
}
}
auto t2 = clock();
auto t3 = clock();
cout << res << endl << "Query count: " << query_count << endl;
auto t4 = clock();
return 0;
}
/*
res = 111111 Query count = 85
t2-t1 = 0.321
t3-t2 = 0.083
t4-t3 = 0
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 331
#include <iostream>
#include <vector>
#include <algorithm>
#include<ctime>
#include <string>
#include <bits/stdc++.h>
vector<int> query(int i)
{
vector<int> res;
if (memo.count(i))
{
res.emplace_back(memo[i].first);
res.emplace_back(memo[i].second);
}
else
{
res = ask(i);
memo[i] = {res[0], res[1]};
}
return res;
}
int numValuable;
vector<int> candidates; // non-lollipop boxes
int find_best(int n)
{
numValuable = 0;
for (int i = 0; i < min(n, 500); i++)
{ // least valuable box must satisfy sumˆ2 <= n,
// and since n <= 200000 then sum <= 500 will suffice
vector<int> res = query(i);
if (res[0] + res[1] > numValuable)
{
numValuable = res[0] + res[1];
}
binarySearch(0, 0, 0, n - 1);
return ans;
}
vector<int> ask(int i)
{
query_count++;
if(query_count > max_q)
{
cerr << "Query limit exceeded" << endl;
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 333
exit(0);
}
vector<int> res(2);
res[0] = rank_count[g[i] - 1][i + 1];
res[1] = rank_count[g[i] - 1][n] - res[0];
return res;
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
//cin >> n;
scanf("%d",&n);
//cout<<"n = "<<n<<"\n";
g.resize(n);
for(int i = 0; i < n; i++)
{
cin >> g[i];
if(g[i] < 1)
{
cerr << "Invalid rank " << g[i] << " at index " << i << endl;
exit(0);
}
}
auto t2 = clock();
auto t3 = clock();
cout << res << endl << "Query count: " << query_count << endl;
auto t4 = clock();
return 0;
}
/*
res = 111111 Query count = 624
t2-t1 = 0.247
t3-t2 = 0.071
t4-t3 = 0
#include <iostream>
#include <vector>
#include <algorithm>
#include<ctime>
#include <string>
#define PB push_back
int get_L(int i)
{
if(L[i] != -1) return L[i];
vi res = ask(i);
L[i] = res[0], R[i] = res[1];
return L[i];
}
int get_R(int i)
{
if(L[i] != -1) return R[i];
vi res = ask(i);
L[i] = res[0], R[i] = res[1];
return R[i];
}
int loli;
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 335
vi svi;
if(l == r) return;
if(get_L(r) + get_R(r) < loli)
{
svi.PB(r);
solve(l, r - 1);
return;
}
int find_best(int n)
{
memset(L, -1, sizeof(L));
svi.clear();
loli = 0;
for(int i = 0;i < 100;i++)
{
int x = (rand() + rand()) % n;
x = (x % n + n) % n;
loli = max(loli, get_L(x) + get_R(x));
}
solve(0, n - 1);
for(int x : svi)
{
if(get_L(x) + get_R(x) == 0)
return x;
}
return 0;
}
vector<int> ask(int i)
{
query_count++;
if(query_count > max_q)
{
cerr << "Query limit exceeded" << endl;
exit(0);
}
vector<int> res(2);
res[0] = rank_count[g[i] - 1][i + 1];
res[1] = rank_count[g[i] - 1][n] - res[0];
return res;
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
//cin >> n;
scanf("%d",&n);
//cout<<"n = "<<n<<"\n";
g.resize(n);
for(int i = 0; i < n; i++)
{
cin >> g[i];
if(g[i] < 1)
{
cerr << "Invalid rank " << g[i] << " at index " << i << endl;
exit(0);
}
}
auto t2 = clock();
auto t3 = clock();
cout << res << endl << "Query count: " << query_count << endl;
auto t4 = clock();
return 0;
}
/*
res = 111111 Query count = 223
t2-t1 = 0.246
t3-t2 = 0.075
t4-t3 = 0
#include <iostream>
#include <vector>
#include <algorithm>
#include<ctime>
#include <string>
#include<bits/stdc++.h>
//#include "prize.h"
#define god dimasi5eks
#pragma GCC optimize("O3")
#define fi first
#define se second
#define pb push_back
#define pf push_front
// #define fisier 1
int ans;
map<int, pair<int, int> > m[200002];
if(sum == 0)
{
ans = mid;
return;
}
auto it = m[sum].upper_bound(mid);
bool L = 1, R = 1;
if(it != m[sum].begin())
{
it--;
if(cur.se == it -> se.se)
L = 0;
it++;
}
if(it != m[sum].end())
{
if(cur.se == it -> se.se)
R = 0;
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 338
m[sum][mid] = cur;
if(L)
solve(st, mid - 1);
if(R)
solve(mid + 1, dr);
}
int find_best(int n)
{
ans = -1;
solve(0, n - 1);
return ans;
}
vector<int> ask(int i)
{
query_count++;
if(query_count > max_q)
{
cerr << "Query limit exceeded" << endl;
exit(0);
}
vector<int> res(2);
res[0] = rank_count[g[i] - 1][i + 1];
res[1] = rank_count[g[i] - 1][n] - res[0];
return res;
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
//cin >> n;
scanf("%d",&n);
//cout<<"n = "<<n<<"\n";
g.resize(n);
for(int i = 0; i < n; i++)
{
cin >> g[i];
if(g[i] < 1)
{
cerr << "Invalid rank " << g[i] << " at index " << i << endl;
exit(0);
}
}
auto t2 = clock();
rank_count[r][i]++;
}
}
auto t3 = clock();
cout << res << endl << "Query count: " << query_count << endl;
auto t4 = clock();
return 0;
}
/*
res = 111111 Query count = 98
t2-t1 = 0.241
t3-t2 = 0.051
t4-t3 = 0
#include <iostream>
#include <vector>
#include <algorithm>
#include<ctime>
#include <string>
#include<bits/stdc++.h>
//#include "prize.h"
#define MID ((l+r)/2)
#define F first
#define S second
ii mem[1000000];
bool used[1000000];
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 340
set<int> s[10000000];
ii q(int x)
{
if(used[x]) return mem[x];
used[x] = true;
vi a = ask(x);
mem[x] = ii(a[0],a[1]);
return mem[x];
}
int N;
int mina=0;
int rec(int l=0, int r=N-1)
{
if(l>r) return -1;
ii a = q(MID);
if(a.F+a.S==0) return MID;
int find_best(int n)
{
N = n;
int l=0, r=n-1;
int m;
int pos=0;
return rec();
}
vector<int> ask(int i)
{
query_count++;
if(query_count > max_q)
{
cerr << "Query limit exceeded" << endl;
exit(0);
}
vector<int> res(2);
res[0] = rank_count[g[i] - 1][i + 1];
res[1] = rank_count[g[i] - 1][n] - res[0];
return res;
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
CAPITOLUL 3. IOI 2017 3.4. BIG PRIZE 341
cout<<s<<"\n";
//cin >> n;
scanf("%d",&n);
//cout<<"n = "<<n<<"\n";
g.resize(n);
for(int i = 0; i < n; i++)
{
cin >> g[i];
if(g[i] < 1)
{
cerr << "Invalid rank " << g[i] << " at index " << i << endl;
exit(0);
}
}
auto t2 = clock();
auto t3 = clock();
cout << res << endl << "Query count: " << query_count << endl;
auto t4 = clock();
return 0;
}
/*
res = 111111 Query count = 98
t2-t1 = 0.239
t3-t2 = 0.073
t4-t3 = 0
3.5 Simurgh
Problema 5 - Simurgh 100 de puncte
O legendă veche din Shahnameh spune că Zal, legendarul erou persan s-a ı̂ndrăgostit de
Rubada, prinţesa de Kabul. Când Zal a cerut-o pe Rubada ı̂n căsătorie, tatăl ei i-a cerut să
ı̂ndeplinească mai ı̂ntâi o misiune.
În Persia sunt n oraşe marcate de la 0 la n 1, şi m drumuri bidirecţionale marcate de la 0
la m 1. Fiecare drum conectează o pereche de oraşe distincte. Fiecare pereche de oraşe este
conectată cu cel mult un drum. Unele drumuri sunt drumuri regale folosite ı̂n călătorii de către
familia regală. Zal trebuie să determine drumurile care sunt drumuri regale.
Zal are o hartă cu toate oraşele şi drumurile din Persia. El nu ştie care sunt drumurile regale,
dar poate apela la ajutorul lui Simurgh, o pasăre binevoitoare mitică - protectoarea lui Zal. Totuşi,
Simurgh nu vrea să ı̂i dezvăluie lui Zal setul de drumuri regale ı̂n mod direct. ı̂n schimb, pasărea
i-a şoptit lui Zal că setul de drumuri regale formează un set de aur. Un set de drumuri este un
set de aur, dacă şi numai dacă:
Mai mult, Zal poate adresa lui Simurgh unele ı̂ntrebări. Pentru fiecare ı̂ntrebare:
Programul vostru trebuie să-l ajute pe Zal să găsească setul de drumuri regale, adresându-i lui
Simurgh cel mult q ı̂ntrebări. Evaluatorul va juca rolul lui Simurgh.
Detalii de implementare
Trebuie să implementaţi următoarea procedură:
a n: numărul de oraşe,
a u şi v: şiruri de lungime m. Pentru toate 0 & i & m 1, ui şi v i sunt oraşele conectate
de drumul i.
a Procedura trebuie să returneze un şir de lungime n 1 conţinând indicii drumurilor regale
(ı̂n ordine arbitrară).
Soluţia voastră poate efectua cel mult q apeluri către următoarea procedură a evaluatorului:
int count_common_roads(int[] r)
a r: un şir de lungime n 1 conţinând indicii drumurilor din setul de aur (ı̂n ordine arbitrară).
a Această procedură returnează numărul de drumuri regale ı̂n r.
Exemplu
În acest exemplu sunt 4 oraşe şi 6 drumuri. Notăm prin a, b drumul care conectează oraşele
a şi b. Drumurile sunt numerotate de la 0 la 5 ı̂n ordinea următoare: (0,1), (0,2), (0,3), (1,2),
(1,3) şi (2,3). Fiecare set de aur conţine n 1 3 drumuri.
Fie setul regal format din drumurile cu indicii 0, 1, şi 5, adică drumurile care conectează oraşele
(0,1), (0,2), şi (2,3). Atunci:
Procedura find_roads ar trebui să returneze [5, 1, 0] sau oricare alt şir de lungime 3 care
va conţine aceste trei elemente.
De remarcat, că următoarele apeluri nu sunt permise:
drumurilor regale ı̂n şirul r. Cu toate acestea, ı̂n cazul ı̂n care programul submitat apelează
count_common_roads cu un set de indici care nu descriu un set de aur, verdictul graderului va
fi ’Wrong Answer’.
Observaţie tehnică
Procedura count_common_roads ı̂n C++ şi Pascal foloseşte metoda pass by reference din
considerente de eficienţă. Puteţi apela procedura ı̂n modul obişnuit. Se garantează că evaluatorul
nu va modifica valoarea r.
Timp maxim de executare/test: 3.0 secunde
Memorie: total 1024 MB
Given a graph G with n vertices and m edges. Zal has selected a spanning tree of the graph
but you don’t know which edges appear in his spanning tree. In every query, you can give him a
spanning tree of the graph and he’ll tell you how many edges your spanning tree has in common
with his. Your wish to find his spanning tree with a small number of queries.
Subtask 1
Iterate over all spanning trees and try all of them.
Subtask 2
start with an arbitrary spanning tree t and keep improving your solution as follows:
- randomly choose an edge e
- add the edge to your solution
- remove a random edge from the cycle of t < e to make it a tree t
- if t has more edges in common with Zal’s tree then set t t
- stop if t is Zal’s tree
Subtask 3
Exactly one query per edge. Decompose your graph into a number of disjoint (or almost
disjoint) cycles. For each cycle C, find a tree t that connects C to all vertices of the graph (C < t
is a spanning tree with an extra edge). For ech e " C, determine the number of edges that C < te
has in common with Zal’s tree. If all these numbers are equal, then none of the edges of C appear
in Zal’s tree. Otherwise, the edges whose removal decrease the number of common edges are in
Zal’s tree.
Subtask 4
One can determine with 3 queries whether an edge e appears in Zal’s tree; It only suffices
to find 2 other edges that make a triangle together with e and do as mentioned earlier. Fix an
arbitrary tree t and find out which of its edges appear in Zal’s tree. Once we find that, for every
forest F of G we can determine how many edge F shares with Zal’s tree with a single query; add
some of the edges of t to F to make it a spanning tree, query that tree, and determine how many
edges of F are in common with Zal’s tree. Determine the degree of each vertex in Zal’s tree with
n queries. Then every time we find the incident edge of a leaf with log n queries and remove
that edge from the solution. We continue on with the new edges.
Subtask 5
The same as previous subtask. The only difference is that finding a tree and determining which
of its edges appear in Zal’s tree is a bit harder. Roughly speaking, we need to remove the cut
edges (which we know are included in Zal’s tree). Then every component is a 2-edge-connected
graph and we can find an ear-decomposition for them. Note that for every cycle C we can figure
out with ¶C ¶ querier which edges of C are in Zal’s tree. The only extension that we need to that
is that if we already know the status of k edges of C, we can do this with ¶C ¶ k 1 queris.
Therefore, we can solve the problem for each component separately with at most 2n quires.
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 345
#include "simurgh.h"
#include <cstdio>
#include <cassert>
#include <vector>
#include <cstdlib>
#include <string>
#include<ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <cmath>
#include <cstring>
#define Foreach(i, c) \
for(__typeof((c).begin()) i = (c).begin(); i != (c).end(); ++i)
#define For(i,a,b) for(int (i)=(a);(i) < (b); ++(i))
#define rof(i,a,b) for(int (i)=(a);(i) > (b); --(i))
#define rep(i, c) for(auto &(i) : (c))
#define x first
#define y second
#define pb push_back
#define PB pop_back()
#define iOS ios_base::sync_with_stdio(false)
#define sqr(a) (((a) * (a)))
#define all(a) a.begin() , a.end()
#define error(x) cerr << #x << " = " << (x) <<endl
#define Error(a,b) \
cerr<<"( "<<#a<<" , "<<#b<<" ) = ( "<<(a)<<" , "<<(b)<<" )\n";
#define errop(a) cerr<<#a<<" = ( "<<((a).x)<<" , "<<((a).y)<<" )\n";
#define coud(a,b) cout<<fixed << setprecision((b)) << (a)
#define L(x) ((x)<<1)
#define R(x) (((x)<<1)+1)
#define umap unordered_map
#define double long double
vi __edges_vec;
vi adj[maxn];
pii edges[maxm];
bool bit[maxm];
int _next_ = 1;
int _last_id[maxm];
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 346
vector<int> ANS;
if(˜p)
toggle(ind[v][p]);
}
while(cur != x)
{
if(state[cur] == -1 or for_a_one == -1)
{
int cur_edge = ind[cur][par[cur]];
toggle(cur_edge);
last_num[cur_edge] = query();
sminmax(mn, mx, last_num[cur_edge]);
if(˜state[cur])
for_a_one = last_num[cur_edge] - (!state[cur]);
toggle(cur_edge);
}
cur = par[cur];
}
toggle(back_edge);
cur = y;
while(cur != x)
{
if(state[cur] == -1)
{
int cur_edge = ind[cur][par[cur]];
if(˜for_a_one)
state[cur] = last_num[cur_edge] == for_a_one;
else if(mn == mx)
state[cur] = 0;
else
state[cur] = last_num[cur_edge] == mn;
}
cur = par[cur];
}
}
}
vi tree, ans;
rep(e, subset)
merge(e);
rep(e, tree)
if(merge(e))
sum += edge_state(e);
return query() - sum;
}
int e = ed[l];
int u = edges[e].x + edges[e].y - v;
ans.pb(e);
-- deg[u];
mark[v] = true;
if(deg[u] == 1)
remove(u);
}
vi find_roads(int n, vi v, vi u)
{
::n = n;
::m = v.size();;
memset(state, -1, sizeof state);
memset(ind, -1, sizeof ind);
For(i,0,m)
{
edges[i] = {v[i], u[i]};
ind[v[i]][u[i]] = ind[u[i]][v[i]] = i;
adj[v[i]].pb(u[i]), adj[u[i]].pb(v[i]);
}
dfs();
DFS();
static int q = 0;
//static int n, m, q = 0;
static vector<int> u, v;
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 349
return true;
}
int common = 0;
for(int i = 0; i < n - 1; i++)
{
bool is_common = goal[r[i]];
if (is_common)
common++;
}
return common;
}
wrong_answer();
return _count_common_roads_internal(r);
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
u.resize(m);
v.resize(m);
goal.resize(m, false);
goal[id] = true;
}
auto t2 = clock();
auto t3 = clock();
if(_count_common_roads_internal(res) != n - 1) wrong_answer();
//printf("YES\n");
printf("YES q = %d\n\n",q);
auto t4 = clock();
return 0;
}
/*
wrslcnopzlckvxbnair_input_simurgh_lmncvpisadngpiqdfngslcnvd
m=124750 n=500
MAX_Q = 12000
YES q = 4794
t2-t1 = 0.297
t3-t2 = 1.109
t4-t3 = 0
#include <cstdio>
#include <cassert>
#include <vector>
#include <cstdlib>
#include <string>
#include<ctime>
#include<iostream>
#include <algorithm>
struct road
{
int i, x;
};
int n, m;
const int MAXM = 500 * 499 / 2;
vector<road> edge[500];
pi es[MAXM];
bool dfsTree[MAXM];
bool backGraph[MAXM];
vector<int> dfsQ;
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 351
int par[500];
int parEdge[500];
int dep[500];
int back[500];
int backEdge[500];
int ord = 0, base;
int royal[MAXM];
int sub[500];
int uf[500];
dfsTree[i.i] = true;
dfsQ.push_back(i.i);
par[i.x] = x;
parEdge[i.x] = i.i;
dfs(i.x, x);
if (back[i.x] == dep[i.x])
royal[i.i] = 1;
else
if (back[i.x] < back[x])
{
back[x] = back[i.x];
backEdge[x] = backEdge[i.x];
}
}
int find(int x)
{
if (uf[x] != x) return uf[x] = find(uf[x]);
return x;
}
if (merge(es[i].first, es[i].second))
{
qs.push_back(i);
if (royal[i] == 1) ++other;
}
}
vector<int> qs;
int m = (s + e) / 2;
for (int i = s; i <= m; ++i) qs.push_back(vt[i]);
int d = question(qs);
bsearch(vt, s, m, d);
bsearch(vt, m + 1, e, c - d);
}
dfs(0, -1);
base = count_common_roads(dfsQ);
vector<pi> es;
for (int i = 0; i < m; ++i)
{
if (backGraph[i]) es.push_back(pi(min(dep[u[i]], dep[v[i]]), i));
}
sort(es.begin(), es.end());
else
allZero = false;
j = par[j];
}
vector<int> qs;
for (int k : dfsQ)
{
if (k != parEdge[j]) qs.push_back(k);
}
qs.push_back(i.second);
sub[j] = count_common_roads(qs) - base;
if (royal[parEdge[j]] != 0)
{
allZero = false;
royal[i.second] = royal[parEdge[j]] + 2 * sub[j];
}
else
if (sub[j] != 0)
{
allZero = false;
royal[parEdge[j]] = -sub[j];
royal[i.second] = sub[j];
}
if (allZero)
{
j = s;
while (j != e)
{
royal[parEdge[j]] = -1;
j = par[j];
}
royal[i.second] = -1;
continue;
}
j = s;
while (j != e)
{
if (royal[parEdge[j]] == 0)
royal[parEdge[j]] = royal[i.second] - 2 * sub[j];
j = par[j];
}
}
vector<int> ret;
for (int i = 0; i < m; ++i)
{
if (royal[i] == 1) ret.push_back(i);
}
return ret;
}
static int q = 0;
//static int n, m, q = 0;
static vector<int> u, v;
static vector<bool> goal;
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 354
return true;
}
int common = 0;
for(int i = 0; i < n - 1; i++)
{
bool is_common = goal[r[i]];
if (is_common)
common++;
}
return common;
}
wrong_answer();
return _count_common_roads_internal(r);
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
u.resize(m);
v.resize(m);
goal.resize(m, false);
auto t2 = clock();
auto t3 = clock();
if(_count_common_roads_internal(res) != n - 1) wrong_answer();
//printf("YES\n");
printf("YES q = %d\n\n",q);
auto t4 = clock();
return 0;
}
/*
wrslcnopzlckvxbnair_input_simurgh_lmncvpisadngpiqdfngslcnvd
m=124750 n=500
MAX_Q = 12000
YES q = 2536
t2-t1 = 0.406
t3-t2 = 0.39
t4-t3 = 0
#include<ctime>
#include<bits/stdc++.h>
int n,m;
pii e[maxm];
int head[maxn];
vector<pii> way[maxn], edge[maxn];
int ban[maxm], res[maxm];
vector<int> tree;
vector<int> p;
int cut[maxm];
int ask_count;
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 356
int findhead(int x)
{
if(x==head[x]) return x;
return head[x] = findhead(head[x]);
}
for(auto id : tree)
{
int u = e[id].X, v = e[id].Y;
if(findhead(u)!=findhead(v))
{
head[findhead(u)] = findhead(v);
vec.push_back(id);
val -= res[id];
}
}
ask_count++;
if(ask_count > 8000) assert(0);
val += count_common_roads(vec);
return val;
}
dfs(0,-1,-1);
p.clear();
lca(u,v);
int good = 0;
for(auto id : p) if(res[id]==-1) good = 1;
if(!good) continue;
int x = -1;
for(auto id : p) if(res[id]!=-1) x = id;
if(x==-1)
{
for(auto id : p) cut[id] = ask(id,wow);
for(auto id : p) if(cut[id] - ori == 1) res[wow] = 1;
for(auto id : p) res[id] = ori - cut[id] + res[wow];
}
else
{
res[wow] = ask(x,wow) - ori + res[x];
for(auto id : p)
if(res[id]==-1)
res[id] = ori - ask(id,wow) + res[wow];
}
}
for(int i=0;i<m;i++)
{
if(res[i] == -1) res[i] = 1;
}
for(int x=0;x<n;x++)
{
for(int ext=get(x,0,edge[x].size()-1);ext>0;ext--)
{
int l = 0, r = edge[x].size()-1, mid, pos = -1;
while(l<=r)
{
mid = (l+r)/2;
if(get(x,0,mid) >= 1)
{
pos = edge[x][mid].Y;
r = mid-1;
}
else l = mid+1;
}
if(pos==-1) break;
res[pos] = 1;
}
}
vector<int> ans;
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 358
for(int i=0;i<m;i++)
if(res[i])
ans.push_back(i);
return ans;
}
static int q = 0;
//static int n, m, q = 0;
static vector<int> u, v;
static vector<bool> goal;
return true;
}
int common = 0;
for(int i = 0; i < n - 1; i++)
{
bool is_common = goal[r[i]];
if (is_common)
common++;
}
return common;
}
wrong_answer();
return _count_common_roads_internal(r);
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
u.resize(m);
v.resize(m);
goal.resize(m, false);
auto t2 = clock();
auto t3 = clock();
if(_count_common_roads_internal(res) != n - 1) wrong_answer();
//printf("YES\n");
printf("YES q = %d\n\n",q);
auto t4 = clock();
return 0;
}
/*
wrslcnopzlckvxbnair_input_simurgh_lmncvpisadngpiqdfngslcnvd
m=124750 n=500
MAX_Q = 12000
YES q = 5685
t2-t1 = 0.39
t3-t2 = 1.235
t4-t3 = 0
#include <bits/stdc++.h>
int n, m;
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 360
int tick;
pii disc[N], low[N];
void dfs(int u, int p)
{
disc[u] = low[u] = pii(++tick, -1);
for (auto v : G[u])
{
if (!disc[v.F].F)
{
// push edge to tree
is_tree[v.S] = true;
T.push_back(v.S);
GT[u].emplace_back(v.F, v.S);
GT[v.F].emplace_back(u, v.S);
// tarjan’s algorithm
dfs(v.F, u);
low[u] = min(low[u], low[v.F]);
if (low[v.F].F > disc[u].F)
ans[v.S] = 1;
}
else
if (v.F != p)
{
low[u] = min(low[u], pii(disc[v.F].F, v.S));
}
}
}
if (fnd != -1)
{ // case where we can quickly determine ce’s value
ans[ce] = ans[fnd] + get_changes(fnd, ce);
for (auto e : path)
{ // update other edge in path we don’t know
if (ans[e] == -1)
ans[e] = ans[ce] - get_changes(e, ce);
}
}
else
{ // don’t know, so query everything in the cycle
for (auto e : path)
{
int d = get_changes(e, ce);
if (d == 1)
ans[ce] = 1, ans[e] = 0;
else if (d == -1)
ans[ce] = 0, ans[e] = 1;
}
int par[N];
int root(int u)
{
if (par[u] == u) return u;
return par[u] = root(par[u]);
}
vector<int> q;
for (auto e : adj)
{
if (merge(U[e], V[e]))
q.push_back(e);
}
int cnt = 0;
for (auto e : T)
{
if (merge(U[e], V[e]))
{
cnt += ans[e];
q.push_back(e);
}
}
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 362
if (cnt == adj.size())
{
for (auto e : adj)
ans[e] = 1;
return;
}
// return answer
vector<int> ret;
for (int i = 0; i < m; ++i)
{
if (ans[i])
ret.push_back(i);
}
return ret;
}
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 363
static int q = 0;
//static int n, m, q = 0;
static vector<int> u, v;
static vector<bool> goal;
return true;
}
int common = 0;
for(int i = 0; i < n - 1; i++)
{
bool is_common = goal[r[i]];
if (is_common)
common++;
}
return common;
}
wrong_answer();
return _count_common_roads_internal(r);
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
u.resize(m);
v.resize(m);
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 364
goal.resize(m, false);
auto t2 = clock();
auto t3 = clock();
if(_count_common_roads_internal(res) != n - 1) wrong_answer();
//printf("YES\n");
printf("YES q = %d\n\n",q);
auto t4 = clock();
return 0;
}
/*
wrslcnopzlckvxbnair_input_simurgh_lmncvpisadngpiqdfngslcnvd
m=124750 n=500
MAX_Q = 12000
YES q = 2541
t2-t1 = 0.343
t3-t2 = 0.422
t4-t3 = 0.016
#include "simurgh.h"
#include <bits/stdc++.h>
#define pb push_back
#define MP make_pair
#define F first
#define S second
vector<int> U,V;
vector<pii> G[505];
pii pa[505];
queue<int> q;
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 365
int type[505],dep[505],deg[505],boss[505],n;
set<int> s;
bitset<505> vis,ed;
bitset<250000> used;
int ccr()
{
return count_common_roads(vector<int>(s.begin(),s.end()));
}
int finds(int x)
{
if(x==boss[x]) return x;
return boss[x]=finds(boss[x]);
}
int ccr_forest(vector<int> f)
{
int cnt=0;
for(int i=0;i<n;++i)
boss[i]=i;
set<int> tmp;
for(int i:f)
tmp.insert(i),Union(U[i],V[i]);
for(int i=1;i<n;++i)
if(Union(i,pa[i].F))
cnt+=type[i],tmp.insert(pa[i].S);
tmp.swap(s),cnt=ccr()-cnt,tmp.swap(s);
return cnt;
}
int leaf_finding(int u)
{
vector<int> candi;
for(pii i:G[u])
if(!ed[i.F])
candi.pb(i.S);
int l=0,r=candi.size()-1;
while(l<r)
{
vector<int> v;
int m=l+r>>1;
for(int i=l;i<=m;++i)
v.pb(candi[i]);
if(ccr_forest(v)>=1) r=m;
else l=m+1;
}
return candi[l];
}
dfs(0,-1,-1,0),fill(type,type+N,-1);
int cur=ccr();
for(int i=0;i<u.size();++i)
{
if(used[i]) continue;
int cnt=0,sz=0,tp=-1,a=u[i],b=v[i];
pii sw;
while(a!=b)
{
if(dep[a]<dep[b]) swap(a,b);
if(˜type[a]) sw=MP(pa[a].S,type[a]);
cnt+=!˜type[a],++sz,a=pa[a].F;
}
if(!cnt) continue;
a=u[i],b=v[i];
if(cnt==sz)
{
vector<int> v;
while(a!=b)
{
if(dep[a]<dep[b]) swap(a,b);
s.erase(pa[a].S),s.insert(i);
int tmp=ccr();
if(tmp==cur) v.pb(a);
else
{
if(tmp>cur) tp=1,type[a]=0;
else tp=0,type[a]=1;
for(int j:v)
type[j]=tp;
s.erase(i),s.insert(pa[a].S),a=pa[a].F;
break;
}
s.erase(i),s.insert(pa[a].S),a=pa[a].F;
}
if(a==b&&!˜tp)
for(int j:v)
type[j]=0;
}
else
s.erase(sw.F),
s.insert(i),
tp=(sw.S==0)ˆ(ccr()==cur),
s.erase(i),
s.insert(sw.F);
while(a!=b)
{
if(dep[a]<dep[b]) swap(a,b);
s.erase(pa[a].S),s.insert(i);
if(!˜type[a])
type[a]=tpˆ(ccr()!=cur);
s.erase(i),s.insert(pa[a].S),a=pa[a].F;
}
}
for(int i=1;i<n;++i)
if(!˜type[i]) type[i]=1;
for(int i=0;i<n;++i)
{
vector<int> v;
for(pii j:G[i])
v.pb(j.S);
deg[i]=ccr_forest(v);
if(deg[i]==1)
q.push(i);
}
while(q.size()>1)
{
int u=q.front();
q.pop(),
ed[u]=1,
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 367
ans.pb(leaf_finding(u)),
uˆ=U[ans.back()]ˆV[ans.back()];
if(--deg[u]==1)
q.push(u);
}
return ans;
}
static vector<int> u, v;
static vector<bool> goal;
return true;
}
int common = 0;
for(int i = 0; i < n - 1; i++)
{
bool is_common = goal[r[i]];
if (is_common)
common++;
}
return common;
}
wrong_answer();
return _count_common_roads_internal(r);
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
cout<<"m="<<m<<" n="<<n<<"\n";
u.resize(m);
v.resize(m);
goal.resize(m, false);
auto t2 = clock();
auto t3 = clock();
if(_count_common_roads_internal(res) != n - 1) wrong_answer();
//printf("YES\n");
printf("YES qq = %d\n\n",qq);
auto t4 = clock();
return 0;
}
/*
wrslcnopzlckvxbnair_input_simurgh_lmncvpisadngpiqdfngslcnvd
m=124750 n=500
MAX_Q = 12000
YES qq = 4800
t2-t1 = 0.312
t3-t2 = 4.481
t4-t3 = 0
#include<bits/stdc++.h>
void plant(int v)
{
visited[v] = 1;
for(auto e : adj[v])
{
int u = from[e] ˆ to[e] ˆ v;
if(!visited[u])
{
ind.pb(e);
h[u] = h[v] + 1;
par[u] = e;
tree[e] = 1;
plant(u);
}
else if(h[u] < h[v] - 1)
bc[v].pb(e);
}
}
return nw;
}
return x > y;
}
int wtf[maxm];
vector<int> shit;
for(int i = 0; i < sz; i++)
{
int e = bc[i];
tree[wtf[e]] = 0;
shit.pb(e);
}
int ts = 0;
for(auto x : ind)
if(tree[x])
{
if(is[x] == 1)
ts++;
shit.pb(x);
}
void dfs(int v)
{
for(auto e : adj[v])
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 370
{
int u = from[e] ˆ to[e] ˆ v;
if(h[u] == h[v] + 1)
dfs(u);
}
if(bc[v].empty())
return;
int last = v;
is[bc[v][r - 1]] = 1;
stl = r;
st++;
}
adj[a].pb(i);
adj[b].pb(i);
from[i] = a , to[i] = b;
}
plant(0);
num = count_common_roads(ind);
for(int i = 0; i < m; i++)
if(!tree[i])
{
int v = from[i] , u = to[i];
if(h[v] < h[u])
swap(v , u);
vector<int> ed;
bool has0 = 0;
while(v != u)
{
if(is[par[v]] == 0)
has0 = 1;
ed.pb(par[v]);
v = from[par[v]] ˆ to[par[v]] ˆ v;
}
CAPITOLUL 3. IOI 2017 3.5. SIMURGH 371
if(!has0)
continue;
vector<int> eq;
for(auto e : ed)
{
if(is[e] != 0 && is[i] != 0)
continue;
if(nw == num)
{
if(is[e] != 0)
is[i] = is[e];
else
eq.pb(e);
}
else if(nw == num + 1)
{
is[i] = 1;
is[e] = -1;
}
else
{
is[e] = 1;
is[i] = -1;
}
}
if((int)eq.size() == (int)ed.size())
is[i] = -1;
for(auto e : eq)
is[e] = is[i];
}
for(auto x : ind)
if(is[x] == 0)
is[x] = 1;
dfs(0);
vector<int> ans;
for(int i = 0; i < m; i++)
{
if(!is[i])
is[i] = -1;
if(is[i] == 1)
ans.pb(i);
}
while(count_common_roads(ans) != n - 1);
return ans;
}
static int n, m, q = 0;
static vector<int> u, v;
static vector<bool> goal;
return true;
}
int common = 0;
for(int i = 0; i < n - 1; i++)
{
bool is_common = goal[r[i]];
if (is_common)
common++;
}
return common;
}
wrong_answer();
return _count_common_roads_internal(r);
}
int main()
{
auto t1 = clock();
string s;
getline (cin,s);
cout<<s<<"\n";
u.resize(m);
v.resize(m);
goal.resize(m, false);
auto t2 = clock();
auto t3 = clock();
if(_count_common_roads_internal(res) != n - 1) wrong_answer();
//printf("YES\n");
printf("YES q = %d\n\n",q);
auto t4 = clock();
return 0;
}
/*
wrslcnopzlckvxbnair_input_simurgh_lmncvpisadngpiqdfngslcnvd
m=124750 n=500
MAX_Q = 12000
YES q = 4637
t2-t1 = 0.437
t3-t2 = 2.274
t4-t3 = 0
Biblioteca Naţională a Iranului se află ı̂n Teheran. Atracţia principală a bibliotecii este local-
izată de-a lungul unui coridor ı̂n care se află n mese, numerotate de la 0 la n 1 de la stânga la
dreapta. Pe fiecare masă se află câte o carte antică scrisă de mână. Cărţile sunt ordonate după
vârsta lor, acest lucru ı̂ngreunându-i pe vizitatori să caute cărţile după titlu. Aşadar, administra-
torul bibliotecii a decis să sorteze cărţile ı̂n ordine alfabetică după titlu.
Aryan, un bibliotecar, este responsabil pentru această sarcină. El a creat o listă p de lungime
n, care conţine numere ı̂ntregi de la 0 la n 1, distincte două câte două. Această listă reprezintă
modificările necesare pentru rearanjarea cărţilor ı̂n ordine alfabetică: pentru fiecare 0 & i $ n,
cartea care se află ı̂n momentul curent pe masa i trebuie mutată pe masa pi.
Aryan ı̂ncepe sortarea cărţilor pornind de la masa s. După terminarea sortării cărţilor acesta
doreşte să se ı̂ntoarcă la această masă. Având ı̂n vedere valoarea cărţilor, el nu poate avea la el
mai mult de o carte ı̂n orice moment de timp. Cât timp Aryan sortează cărţile, el va efectua o
secvenţă de acţiuni. Fiecare acţiune este una din următoarele:
a Dacă nu are la el o carte şi dacă este o carte pe masa la care se află, el poate lua această
carte.
a Dacă are la el o carte şi o altă carte este pe masa la care se află, el poate interschimba cele
două cărţi.
a Dacă are la el o carte şi masa la care se află este goală, el poate pune pe masă cartea pe
care o are la el.
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 374
Pentru toate 0 & i, j & n 1, distanţa dintre mesele i şi j este de ¶j i¶ metri. Sarcina voastră
este de a-l ajuta pe Aryan să sorteze cărţile ı̂ntr-un mod ı̂n care distanţa totală parcursă de el să
fie minimă.
Detalii de implementare
Voi trebue să implementaţi următoarea procedură:
a p este un şir de lungime n. Cartea care se află la ı̂nceput pe masa i trebuie dusă de Aryan
pe masa pi (pentru toate 0 & i $ n).
a s reprezintă poziţia mesei de unde ı̂ncepe Aryan, şi unde trebuie să se afle după sortarea
cărţilor.
a Această procedură trebuie să returneze distanţa totală minimă (ı̂n metri) parcusă de Aryan.
Exemplu
minimum_walk([0, 2, 3, 1], 0)
În acest exemplu, n 4 şi Aryan se află iniţial la masa 0. El sortează cărţile după cum
urmează:
a Merge la masa 1 şi ia cartea de pe masă. Această carte trebuie să ajungă pe masa 2.
a Apoi, merge la masa 2 şi interschimbă cartea din mână cu cea de pe masă. Cartea nouă
trebuie să ajungă pe masa 3.
a Apoi, merge la masa 3 şi interschimbă cartea din mână cu cea de pe masă. Cartea nouă
trebuie să ajungă pe masa 1.
a Apoi, merge la masa 1 şi pune cartea ce o are la el pe această masă.
a În final, el se ı̂ntoarce la masa 0.
Se observă că pe masa 0 cartea se află pe poziţia corectă, deci Aryan nu trebuie să o mute.
Distanţa totală parcursă ı̂n această soluţie este de 6 metri. Aceasta este soluţia optimă; aşadar
procedura trebuie să returneze valoarea 6.
Restricţii şi precizări
a 1 & n & 1 000 000
a 0&s&n1
a şirul p conţine n numere ı̂ntregi distincte ı̂ntre 0 si n 1, inclusiv.
Subtask-uri
1. (12 puncte) n & 4 şi s 0
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 375
Example:
Balancing property. Across every edge of the underlying path graph, Mina will walk equally
often from left to right as she walks right to left. A similar balance also applies to the books. For
every edge of the path, there are equally many books that need to be moved from left to right as
there are from right to left.
Cycles of the permutation The array order specifies a permutation. We will denote that
permutation by π from here on. We will see, that the answer only depends on how π partitions the
set of slots r0, ..., n 1x into disjoint cycles. A book that is placed correctly from the beginning,
we call trivial. Their corresponding trivial cycles (cycles of length one) can almost be ignored, as
we will always just move past them.
Single cycle If π consists of a single cycle then the answer is easy to find: Mina can grab the
book at S, bring it to π S , take the book from there to π π S and so on until she returns to
S. As she brings one book on slot closer to its target position in every step, her walk surely is
optimal. We can compute this number of steps by
n1
d π = ¶i π i¶
i 0
which is exactly the sum of the distances between initial and target position of every book.
Lower bound d π The sum of distances d π is a lower bound on the answer even if π
consists of multiple cycles. We distinguish two kinds of steps for Mina: A step is called essential
if Mina brings one book one step closer to its target position than this book ever was before.
Otherwise the step is called non-essential. Every way of sorting the books consists of exactly d π
many essential steps. The number of non-essential steps needed depends on how the cycles of π
overlap.
Two cycles Every cycle of π covers some interval I of the bookshelf which extends from the
leftmost book to the rightmost book that are part of this cycle.
We have I N 0, n 1, where we use i, j as a shorthand for ri, i 1, ..., j 1, j x.
Let π consist of exactly two non-trivial cycles C1 and C2 with their respective intervals I1 ,
I2 and let S 0 wit S " C1 . Then the answer only depends on whether the cycles overlap
(I1 = I2 j Ø) or not. If they overlap, the answer is d π otherwise it is d π 2.
Why? If they overlap Mina can sort along C1 until she encounters the first book belonging
to C2 . She then leaves the book she was carrying at that slot to fully sort C2 and return to the
same slot. She can than pick up that book again and finish sorting C1 without ever spending a
non-essential step.
If the two cycles dont overlap (so C1 is entirely to the left of C2 ), Mina can do something
similar.
She starts sorting C1 until she encounters the rightmost slot belonging to C1 . She then takes
the book from there and non-essentially walks with one step to the right to the leftmost slot of
C2 . There, she sorts C2 and picks up the same book again to non-essentially walk back to C1 .
Finally, she finishes sorting C1 and returns to S. This is optimal since the only two non-
essential steps of Minas walk are spent across an edge that no book needs to cross but has to be
crossed by Mina eventually as there are non-trivial books on both sides.
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 377
Multiple cycles The two cases from before generalize to the case where consists of many
cycles. Any two overlapping cycles can be interleaved without non-essential steps and Mina has
to spend two non-essential steps across every edge that no book needs to cross but on both sides
¬
there are either some non-trivial books or S. More formally, let E be the subset of the edges of
the path with the following property:
e i, i 1 " E
¬
no book has to cross e and
some book to the left of e is non-trivial or at S and
some book to the right of e is non-trivial or at S and
Àj " 0, i π j % i 1 0 ¿ © j " i 1, n 1 π j & i and
¿l " 0, is.t. l j π l 1 l S and
¿r " i 1, n 1s.t. r j π r 1 r S
¬
If S 0, these are all the non-essential steps needed, so the answer is d π 2 ¶E ¶.
¬
Implementation With these observations, it is easy to compute both d π and ¶E ¶. If it
¬
is done in quadratic time (e.g. by just checking the above conditions for E by looping over all
indices for every edge), this will solve subtask 3 (see library_35.cpp for an implementation).
¬
However, it is not hard to compute E in linear time (e.g. in a scanline fashion from left to right),
which will then score for the first four subtasks (see library_50.cpp for an implementation).
We could try out both options and define the following subproblem:
How many non-essential steps do we need, if we already know how to connect all the cycles
in the interval l, r with S " l, r?
This gives rise to a dynamic programming formulation with a state of quadratic size (all intervals
containing S).
¬ ¬
For any given interval, we define the function extend l, r with l , r extend l, r being the
largest part of the shelf that we can sort without spending any additional non-essential steps. So
extend has to repeatedly add all cycles C whose interval I partially or fully overlap with l, r and
then continue with l, r l, r < I until no more cycles can extend the interval.
Once there is no other overlapping cycle (so l, r extend l, r), we are either done or we
know that we have to spend some non-essential steps.
Let combine l, r be the function that computes the cost of connecting all cycles to the interval
l, r .
We can recursively compute it using
We need to take care of the border cases (when l 1 or r 1 are outside the shelf) and initialize
¬ ¬ ¬ ¬
it with combine l , r 0 for l , r being the smallest interval that contains all non-trivial books
and S.
By implementing extend carefully, we can achieve an amortized constant time complexity
across all calls, so that the dynamic program runs in quadratic time overall. The code in the file
library_70.cpp implements this using memoization. Note that for S 0, the set of states is
only of linear size, so this solution also passes subtask 4.
To solve the problem in linear time, we note that we can decide whether to go left or right
somewhat locally without exploring quadratically many states. If l, r is some extended interval
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 378
33
(l, r extend l, r), we look for two special cycles Cl and Cr . Cl is the first S-containing cycle
that we encounter, when walking from l to the left. Similarly, Cr is the first S-containing cycle
when walking from r to the right.
Let cl be the cost of reaching Cl from l (and define cr ).
Note that cl is not just twice the distance between l and the closest book of Cl as there might be
some small cycles along the way that help us save some non-essential steps. But we can compute
cl quickly by solving the (S 0)-problem between l and the first box of Cl .
Observe that if Cl does not exist, Cr does also not exist (as l, r is maximally extended, the
book of Cl to right of S also has to be to the right of r and vice versa).
Also note that once we reach either Cl or Cr , we also reach Cl <Cr and therefore get extend Cl <
Cr without any further cost. This means that we can greadily decide for the cheaper of the two
sides (of cost min cl , cr ) and then continue with the interval extend Cl < Cr regardless of whether
we decided to go left or right.
Finally, one has to take care of the border region, everything outside of the outermost S-
containing cycles (so once Cl and/or Cr no longer exist). But this is easy, as this is just another
(S 0)-case on each side.
We can answer all the extend l, r calls and compute all the cl and cr costs using only one
overall sweep over the shelf (if we precompute the cycle of each shelf and the interval of each cycle,
which we can also do in O n). Therefore, we can find determine the answer d π combine S, S
in linear time. The code in the file library_100.cpp implements this optimal solution.
Overview
To summarize, here are the solution techniques listed per subtask:
#include <iostream>
#include <vector>
#include "books.h"
#include <cstdio>
#include <cassert>
#include <fstream>
33
A cycle C with interval I is S-containing if and only if S " I.
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 379
#include<ctime>
int val(int x)
{
return (x > 0 ? x : -x);
}
mark[v]++;
v = pos[v];
}
}
int gl = 0;
while (gl < s && p[gl] == gl)
gl++;
int gr = n - 1;
while (gr > s && p[gr] == gr)
gr--;
int l = s + 1, r = s;
go(l, r, s, s);
bool done = false;
while (gl < l || r < gr)
{
int nl = l, nr = r;
if (!done)
{
while (nl >= 0 && ri[nl] <= r)
nl--;
}
if (nl == -1)
done = true;
if (done)
{
nl = l;
if (l <= gl)
{
nr++;
ans += 2;
}
else
{
nl--;
ans += 2;
}
}
else
{
while (l <= le[nr])
nr++;
ans += min(dist(l - 1, nl), dist(r + 1, nr)) + 2;
}
go(l, r, nl, nr);
}
return ans;
}
int main()
{
auto t1 = clock();
string str;
getline (cin,str);
//cout<<str<<"\n";
int n, s;
assert(2 == scanf("%d %d", &n, &s));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 381
auto t4 = clock();
cout<<"res = "<<res<<"\n";
return 0;
}
/*
res = 3320522632
t2-t1 = 1.871 ... citire !!!
t3-t2 = 0.219
t4-t3 = 0
#include "books.h"
#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define st first
#define nd second
int H[N],T[N],A[N],B[N],n,i,j,l,r,ll,rr,t1,t2,t,a,b,lll,rrr;
long long x;
}
}
l = r = s;
a = A[s];
b = B[s];
relax(l,r,a,b);
t2 = 0;
if(r < j)
{
for(a = l, b = r ; lll == l && rrr < j ; )
{
rrr++;
t2++;
a = min(A[rrr],a);
b = max(B[rrr],b);
relax(lll,rrr,a,b);
}
if(l <= i) { t += t2; break; }
}
return x + t+t;
}
int main()
{
auto t1 = clock();
string str;
getline (cin,str);
//cout<<str<<"\n";
int n, s;
assert(2 == scanf("%d %d", &n, &s));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
cout<<"res = "<<res<<"\n";
return 0;
}
/*
res = 3320522632
t2-t1 = 1.703
t3-t2 = 0.172
t4-t3 = 0
#include <bits/stdc++.h>
#include "books.h"
int cl = s, cr = s;
queue<int> qu;
qu.push(s);
while (1)
{
while (qu.size())
{
int u = qu.front(); qu.pop();
while (cl > p[u])
{
cl--, qu.push(cl);
}
while (1)
{
if (l <= ml) break;
l--, dl++, ql.push(l);
while (ql.size())
{
int u = ql.front();
ql.pop();
while (l > p[u])
{
l--, ql.push(l);
}
if (p[u] > s) fl = 1;
}
if (fl) break;
}
while (1)
{
if (r >= mr) break;
r++, dr++, qr.push(r);
while (qr.size())
{
int u = qr.front();
qr.pop();
while (r < p[u])
{
r++, qr.push(r);
}
if (p[u] < s) fr = 1;
}
if (fr) break;
}
int main()
{
auto t1 = clock();
string str;
getline (cin,str);
//cout<<str<<"\n";
int n, s;
assert(2 == scanf("%d %d", &n, &s));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 385
auto t4 = clock();
cout<<"res = "<<res<<"\n";
return 0;
}
/*
res = 3320522632
t2-t1 = 1.687
t3-t2 = 0.391
t4-t3 = 0
#include <bits/stdc++.h>
#include "books.h"
{
int x = q.front();
q.pop();
if (p[x] > s)
{
found_l = true;
}
return ans;
}
int main()
{
auto t1 = clock();
string str;
getline (cin,str);
//cout<<str<<"\n";
int n, s;
assert(2 == scanf("%d %d", &n, &s));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
cout<<"res = "<<res<<"\n";
return 0;
}
/*
res = 3320522632
t2-t1 = 1.703
t3-t2 = 0.328
t4-t3 = 0
#include <bits/stdc++.h>
#pragma optimization("unroll-loops")
#pragma optimization("Ofast")
#pragma target("avx2")
if(s > R)
{
res += (s - R) << 1;
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 388
s = R;
}
if(s < L)
{
res += (L - s) << 1;
s = L;
}
l = r = s;
push(l, r, mn, mx, p);
int main()
{
auto t1 = clock();
string str;
getline (cin,str);
//cout<<str<<"\n";
int n, s;
assert(2 == scanf("%d %d", &n, &s));
auto t2 = clock();
auto t3 = clock();
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 389
printf("%lld\n", res);
auto t4 = clock();
cout<<"res = "<<res<<"\n";
return 0;
}
/*
res = 3320522632
t2-t1 = 1.703
t3-t2 = 0.125
t4-t3 = 0
#include <bits/stdc++.h>
#include "books.h"
int l = s, r = s;
while(x < l || r < y)
{
extend(l, r);
int al = l, ar = r;
int bl = l, br = r;
long long ca = 0, cb = 0;
int main()
{
auto t1 = clock();
string str;
getline (cin,str);
//cout<<str<<"\n";
int n, s;
assert(2 == scanf("%d %d", &n, &s));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
cout<<"res = "<<res<<"\n";
return 0;
}
/*
res = 3320522632
t2-t1 = 1.953
t3-t2 = 0.172
t4-t3 = 0
#include <bits/stdc++.h>
#include "books.h"
while(i>b||j<e-1)
{
bool bol = false;
while(mi < i)
{
bol = true;
i--;
if(p[i]>s)
{
cnt += curl;
curl = 0;
curr = 0;
}
mi = min(mi, p[i]);
ma = max(ma, p[i]);
}
while(j<ma)
{
bol = true;
j++;
if(p[j]<s)
{
cnt+=curr;
curl = 0;
curr = 0;
}
mi = min(mi, p[j]);
ma = max(ma, p[j]);
if(!bol)
{
if(mi>b){mi--;curl+=2;}
if(ma<e-1){ma++;curr+=2;}
}
cnt+=curl+curr;
for(int ii = 0; ii<n; ii++)
{
cnt += abs(ii - p[ii]);
}
return cnt;
}
int main()
{
auto t1 = clock();
string str;
getline (cin,str);
//cout<<str<<"\n";
int n, s;
assert(2 == scanf("%d %d", &n, &s));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
cout<<"res = "<<res<<"\n";
return 0;
}
/*
res = 3320522632
t2-t1 = 1.843
t3-t2 = 0.047
t4-t3 = 0
#include <cassert>
#include<ctime>
#include "books.h"
#include<iostream>
LL minimum_walk(vector<int> p, int s)
{
N = p.size(), eL = N+1, S = s+1, Lcur = S, Rcur = S;
for (int i=0; i<N; i++)
{
P[i+1]=p[i]+1; //1 index
ans += (LL) max(p[i] - i, i - p[i]);
}
while (!vis[cur])
{
L[cyc] = min(L[cyc], cur);
R[cyc] = max(R[cyc], cur);
C[cur] = cyc;
vis[cur] = true;
cur = P[cur];
}
cyc++;
}
//check R cost:
while (ptR <= eR)
{
if (ptR > tmpR) {tmpR = ptR, Rcost++;}
tmpR = max(tmpR, R[C[ptR]]);
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 394
//check L cost:
while (ptL >= eL)
{
if (ptL < tmpL) {tmpL = ptL, Lcost++;}
tmpL = min(tmpL, L[C[ptL]]);
if (R[C[ptL]] > Rcur)
{
root = false;
break;
}
ptL--;
}
if (root)
{
ans+=2*(Lcost + Rcost);
break;
}
else if (Lcost > Rcost)
{
Rcur = ptR, Lcur = L[C[ptR]];
ans+=2*Rcost;
}
else
{
Lcur = ptL, Rcur = R[C[ptL]];
ans+=2*Lcost;
}
}
}
return(ans);
}
int main()
{
auto t1 = clock();
string str;
getline (cin,str);
//cout<<str<<"\n";
int n, s;
assert(2 == scanf("%d %d", &n, &s));
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", res);
auto t4 = clock();
cout<<"res = "<<res<<"\n";
CAPITOLUL 3. IOI 2017 3.6. ANCIENT BOOKS 395
return 0;
}
/*
res = 3320522632
t2-t1 = 1.781
t3-t2 = 0.125
t4-t3 = 0
Petru lucrează pentru o companie care a construit un dispozitiv pentru detectarea moleculelor.
Fiecare moleculă are o greutate pozitivă ı̂ntreagă. Dispozitivul are un interval de detectare l, u,
unde l şi u sunt numere ı̂ntregi, pozitive.
Dispozitivul poate detecta un set de molecule dacă şi numai dacă acest set conţine un subset
de molecule cu greutate totală aparţinând intervalului de detectare a dispozitivului.
Formal, considerăm n molecule cu greutăţi ı̂ntregi w0 , ..., wn1 . Detectarea se consideră reuşită
dacă există un set de indici distincţi I ri1 , ..., , im x astfel ı̂ncât
şi
wmin min w0 , ..., wn1 .
Scrie un program care fie găseşte un subset de molecule cu greutate totală ı̂n intervalul de
detectare, fie determină că nu există un asemenea subset.
Detalii de implementare
Trebuie să implementezi funcţia (metoda):
396
CAPITOLUL 4. IOI 2016 4.1. DETECTING MOLECULES 397
Programul poate scrie indicii ı̂n array-ul returnat (sau ı̂n array-ul result pentru limbajul C) ı̂n
oricare ordine.
Te rugăm să foloseşti fişierele şablon furnizate pentru detalii de implementare ı̂n limbajul de
programare pe care ı̂l foloseşti.
Exemple
Exemplul 1
În acest exemplu avem patru molecule cu greutăţile 6, 8, 8 şi 7. Dispozitivul poate detecta
subseturi de molecule cu greutate totală cuprinsă ı̂ntre 15 şi 17, inclusiv. De remarcat, că 17 - 15
' 8 - 6 . Greutatea totală a moleculelor 1 şi 3 este w1 + w3 = 8 + 7 = 15, astfel funcţia poate
returna [1, 3]. Alte răspunsuri corecte posibile sunt [1, 2] ( w1 + w2 = 8 + 8 = 16 ) şi [2, 3] ( w2
+ w3 = 8 + 7 = 15 ).
Exemplul 2
În acest exemplu avem patru molecule cu greutăţile 5, 5, 6 şi 6, şi căutăm un subset cu
greutatea totală ı̂ntre 14 şi 15, inclusiv. La fel, vom remarca 15 - 14 ' 6 - 5. Nu există un subset
de molecule cu greutate totală ı̂ntre 14 şi 15 astfel funcţia va returna un array vid.
Exemplul 3
În acest exemplu avem patru molecule cu greutăţile 15, 17, 16 şi 18, şi căutăm un subset cu
greutatea totală ı̂ntre 10 şi 20, inclusiv. La fel, vom remarca 20 - 10 ' 18 - 15. Oricare subset
format din exact un element satisface cerinţele, astfel că răspunsuri corecte sunt: [0], [1], [2] şi [3].
Subtaskuri
1. (9 puncte): 1 & n & 100, 1 & wi & 100, 1 & u, l & 1000, toate wi sunt egale.
2. (10 puncte): 1 & n & 100, 1 & wi , u, l & 1000, şi
max w0 , ..., wn1 min w0 , ..., wn1 & 1
max w0 , ..., wn1 min w0 , ..., wn1 & 1.
3. (12 puncte): n & 100 şi wi , u, l & 1 000.
4. (15 puncte): n & 10 000 şi wi , u, l & 10 000 .
5. (23 puncte): n & 10 000 şi wi , u, l & 500 000
6. (31 puncte): n & 200 000 şi wi , u, l $ 2 .
31
Sample grader
Sample grader-ul citeşte inputul ı̂n următorul format:
` linia 1: numerele ı̂ntregi n, l, u.
` linia 2: n numere ı̂ntregi: w0 , ..., wn1
#include <cstdio>
#include <algorithm>
#include <vector>
#include<ctime>
#include<iostream>
forn(i, n)
wp[i] = pii(w[i], i);
sort(wp.begin(), wp.end());
vector<ll> mi(n + 1), ma(n + 1);
forn(i, n)
{
mi[i + 1] = mi[i] + wp[i].first;
ma[i + 1] = ma[i] + wp[n - i - 1].first;
}
forn(i, n + 1)
if (mi[i] <= u && ma[i] >= l)
{
int pos = n - 1;
ll sum = mi[i];
vector<int> result(i);
forn(j, i)
{
while (pos >= i && sum + wp[pos].first - wp[j].first > u)
pos--;
if (pos >= i && sum + wp[pos].first - wp[j].first <= u)
sum += wp[pos].first - wp[j].first, result[j]
= wp[pos--].second;
else
result[j] = wp[j].second;
}
return result;
}
return vector<int>();
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, l, u;
scanf("%d %d %d", &n, &l, &u);
std::vector<int> w(n);
for (int i = 0; i < n; i++)scanf("%d", &w[i]);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%d\n", (int)result.size());
for (int x : result) printf("%d ", x);
printf("\n");
auto t4 = clock();
cout<<"result.size() = "<<(int)result.size()<<"\n\n";
return 0;
}
// END CUT
/*
CAPITOLUL 4. IOI 2016 4.1. DETECTING MOLECULES 400
result.size() = 1000
t2-t1 = 0.39
t3-t2 = 0.297
t4-t3 = 0
#include <cstdio>
#include <algorithm>
#include <vector>
#include <fstream>
#include<iostream>
#include<ctime>
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, l, u;
scanf("%d %d %d", &n, &l, &u);
std::vector<int> w(n);
for (int i = 0; i < n; i++)scanf("%d", &w[i]);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%d\n", (int)result.size());
for (int x : result) printf("%d ", x);
printf("\n");
auto t4 = clock();
cout<<"result.size() = "<<(int)result.size()<<"\n\n";
return 0;
}
// END CUT
/*
result.size() = 1000
t2-t1 = 0.359
t3-t2 = 0.281
t4-t3 = 0
#include <cstdio>
#include <algorithm>
#include <vector>
#include <fstream>
#include<iostream>
#include<ctime>
int r = n;
for (int l = n; l >= 0; l--)
{
while (r > l && sum < L)
sum += wp[--r].first;
if (L <= sum && sum <= U)
{
vector<int> res;
while (l--)
CAPITOLUL 4. IOI 2016 4.1. DETECTING MOLECULES 402
res.push_back(wp[l].second);
while (r < n)
res.push_back(wp[r++].second);
return res;
}
if (l)
sum -= wp[l - 1].first;
}
return vector<int>();
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, l, u;
scanf("%d %d %d", &n, &l, &u);
std::vector<int> w(n);
for (int i = 0; i < n; i++)scanf("%d", &w[i]);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%d\n", (int)result.size());
for (int x : result) printf("%d ", x);
printf("\n");
auto t4 = clock();
cout<<"result.size() = "<<(int)result.size()<<"\n\n";
return 0;
}
// END CUT
/*
result.size() = 1000
t2-t1 = 0.375
t3-t2 = 0.281
t4-t3 = 0
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <numeric> // acumulate
CAPITOLUL 4. IOI 2016 4.1. DETECTING MOLECULES 403
#include <fstream>
#include<iostream>
#include<ctime>
sort(wp.begin(), wp.end());
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, l, u;
scanf("%d %d %d", &n, &l, &u);
std::vector<int> w(n);
for (int i = 0; i < n; i++)scanf("%d", &w[i]);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%d\n", (int)result.size());
for (int x : result) printf("%d ", x);
printf("\n");
auto t4 = clock();
cout<<"result.size() = "<<(int)result.size()<<"\n\n";
return 0;
}
// END CUT
/*
result.size() = 1000
t2-t1 = 0.359
t3-t2 = 0.297
t4-t3 = 0
#include "molecules.h"
#include <stdio.h>
#include <algorithm>
#include <fstream>
#include<iostream>
#include<ctime>
struct point
{
int a, num;
bool operator<(const point &p)const
{
return a < p.a;
}
} P[201000];
sort(P,P+n);
vector<int>res;
for(i=0;i<n;i++)
{
S1 += P[i].a;
S2 += P[n-i-1].a;
if(S1 <= u && S2 >= l)
{
if(S1 >= l)
{
for(j=0;j<=i;j++)res.push_back(P[j].num);
return res;
}
for(j=i+1;j<n;j++)
{
S1 += P[j].a;
S1 -= P[j-i-1].a;
if(S1 >= l)
{
for(k=j-i;k<=j;k++)res.push_back(P[k].num);
return res;
}
}
CAPITOLUL 4. IOI 2016 4.1. DETECTING MOLECULES 405
}
}
return res;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, l, u;
scanf("%d %d %d", &n, &l, &u);
std::vector<int> w(n);
for (int i = 0; i < n; i++)scanf("%d", &w[i]);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%d\n", (int)result.size());
for (int x : result) printf("%d ", x);
printf("\n");
auto t4 = clock();
cout<<"result.size() = "<<(int)result.size()<<"\n\n";
return 0;
}
// END CUT
/*
result.size() = 1000
t2-t1 = 0.359
t3-t2 = 0.109
t4-t3 = 0
#include <algorithm>
#include "molecules.h"
#include <fstream>
#include<iostream>
#include<ctime>
{
vector<int> V;
ll N=w.size();
ll S=0;
vector<pair<ll,int>> W;
for(ll i=0;i<N;i++)
W.push_back({w[i],i});
sort(W.begin(), W.end());
for(ll a=0,b=0;a<N;a++)
{
S-=a?W[a-1].first:0;
while(l>S and b<N)
S+=W[b++].first;
if(l<=S and S<=u)
{
for(ll i=a;i<b;i++)
V.push_back(W[i].second);
return V;
}
}
return V;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, l, u;
scanf("%d %d %d", &n, &l, &u);
std::vector<int> w(n);
for (int i = 0; i < n; i++)scanf("%d", &w[i]);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%d\n", (int)result.size());
for (int x : result) printf("%d ", x);
printf("\n");
auto t4 = clock();
cout<<"result.size() = "<<(int)result.size()<<"\n\n";
return 0;
}
// END CUT
/*
result.size() = 1000
t2-t1 = 0.343
t3-t2 = 0.313
t4-t3 = 0
CAPITOLUL 4. IOI 2016 4.1. DETECTING MOLECULES 407
#include "molecules.h"
#include <bits/stdc++.h>
#include <fstream>
#include<iostream>
#include<ctime>
vector<int> res;
vector<pii> v;
for(int i=0;i<w.size();i++)
{
v.emplace_back(w[i],i);
}
sort(v.begin(),v.end());
int l = 0;
ll sum = 0;
for(int r = 0;r < v.size();r++)
{
sum += v[r].first;
while(sum > u)
{
sum -= v[l].first;
l++;
}
//cout<<l<<" - "<<r<<": "<<sum<<endl;
if(sum >= lw)
{
for(int i = l;i<=r;i++) res.push_back(v[i].second);
return res;
}
}
return vector<int>();
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, l, u;
scanf("%d %d %d", &n, &l, &u);
std::vector<int> w(n);
for (int i = 0; i < n; i++)scanf("%d", &w[i]);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
CAPITOLUL 4. IOI 2016 4.1. DETECTING MOLECULES 408
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%d\n", (int)result.size());
for (int x : result) printf("%d ", x);
printf("\n");
auto t4 = clock();
cout<<"result.size() = "<<(int)result.size()<<"\n\n";
return 0;
}
// END CUT
/*
result.size() = 1000
t2-t1 = 0.359
t3-t2 = 0.312
t4-t3 = 0
#include "molecules.h"
#include <bits/stdc++.h>
#include <fstream>
#include<iostream>
#include<ctime>
int ind=1;
ll soma=0;
for(int i=1; i<=n; i++)
{
soma+=v[i].first;
while(soma>R&&ind<i) soma-=v[ind++].first;
if(L<=soma&&soma<=R)
{
for(int j=ind; j<=i; j++)
resp.push_back(v[j].second);
break;
}
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, l, u;
scanf("%d %d %d", &n, &l, &u);
std::vector<int> w(n);
for (int i = 0; i < n; i++)scanf("%d", &w[i]);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%d\n", (int)result.size());
for (int x : result) printf("%d ", x);
printf("\n");
auto t4 = clock();
cout<<"result.size() = "<<(int)result.size()<<"\n\n";
return 0;
}
// END CUT
/*
result.size() = 1000
t2-t1 = 0.359
t3-t2 = 0.203
t4-t3 = 0
#include<bits/stdc++.h>
#include <fstream>
#include<iostream>
#include<ctime>
sort(v.begin(), v.end());
CAPITOLUL 4. IOI 2016 4.1. DETECTING MOLECULES 410
int idx=0;
long long sum=0ll;
for(int i=0; i<n; i++)
{
for(; idx<n && sum<l; idx++)
sum+=v[idx].first;
sort(res.begin(), res.end());
return res;
}
sum-=v[i].first;
}
return vector<int>();
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, l, u;
scanf("%d %d %d", &n, &l, &u);
std::vector<int> w(n);
for (int i = 0; i < n; i++)scanf("%d", &w[i]);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%d\n", (int)result.size());
for (int x : result) printf("%d ", x);
printf("\n");
auto t4 = clock();
cout<<"result.size() = "<<(int)result.size()<<"\n\n";
return 0;
}
// END CUT
/*
result.size() = 1000
t2-t1 = 0.343
t3-t2 = 0.282
t4-t3 = 0
Anna lucrează la un parc de distracţii, iar acum coordonează construcţia unui nou roller-
coaster. Ea a proiectat deja n sectoare speciale (indexate convenabil de la 0 la n 1) care
afectează viteza trenului: sectoare ascendente, sectoare de frânare şi altele. Acum trebuie să
asambleze toate aceste sectoare şi să propună o versiune finală a roller-coaster-ului. ı̂n această
problemă, vom considera că trenul este punctiform (are lungime egală cu 0).
Pentru fiecare i ı̂ntre 0 şi n 1 inclusiv, cel de al i-lea sector special are două proprietăţi:
` atunci când trenul intră ı̂n acest sector, viteza sa trebuie să fie mai mică sau egală cu si
km/h.
` atunci când părăseşte acest sector, viteza trenului va fi exact ti km/h, indiferent de viteza
cu care trenul a intrat ı̂n acest sector.
Roller-coaster-ul va fi asamblat din aceste n sectoare speciale, care vor fi aşezate ı̂ntr-o anumită
ordine. Fiecare din cele n sectoare speciale trebuie să apară exact o dată ı̂n roller-coaster. Mai
mult, trebuie să existe un segment de cale ferată ı̂ntre oricare două sectoare consecutive. Anna
trebuie să stabilească ordinea celor n sectoare, iar apoi să decidă lungimea fiecărui segment de cale
ferată. Lungimea unui segment este măsurată ı̂n metri şi poate fi egală cu orice număr natural
nenegativ (inclusiv 0).
Fiecare metru de cale ferată dintre două sectoare speciale ı̂ncetineşte trenul cu 1 km/h. La
ı̂nceputul călătoriei trenul ı̂ntră ı̂n primul sector special (ı̂n ordinea aleasă de Anna) cu viteza de
1 km/h.
Versiunea finală a roller-coaster-ului trebuie să respecte următoarele cerinţe: trenul nu ı̂ncalcă
nicio limită de viteză atunci când intră ı̂n sectoarele speciale. viteza trenului rămâne permanent
pozitivă.
În toate subtask-urile, cu excepţia subtaskului 3, sarcina voastră este să găsiţi o ordonare
a celor n sectoare speciale şi să decideţi lungimile segmentelor de cale ferate dintre sectoarele
consecutive, asftel ı̂ncât lungimea totală a segmentelor de cale ferată să fie minimă. În subtask-
ul 3 trebuie doar să verificaţi dacă există o ordonare a sectoarelor speciale astfel ı̂ncât această
lungime totală să fie egală cu zero.
Detalii de Implementare
Trebuie să implementaţi următoarea funcţie (metodă):
` n: numărul de elemente din s şi t (i.e., numărul de sectoare speciale), ceilalţi parametri sunt
identici cu cei precizaţi mai sus.
Exemple
Exemplul 1
CAPITOLUL 4. IOI 2016 4.2. ROLLER COASTER RAILROAD 412
În acest exemplu există patru sectoare speciale. Cea mai bună soluţie este să le construim ı̂n
ordinea 0, 3, 1, 2 şi să le conectăm cu segmente de lungime 1, 2, 0.
Trenul va călători astfel:
` Iniţial, viteza trenului este de 1 km/h.
` Trenul ı̂ncepe cursa intrând ı̂n sectorul special cu numărul 0.
` Trenul părăseşte sectorul 0 cu o viteză de 7 km/h.
` Urmează apoi un segment de lungime egală cu 1 metru. Când trenul ajunge la finalul acestui
segment, viteza sa este 6 km/h.
` Trenul intră ı̂n sectorul cu numărul 3 cu o viteză de 6 km/h şi ı̂l părăseşte cu aceeaşi viteză.
` După ce părăseşte sectorul 3, trenul călătoreşte de-a lungul unui segment de 2 metri. Viteza
sa scade la 4 km/h.
` Trenul intră apoi ı̂n sectorul 1 cu o viteză de 4 km/h şi ı̂l părăseşte cu o viteză de 3 km/h.
` Imediat după sectorul special 1, trenul intră ı̂n sectorul special cu numărul 2.
` Trenul părăseşte sectorul cu numărul 2. Viteza sa finală este de 8 km/h.
Sample grader
Sample grader-ul citeşte datele ı̂n următorul format:
` linia 1: număr ı̂ntreg n.
` linia 2 i, pentru i ı̂ntre 0 şi n 1: numerele ı̂ntregi si şi ti .
n
The answer to the problem is mini ans2 1i. One could also notice that this subtask
is an instance of the well-known TSP (travelling salesman problem), where the special sections
represent the cities, and the distance function is the required railway segment length.
Subtask 3. Let’s add an additional special section with s and t 1: now we can
introduce a restriction that the train must have speed exactly 1 km/h at the end of the journey
(here represents any number greater or equal than any of the numbers given in the input data
9
- 10 would sufice).
Consider an infinite graph, with a vertex set 1; 2; 3; ... and there is an edge from si to ti
for every section i (including the added one). For every positive integer x consider the balance
value: (number of edges going over the segment x, x 1 from left to right) minus (number of
edges going over the segment x, x 1 from right to left). In the picture above one can see three
edges going from left to right (red) and two going in the opposite direction (green), so the balance
is 1.
If one aims to start from 1 km/h and end with the same speed, then the train must cross the
segment x; x 1 equal number of times in both directions. If the balance is positive then it’s
necessary to add an additional green edge to slow down the train, so at least one railway segment
is required and the answer is not zero. If the balance is negative it just means that the train needs
to be accelerated at some point, so one can add as many additional red edges as needed for free.
Once the balance equals zero for every x, it is suficient to check whether the resulting graph
is connected or not. If the graph is not connected, than the answer is clearly not zero: to go from
one component to the other it’s needed to slow down the train at least once, so an additional
railway segment is required. If the graph is connected, then, since all the balances are zero, for
every vertex x its in-degree equals its degree!out-degree, and thus there exists an Euler cycle in
this graph, from which one could construct a valid sections arrangement.
To do this eficiently, one need to consider only the ”interesting” values of x, which are
given in the input data, and instead of considering segments x; x 1 one should consider
interestingi ; interestingi1 .
Subtask 4. The solution for the last subtask naturally emerges from the previous one. If the
balance is positive for some x interestingi , it is required to add additional green edges until
the balance is restored, and every green edge corresponds to a railway segment. Thus, for every
x interestingi one needs to add max 0; balance length to the answer, where length stands for
the distance to the next interesting point (interestingi1 interestingi ).
The last piece is to make the graph connected. In case the balance is zero we can connect
interestingi and interestingi1 with two edges in both directions, paying the length of this seg-
ment. Now we need to solve an instance of the well-know MST (minimum spanning tree) problem.
#include <fstream>
#include<iostream>
#include<ctime>
CAPITOLUL 4. IOI 2016 4.2. ROLLER COASTER RAILROAD 414
#define mp make_pair
#define pb push_back
#define fs first
#define sc second
sort(e.begin(), e.end());
int64 res = 0;
for (int i = 0, delta = 0; i + 1 < (int) e.size(); ++i)
{
delta += e[i].sc.fs;
res += max(0, delta) * (int64) (e[i + 1].fs - e[i].fs);
edges.pb(mp(e[i + 1].fs - e[i].fs, mp(e[i].sc.sc, e[i + 1].sc.sc)));
if ((e[i + 1].fs == e[i].fs) || (delta != 0))
dsu_union(p, e[i].sc.sc, e[i + 1].sc.sc);
}
sort(edges.begin(), edges.end());
return res;
}
int main()
{
auto t1 = clock();
int n, need_answer;
scanf("%d", &n);
CAPITOLUL 4. IOI 2016 4.2. ROLLER COASTER RAILROAD 415
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", ans);
auto t4 = clock();
cout<<"ans = "<<ans<<"\n\n";
return 0;
}
/*
ans = 309419403
t2-t1 = 0.703
t3-t2 = 1.563
t4-t3 = 0
#include "railroad.h"
#include <bits/stdc++.h>
struct mode
{
ll p,v,i;
bool operator < (const mode&x) const
{
return p < x.p;
}
};
struct edge
{
ll a,b,w;
bool operator < (const edge&x) const
{
CAPITOLUL 4. IOI 2016 4.2. ROLLER COASTER RAILROAD 416
return w<x.w;
}
};
ll boss[200005];
ll finds(ll a)
{
if(a==boss[a]) return a;
return boss[a]=finds(boss[a]);
}
ll plan_roller_coaster(vector<int> s,vector<int> t)
{
ll n=s.size()+1,ans=0,nw=0;
vector<mode> v;
vector<pii> interesting;
vector<edge> e;
s.pb(1000000001),t.pb(1);
for(int i=0;i<n;++i)
boss[i]=i,v.pb(mode{s[i],1,i}),v.pb(mode{t[i],-1,i});
sort(ALL(v));
for(int i=0,t=0;i+1<v.size();)
{
interesting.pb(MP(v[i].p,v[i].i));
while(t<v.size()&&v[i].p==v[t].p)
nw+=v[t].v,++t;
if(nw>0)
ans+=nw*(v[t].p-v[i].p);
if(nw!=0)
Union(v[t].i,v[i].i);
for(++i;i<t;++i)
Union(v[i-1].i,v[i].i);
}
for(int i=0;i+1<interesting.size();++i)
if(finds(interesting[i].S)!=finds(interesting[i+1].S))
e.pb(edge{interesting[i].S,
interesting[i+1].S,
interesting[i+1].F-interesting[i].F});
sort(ALL(e));
for(auto i:e)
if(finds(i.a)!=finds(i.b))
Union(i.a,i.b),ans+=i.w;
return ans;
}
int main()
{
auto t1 = clock();
int n, need_answer;
scanf("%d", &n);
auto t2 = clock();
CAPITOLUL 4. IOI 2016 4.2. ROLLER COASTER RAILROAD 417
auto t3 = clock();
printf("%lld\n", ans);
auto t4 = clock();
cout<<"ans = "<<ans<<"\n\n";
return 0;
}
/*
ans = 309419403
t2-t1 = 0.745
t3-t2 = 0.893
t4-t3 = 0
#include "railroad.h"
#include <bits/stdc++.h>
#define N 200005
#define ff first
#define ss second
int find(int v)
{
return (v == p[v] ? v : p[v] = find(p[v]));
}
in[s[i]].push_back(i);
in[t[i]].push_back(i);
}
for(auto x : sw)
{
if(bal > 0)
{
res += 1LL * bal * (x.ff - last);
}
for(int y : in[x.ff])
{
f.push_back({ bal == 0 ? x.ff - last : 0, {y, lastid}});
lastid = y;
last = x.ff;
}
bal += x.ss;
}
sort(f.begin(), f.end());
for(auto x : f)
res += x.ff * unite(x.ss.ff, x.ss.ss);
return res;
}
int main()
{
auto t1 = clock();
int n, need_answer;
scanf("%d", &n);
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", ans);
auto t4 = clock();
cout<<"ans = "<<ans<<"\n\n";
return 0;
}
/*
ans = 309419403
t2-t1 = 0.794
t3-t2 = 3.261
t4-t3 = 0
#include<bits/stdc++.h>
#define x first
#define y second
int Find(int v)
{
return (P[v] < 0 ? v : (P[v] = Find(P[v])));
}
sort(A.begin(), A.end());
int SM = 0;
ll tot = 0;
memset(P, -1, sizeof(P));
sort(E.begin(), E.end());
for (auto e : E)
if (Merge(e.y.x, e.y.y))
tot += e.x;
return (tot);
}
int main()
{
auto t1 = clock();
int n, need_answer;
scanf("%d", &n);
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", ans);
auto t4 = clock();
cout<<"ans = "<<ans<<"\n\n";
return 0;
}
/*
ans = 309419403
t2-t1 = 0.721
t3-t2 = 1.47
t4-t3 = 0
#include "railroad.h"
#include<bits/stdc++.h>
///Disjoint Sets
///Sweep Line
///Set the balance always to 0, connecting special sections
int link[200005];
int setSize[200005];
int Find(int u)
{
if(link[u]==u) return u;
else return link[u]=Find(link[u]);
}
if(setSize[v]>setSize[u]) swap(u,v);
setSize[u]+=setSize[v];
link[v]=u;
}
void initDSU(int n)
{
for(int i=1;i<=n;i++)
{
setSize[i]=1;
link[i]=i;
}
}
struct event
{
int T;
int op;
int id; //Which special section
bool operator<(const event& a)
{
if(T<a.T)
return true;
else
{
if(T==a.T)
{
if(op<a.op) return true;
else return false;
}
else return false;
}
}
};
struct segment
{
ll length;
int a,b; //ID where it starts and ends
bool operator < (const segment& s)
{
return length<s.length;
}
};
vector<event> timeline;
vector<segment> remaining; //Not taken because its balance was 0
sort(timeline.begin(),timeline.end());
for(int i=0;i<2*n-1;i++)
{
balance+=timeline[i].op;
if(balance<0)
{
//Add a track from left to right (free) and connect i with i+1
unite(timeline[i].id,timeline[i+1].id);
}
else
CAPITOLUL 4. IOI 2016 4.2. ROLLER COASTER RAILROAD 422
if(balance>0)
{
//We need to slow down the train so we add "balance" tracks
cost+=(ll)(timeline[i+1].T-timeline[i].T)*balance;
sort(remaining.begin(),remaining.end());
set<int> R; //Roots
for(int i=1;i<=n;i++)
{
R.insert(Find(i));
}
int roots=R.size();
int i=0;
while(roots>1)
{ //Not fully connected
int a=remaining[i].a;
int b=remaining[i].b;
if(!same(a,b))
{
unite(a,b);
cost+=remaining[i].length;
roots--;
}
i++;
}
return cost;
}
int main()
{
auto t1 = clock();
int n, need_answer;
scanf("%d", &n);
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", ans);
auto t4 = clock();
cout<<"ans = "<<ans<<"\n\n";
CAPITOLUL 4. IOI 2016 4.2. ROLLER COASTER RAILROAD 423
return 0;
}
/*
ans = 309419403
t2-t1 = 0.69
t3-t2 = 1.037
t4-t3 = 0
#include <algorithm>
#include <vector>
#include<ctime> // clock()
#include<cstdint> // int64_t
#include<fstream> // freeopen
#include<iostream> // cout
vi nxt;
int head(int u)
{
return nxt[u] != -1 ? nxt[u] = head(nxt[u]) : u;
}
ll plan_roller_coaster(vi s, vi t)
{
s.eb(inf); t.eb(1); int n = sz(s);
vi p = s; p.insert(end(p), all(t));
vi sum(m--), e;
rep(i, 0, n)
{
int l = lb(all(p), s[i]) - begin(p), r = lb(all(p),t[i])-begin(p);
unite(l, r); ++sum[l]; --sum[r];
}
rep(i, 0, m) sum[i + 1] += sum[i];
ll ans = 0;
rep(i, 0, m)
CAPITOLUL 4. IOI 2016 4.2. ROLLER COASTER RAILROAD 424
{
if (sum[i])
{
unite(i, i + 1);
if (sum[i] > 0)
ans += 1ll * sum[i] * (p[i + 1] - p[i]);
}
else e.eb(i);
}
trav(u, e)
if (unite(u, u + 1))
ans += p[u + 1] - p[u];
return ans;
}
int main()
{
auto t1 = clock();
int n, need_answer;
scanf("%d", &n);
auto t2 = clock();
auto t3 = clock();
printf("%lld\n", ans);
auto t4 = clock();
cout<<"ans = "<<ans<<"\n\n";
return 0;
}
/*
ans = 309419403
t2-t1 = 0.739
t3-t2 = 1.324
t4-t3 = 0
4.3 Shortcut
Problema 3 - Shortcut 100 de puncte
Pavel are un joc cu trenuleţe. Acesta este foarte simplu. Există o singură linie principală
constând ı̂n n staţii consecutive, numerotate ı̂n ordine, de-a lungul liniei, cu numere de la 0 la
n 1. Staţiile şi sunt situate la capetele liniei principale. Distanţa dintre staţiile i şi i 1 este de
li centimetri (0 & i & n 1).
În afară de linia principală pot exista şi linii secundare. Fiecare linie secundară este o linie
de cale fereată ı̂ntre o staţie de pe linia principală şi o nouă staţie nesituată pe linia principală.
(Aceste staţii noi nu sunt numerotate.) Din fiecare staţie de pe linia principală poate pleca cel
mult o linie secundară. Lungimea liniei secundare care pleaca din staţia i este de di centimetri.
Dacă di 0 ı̂nseamnă că nu există linie secundară care pleacă din staţia i.
Pavel ı̂şi propune să construiască o scurtătură: o linie expres ı̂ntre două staţii (posibil vecine)
ale liniei principale. Linia expres va avea lungimea de exact c centimetri, indiferent care vor fi
cele două staţii pe care le va conecta.
Fiecare porţiune de cale ferată, inclusiv linia expres, poate fi parcursă ı̂n ambele sensuri.
Distanţa dintre două staţii este cea mai mică lungime a unui treseu care uneşte cele două staţii
de-a lungul căii ferate. Diametrul ı̂ntregii reţele de cale ferată este maximul distanţelor pentru
oricare pereche de staţii. Cu alte cuvinte, acesta este cel mai mic număr t, astfel ı̂ncât distanţa
ı̂ntre oricare două staţii este cel mult t.
Pavel doreşte să construiască linia expres astfel ı̂ncât diametrul reţelei rezultate să fie mini-
mizat.
Detalii de implementare
Trebuie să implementezi funcţia
Folosiţi fişierele template oferite pentru detalii de implementare ı̂n limbajul vostru de progra-
mare.
Exemple
Exemplul 1
Pentru reţeaua de cale ferată de mai jos, graderul va face urmatorul apel:
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 426
Soluţia optimă este să se construiască linia expres ı̂ntre staţiile 1 şi 3, aşa cum este arătat ı̂n
figură.
Diametrul noii reţele de cale ferată este de 80 de centimetri, aşa că funcţia va trebui sa returneze
80.
Exemplul 2
Graderul face următorul apel:
Soluţia optimă este să se conecteze staţiile 2 şi 7, caz ı̂n care diametrul este 110.
Exemplul 3
Graderul face următorul apel:
Soluţia optimă este să se conecteze staţiile 1 şi 2, reducând diametrul la 21.
Exemplul 4
Graderul face următorul apel:
Oricum am conecta două staţii cu o linie expres de lungime 3 nu se poate ı̂mbunătăţi diametrul
reţelei iniţiale de cale ferată care este 4.
Subtaskuri
Pentru toate subtaskurile 2 & n & 1 000 000, 1 & li & 109 , 0 & di & 109 , 1 & c & 109 .
1. (9 puncte) 2 & n & 10,
2. (14 puncte) 2 & n & 100,
3. (8 puncte) 2 & n & 250,
4. (7 puncte) 2 & n & 500,
5. (33 puncte) 2 & n & 3 000,
6. (22 puncte) 2 & n & 100 000,
7. (4 puncte) 2 & n & 300 000,
8. (3 puncte) 2 & n & 1 000 000.
Sample grader
Sample grader-ul citeşte date de intrare ı̂n următorul format:
` linia 1: numerele ı̂ntregi n şi c,
` linia 2: numerele ı̂ntregi l0 , l1 , ..., ln2 ,
` linia 3: numerele ı̂ntregi d0 , d1 , ..., dn1 .
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 427
If we take a look at some pair i and j we can see that if di + dj + jxi xj j 6 k then all pairs
of y and z work. Otherwise, only y and z such that di + dj + jxi yj + jxj zj 6 k are valid. This
o
formula actually describes a square rotated 45 . What we need to do is to try all pairs of i and j,
cross corresponding squares and then check if there is some point where y = xa and z = xb inside
the resulting area.
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 428
So far we can just check for such point by trying all possible pairs of a and b. However, there is
a nice way to perform this check in linear time and not care about its impact to overall complexity
in future. Proceed with a sweep line and keep two pointers: on the lowest point above the square
and highest point below the square. Since functions of both positions from the x-coordinate of
the sweep line are unimodal the overall complexity will be O n.
The total complexity of such solution is O(n2 logM) where M is the maximal possible answer.
Subtask 6: Now, two more observations are needed. Let’s fix j ¿ i and y ¡ z. Now the pair
produces some square iff xj xi + dj + di ¿ k. Let’s fix j and find the intersection of the squares
for all possible i. The bounds of the square produced can be rewritten as follows:
~
z y & k xj dj xi di ;
z
y ' xj dj xi di k;
z y & k xj dj xi di ;
z
y ' x j dj x i di k
We can see that the bounds only depend on xi di and xi + di. We need only maximal and minimal
values of xi di and xi +di, so we can use some data structure, for example, segment tree, to find
them in O n log n time. The total complexity of this solution is O(n log(n) log(M)).
Subtasks 7 and 8: Notice that xj xi +dj +di ¿ k is equal to (xj +dj)(xi di) ¿ k. It follows
that if we iterate through j in the order of increasing (xj + dj) then the set of i that is used to
take minimum and maximum values is only expanding, i.e. once some particular i is in the set,
it remains there for all remaining values of j. Thus, we can keep current maximum and minimum
values of xi di and xi + di without any data structure with the use of the two pointers technique
and two sorted arrays. The total complexity of the full-score solution is O(n logM). Note, that
sorting is done at the very beginning and there is no need to resort these two arrays in each
iteration of binary search.
The another approach to achieve this time bound that doesn’t use sort (and thus solves the
decision problem itself in linear time) is to get rid of useless elements. We say that station i
dominates station j if di ¿ dj + jxi xj j. Now, if one station is dominated by the other we can
consider only dominator as the endpoint of the express line (unless the position being dominated
is considered for the other end). The set of positions that are not dominated by any other index
can be found in linear time by computing prefix and sufix maximums. Now when we use the same
solution as for subtask 6, but we query maximum and minimum values for inequality only when
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 429
considering ”good” positions (not dominated by any other positions). This allows to achieve the
situation that the query bound moves only right and we can process each of them in O 1.
64 needleft = 1;
65 }
66
67 if (needleft)
68 {
69 maxsum = min(maxsum,
70 (mostleft.fi + diam - C - d[i] - mostleft.se) + x[i]);
71 minsum = max(minsum,
72 (mostright.fi - (diam - C - d[i] - mostright.se)) + x[i]);
73 maxdif = min(maxdif,
74 x[i] - (mostright.fi - (diam - C - d[i] - mostright.se)));
75 mindif = max(mindif,
76 x[i] - (mostleft.fi + diam - C - d[i] - mostleft.se));
77 }
78 while (r > l && q[r - 1].fi > x[i] - d[i]) r--;
79 q[r++] = mp(x[i] - d[i], i);
80 }
81
82 if (maxsum < minsum || maxdif < mindif) return 0;
83 int curdif = 0;
84 int cursum = n;
85 for (int i = 0; i < n; i++)
86 {
87 while (curdif < n && x[curdif] - x[i] < mindif) curdif++;
88 while (cursum > 0 && x[cursum - 1] + x[i] >= minsum) cursum--;
89 int cur = max3(cursum, curdif, i + 1);
90 if (cur < n && x[cur] + x[i] <= maxsum && x[cur] - x[i] <= maxdif)
91 {
92 ans1 = i;
93 ans2 = cur;
94 return 1;
95 }
96 }
97 return 0;
98 }
99
100 long long find_shortcut(int N, int* L0, int* L, int C_)
101 {
102 n = N;
103 C = C_;
104 ll cursum = 0;
105 for (int i = 0; i < n; i++)
106 {
107 d[i] = L[i];
108 x[i] = cursum;
109 if (i + 1 < n) cursum += L0[i];
110 }
111 ll l = 0;
112 ll r = inf;
113 while (r - l > 1)
114 {
115 ll mid = (l + r) / 2;
116 if (can(mid)) r = mid;
117 else l = mid;
118 }
119 can(r);
120 return r;
121 }
122
123 // BEGIN CUT
124 int main()
125 {
126 clock_t t1, t2, t3, t4;
127
128 t1=clock();
129
130 freopen("../tests/subtask_8/220", "r", stdin);
131 freopen("8-220.out.txt", "w", stdout);
132
133 int n, c;
134 scanf("%d%d", &n, &c);
135
136 int *l = (int *)malloc((n - 1) * sizeof(int)); // N > 1
137 int *d = (int *)malloc(n * sizeof(int));
138 for (int i = 0; i < n - 1; i++) {
139 scanf("%d", &l[i]);
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 431
140 }
141 for (int i = 0; i < n; i++) {
142 scanf("%d", &d[i]);
143 }
144
145 t2=clock();
146
147 long long t = find_shortcut(n, l, d, c);
148
149 t3=clock();
150
151 // BEGIN SECRET
152 puts("14e047d7a2907b9034950b074822b302");
153 // END SECRET
154
155 printf("%lld\n", t);
156
157 t4=clock();
158
159 // reset console output
160 freopen("CON", "w", stdout);
161
162 printf("n = %d c = %d\n", n,c);
163 printf("t = %lld\n\n", t);
164
165 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
166 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
167 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
168
169 return 0;
170 }
171 // END CUT
172 /*
173 n = 1000000 c = 1000
174 t = 1000857674
175
176 t2-t1 = 1.109000
177 t3-t2 = 5.916000
178 t4-t3 = 0.000000
179
180 Process returned 0 (0x0) execution time : 7.065 s
181 Press any key to continue.
182 */
#define pb push_back
#define mp make_pair
#define fs first
#define sc second
bool isNonempty(int n)
{
if (suml > sumr || difl > difr) return false;
int p = 0;
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 432
return false;
}
int p = -1;
deque <int> q;
if (p != -1)
{
suml = max(suml, x[i] + d[i] - k + c + maxsump[p]);
sumr = min(sumr, x[i] - d[i] + k - c + mindifp[p]);
difl = max(difl, -x[i] + d[i] - k + c + maxsump[p]);
difr = min(difr, -x[i] - d[i] + k - c + mindifp[p]);
}
}
q.push_back(i);
}
return isNonempty(n);
}
long long find_shortcut(int n, vector <int> len, vector <int> dep, int c)
{
x[0] = 0ll;
maxsump[0] = d[0];
mindifp[0] = -d[0];
important[n - 1] = true;
int curb = n - 1;
for (int i = n - 2; i >= 0; i--)
{
if (x[i] - d[i] < x[curb] - d[curb])
{
important[i] = true;
curb = i;
}
}
return lb;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 434
t2-t1 = 4.79
t3-t2 = 13.439
t4-t3 = 0
#include<ctime> // clock()
#define pb push_back
#define mp make_pair
#define fs first
#define sc second
/** Interface */
/** Read */
s = -1, c = getChar();
while (’0’ <= c && c <= ’9’)
x = x * 10 + c - ’0’, c = getChar();
return s == 1 ? x : -x;
}
/** 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;
bool isNonempty(int n)
{
if (suml > sumr || difl > difr)
return false;
int p = 0;
for (int i = 1; i < n; i++)
{
while (p < i && x[p] + x[i] <= sumr && x[p] - x[i] <= difr)
p++;
while (p > 0 && (x[p] + x[i] > sumr || x[p] - x[i] > difr))
p--;
return false;
}
int p = -1;
deque <int> q;
if (p != -1)
{
suml = max(suml, x[i] + d[i] - k + c + maxsump[p]);
sumr = min(sumr, x[i] - d[i] + k - c + mindifp[p]);
difl = max(difl, -x[i] + d[i] - k + c + maxsump[p]);
difr = min(difr, -x[i] - d[i] + k - c + mindifp[p]);
}
}
q.push_back(i);
}
return isNonempty(n);
}
long long find_shortcut(int n, vector <int> len, vector <int> dep, int c)
{
x[0] = 0ll;
maxsump[0] = d[0];
mindifp[0] = -d[0];
important[n - 1] = true;
int curb = n - 1;
for (int i = n - 2; i >= 0; i--)
{
if (x[i] - d[i] < x[curb] - d[curb])
{
important[i] = true;
curb = i;
}
}
rb = mid;
else
lb = mid + 1;
}
return lb;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
n = readInt();
c = readInt();
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 0.328
t3-t2 = 18.613
t4-t3 = 0
#ifdef WIN32
#define LLD "%I64d"
#else
#define LLD "%lld"
#endif
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
ll x[maxn], d[maxn];
int n, C;
pair<ll, int> q[maxn];
int ans1, ans2;
needleft = true;
}
if (needleft)
{
maxsum = min(maxsum,
(mostleft.fi + diam - C - d[i] - mostleft.se) + x[i]);
minsum = max(minsum,
(mostright.fi - (diam - C - d[i] - mostright.se)) + x[i]);
maxdif = min(maxdif,
x[i] - (mostright.fi - (diam - C - d[i] - mostright.se)));
mindif = max(mindif,
x[i] - (mostleft.fi + diam - C - d[i] - mostleft.se));
}
long long find_shortcut(int N, vector <int> L0, vector <int> L, int C_)
{
n = N;
C = C_;
ll cursum = 0;
for (int i = 0; i < n; i++)
{
d[i] = L[i];
x[i] = cursum;
if (i + 1 < n) cursum += L0[i];
}
ll l = 0;
ll r = inf;
while (r - l > 1)
{
ll mid = (l + r) / 2;
if (can(mid)) r = mid;
else l = mid;
}
can(r);
return r;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 4.629
t3-t2 = 8.341
t4-t3 = 0
#include "shortcut.h"
#include <bits/stdc++.h>
struct Fucking_locality
{
lint arg1, arg2;
lint first;
int second;
bool operator < (const Fucking_locality &fuck) const
{
return make_pair(first,second) < make_pair(fuck.first,fuck.second);
}
};
int n, c;
lint a[1000005], b[1000005];
Fucking_locality v[1000005], w[1000005];
bool trial(lint x)
{
lint ps = -1e18, pe = 1e18, ms = -1e18, me = 1e18;
lint mx = -1e18, mxp = -1, smx = -1e18;
lint mn = 1e18, mnp = -1, smn = 1e18;
int p = 0;
for(int i=0; i<n; i++)
{
while(p < n && w[p].first + x < v[i].first)
{
lint cmx = w[p].arg1;
lint cmn = w[p].arg2;
if(mx < cmx)
{
smx = mx;
mx = cmx;
mxp = w[p].second;
}
else
if(smx < cmx) smx = cmx;
ps = max(ps, q1 - x + c + cb + ca);
pe = min(pe, q2 + x - c + cb - ca);
ms = max(ms, q1 - x + c - cb + ca);
me = min(me, q2 + x - c - cb - ca);
}
p = 0;
for(int i=0; i<n; i++)
{
lint s = max(ps - b[i], b[i] - me);
lint e = min(pe - b[i], b[i] - ms);
while(p < n && s > b[p]) p++;
while(p > 0 && s <= b[p-1]) p--;
while(p < n && b[p] <= e) return true;
}
return false;
}
sort(v, v+n);
sort(w, w+n);
lint s = 0, e = 2e15;
while(s != e)
{
lint m = (s+e)/2;
if(trial(m)) e = m;
else s = m+1;
}
return s;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 3.546
t3-t2 = 8.469
t4-t3 = 0
#include "shortcut.h"
#include <algorithm>
#include<ctime>
#include<fstream>
#include<iostream>
int n, c;
vector<llong> dist;
vector<int> etc;
vector<pair<llong, int>> ad, sb;
bool check(llong m)
{
llong fs = -1ll, se = -1ll;
int fsi = -1, sei = -1, p, q;
llong lad = -1e18, gad = 1e18, lsb = -1e18, gsb = 1e18;
for (int i = 0, j = 0; i < n; ++i)
{
while (j < n && sb[j].first + m < ad[i].first)
{
p = sb[j].second;
llong mx = dist[p] + etc[p];
if (fs < mx)
{
sei = fsi;
fsi = p;
se = fs;
fs = mx;
}
else
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 443
p = ad[i].second;
if (p == sb[0].second && j == 1 || j == 0) continue;
return false;
}
etc = d;
llong ld = 0ll, e = 0ll;
int fs = 0, se = 0;
for (int i = 0; i < n; ++i)
{
ad.push_back({ dist[i] + etc[i], i });
sb.push_back({ dist[i] - etc[i], i });
e = max(e, ld + etc[i]);
if (i < n - 1)
ld = max(ld, (llong)etc[i]) + l[i];
}
sort(ad.begin(), ad.end());
sort(sb.begin(), sb.end());
llong s = fs + se;
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 444
while (s < e)
{
llong m = (s + e) / 2;
if (check(m)) e = m;
else s = m + 1ll;
}
return s;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 3.453
t3-t2 = 6.514
t4-t3 = 0
#include <bits/stdc++.h>
#include "shortcut.h"
deque<int> q;
for (int i = 0; i < n; ++i)
{
while (!q.empty() && x[i]-x[q.front()]+d[i]+d[q.front()] > limit)
{
max_sum = max(max_sum, x[q.front()] + d[q.front()]);
min_diff = min(min_diff, x[q.front()] - d[q.front()]);
q.pop_front();
}
if (max_sum >= 0)
{
lsum = max(lsum, x[i] + d[i] + max_sum + c - limit);
rsum = min(rsum, x[i] - d[i] + min_diff + limit - c);
rdiff = min(rdiff, x[i] - d[i] - max_sum + limit - c);
ldiff = max(ldiff, x[i] + d[i] - min_diff + c - limit);
}
q.push_back(i);
}
return false;
};
high = mid;
}
else
{
low = mid + 1;
}
}
return high;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 3.526
t3-t2 = 29.047
t4-t3 = 0
#include "shortcut.h"
#include <bits/stdc++.h>
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 447
ll Mx0[MAXN], Mx1[MAXN];
ll X[MAXN], L[MAXN], TP[MAXN], TM[MAXN];
int O[MAXN], OJ[MAXN];
int N; ll K, Ans;
bool isp(ll Y)
{
ll xymx = -INFLL, xymn = INFLL, yxmx = -INFLL, yxmn = INFLL, rmn, rmx;
for(int oi = 0, oj = 0, j; oj < N; oj++)
{
j = OJ[oj]; ll t = Y-TP[j];
for(; oi < N && t < TM[O[oi]]; oi++);
if(!oi || (1 == oi && j == O[0])) continue;
rmx = TP[j] == Mx0[oi-1] ? Mx1[oi-1] : Mx0[oi-1];
rmn = -(j == O[0] ? TM[O[1]] : TM[O[0]]);
ll a = Y-K - TM[j], b = K-Y + TP[j];
upmin(xymn, a+rmn); upmax(xymx, b+rmx);
upmin(yxmn, a-rmx); upmax(yxmx, b-rmn);
if(xymn < xymx || yxmn < yxmx) return false;
}
return false;
}
ll getAns()
{
ll mx = -INFLL;
for(int i = 0; i < N; i++)
{
upmax(Ans, X[i]+L[i] + mx);
upmax(mx, L[i]-X[i]);
TP[i] = X[i]+L[i];
TM[i] = L[i]-X[i];
}
i = O[oi]; ll c = TP[i];
if(Mx0[oi] < c) swap(Mx0[oi], c);
if(Mx1[oi] < c) swap(Mx1[oi], c);
}
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 448
ll a = 0, b = 0;
for(int i = 0; i < N; i++)
{
ll c = L[i];
if(a < c) swap(a, c);
if(b < c) swap(b, c);
}
ll s = a+b, e = Ans;
for(ll m; s < e;)
{
m = (s+e) >> 1;
if(isp(m)) e = m;
else s = m+1;
}
return s;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 449
t2-t1 = 3.531
t3-t2 = 3.265
t4-t3 = 0
#include <bits/stdc++.h>
#include "shortcut.h"
/*
j>i -> xi-di, xi+di are known
z+y<=len+(xj-dj)+(xi-di) -> mxsm
z+y>=(xj+dj)+(xi+di)-len -> mism
z-y<=len+(xj-dj)-(xi+di) -> mxdi
z-y>=(xj+dj)-(xi-di)-len -> midi
/*
pll lef = {INF, -INF};
pll rig = {-INF, -INF};
*/
int l = 0, r = 0;
bool skip = false;
// calculate bounds
for (int i = 0; i < n; i++)
{
while (l < r && x[i] + d[i] - dif[l].fi > len)
{
int ind = dif[l++].se; // add element to set of elements
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 450
if (skip)
{
mxsm = min(mxsm, di + x[i] - d[i] + len - c);
mism = max(mism, sm + x[i] + d[i] - len + c);
mxdi = min(mxdi, x[i] - d[i] - sm + len - c);
midi = max(midi, x[i] + d[i] - di - len + c);
}
return false;
}
return ret;
}
// BEGIN CUT
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 451
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 3.507
t3-t2 = 6.25
t4-t3 = 0
#include <bits/stdc++.h>
#include "shortcut.h"
ll x[MAXN], d[MAXN];
int dif[MAXN];
/*
j>i -> xi-di, xi+di are known
z+y<=len+(xj-dj)+(xi-di) -> mxsm
z+y>=(xj+dj)+(xi+di)-len -> mism
z-y<=len+(xj-dj)-(xi+di) -> mxdi
z-y>=(xj+dj)-(xi-di)-len -> midi
// calculate bounds
for (int i = 0; i < n; i++)
{
while (l < r && x[i] + d[i] - (x[dif[l]] - d[dif[l]]) > len)
{
int ind = dif[l++]; // add element to set of elements
// producing the intersection
if (x[ind] - d[ind] < di)
di = x[ind] - d[ind];
if (x[ind] + d[ind] > sm)
sm = x[ind] + d[ind];
skip = true;
}
if (skip)
{
mxsm = min(mxsm, di + x[i] - d[i] + len - c);
mism = max(mism, sm + x[i] + d[i] - len + c);
mxdi = min(mxdi, x[i] - d[i] - sm + len - c);
midi = max(midi, x[i] + d[i] - di - len + c);
}
while (l < r && x[dif[r - 1]] - d[dif[r - 1]] > x[i] - d[i])
r--;
dif[r++] = i;
}
return false;
}
return ret;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 454
t = 1000857674
t2-t1 = 3.886
t3-t2 = 2.516
t4-t3 = 0
#include "shortcut.h"
#include <bits/stdc++.h>
int n,d[N],c,q[N],ql,qr;
ll x[N];
bool Check(ll k)
{
ll mx=-inf,mn=inf;
ll ls=-inf,rs=inf,ld=-inf,rd=inf;
ql=1;qr=0;
for(int i=1;i<=n;i++)
{
for(;ql<=qr && x[q[ql]]-d[q[ql]]<x[i]+d[i]-k;ql++)
mx=max(mx,x[q[ql]]+d[q[ql]]),mn=min(mn,x[q[ql]]-d[q[ql]]);
ls=max(ls,mx+x[i]+d[i]-k+c);
rs=min(rs,mn+x[i]-d[i]+k-c);
ld=max(ld,mx-x[i]+d[i]-k+c);
rd=min(rd,mn-x[i]-d[i]+k-c);
for(;ql<=qr && x[q[qr]]-d[q[qr]]>=x[i]-d[i];qr--);
q[++qr]=i;
}
int l1=n+1,r1=n+1,l2=0,r2=0;
for(int i=1;i<=n;i++)
{
for(;l1>=2 && x[i]+x[l1-1]>=ls;l1--);
for(;r1>=1 && x[i]+x[r1]>rs;r1--);
for(;l2<=n && x[i]-x[l2]>rd;l2++);
for(;r2<n && x[i]-x[r2+1]>=ld;r2++);
int l=max(l1,l2),r=min(r1,r2);
if(l<=r) return 1;
}
return 0;
}
ll lo=0,hi=2*mxd+x[n],mi=lo+hi+1>>1;
for(;lo<hi;mi=lo+hi+1>>1)
{
if(Check(mi)) hi=mi-1;
else lo=mi;
}
return lo+1;
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 455
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 3.507
t3-t2 = 5.25
t4-t3 = 0
#define pb push_back
#define jizz ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define F first
#define S second
#define ET cout << "\n"
#define MP make_pair
#define MEM(i,j) memset(i,j,sizeof i)
#define ALL(v) v.begin(),v.end()
#define DB(a,s,e) {for(int i=s;i<e;++i) cout << a[i] << " ";ET;}
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 456
const ll INF=1e18;
/*
j<i
si-sj+di+dj>k
si+di-k>sj-dj
x-y<0
|sj-x|+|si-y|+di+dj+c<=k
x+y>=(sj+dj)+(si+di)-k+c ->b0
x-y>=(sj+dj)-(si-di)-k+c ->b1
x-y<=(sj-dj)-(si+di)+k-c ->b2
x+y<=(sj-dj)+(si-di)+k-c ->b3
y>=b0-x
y>=x-b2
y<=x-b1
y<=b3-x
y<=sn
*/
b0=max(b0,s[i]+d[i]+mxt-mid+c),
b1=max(b1,mxt-s[i]+d[i]-mid+c);
b2=min(b2,mit-s[i]-d[i]+mid-c),
b3=min(b3,mit+s[i]-d[i]+mid-c);
while(rg>=lf&&s[q[rg]]-d[q[rg]]>s[i]-d[i]) --rg;
q[++rg]=i;
}
for(int i=0,j=n,k=0;i+1<n&&!flag;++i)
{
ll up=min({s[n-1],s[i]-b1,b3-s[i]}),dn=max(b0-s[i],s[i]-b2);
while(j>0&&s[j-1]>=b0-s[i]) --j;
while(k<n&&s[k]<s[i]-b2) ++k;
if(max(j,k)!=n&&s[max(j,k)]<=up) flag=1;
}
if(flag) R=mid;
else L=mid+1;
}
return L;
}
// BEGIN CUT
int main()
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 457
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 3.64
t3-t2 = 4.953
t4-t3 = 0
#include "shortcut.h"
#include <iostream>
#include<ctime>
#include<fstream>
int d[nmax];
long long x[nmax],y[nmax];
int i,n;
long long C;
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 458
if(suml>sumr||difl>difr) return 0;
int p1=1,p2=n;
int poz;
for(i=1;i<=n;i++)
{
while(p1<=n&&x[p1]-x[i]<difl)
p1++;
while(p2>=1&&x[p2]+x[i]>=suml)
p2--;
poz=max(i+1,max(p1,p2+1));
if(poz<=n&&
x[poz]+x[i]>=suml&&
x[poz]+x[i]<=sumr&&
x[poz]-x[i]>=difl&&
x[poz]-x[i]<=difr)
return 1;
}
return 0;
}
return ans;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 459
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 3.562
t3-t2 = 4.498
t4-t3 = 0
#include "shortcut.h"
#include <bits/stdc++.h>
struct SumDif
{
lint sum, dif;
lint X, D;
int id;
};
int N, C;
bool is_valid(lint T)
{
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 460
pos++;
}
return false;
}
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 461
sort(SUM, SUM + N, [&](SumDif &l, SumDif &r) {return l.sum < r.sum;});
sort(DIF, DIF + N, [&](SumDif &l, SumDif &r) {return l.dif < r.dif;});
lint res = 0;
return res;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 3.875
t3-t2 = 6.455
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 462
t4-t3 = 0
#include "shortcut.h"
#include <bits/stdc++.h>
#define X first
#define Y second
int n, c;
ll d[1000007], x[1000007];
vector<pll> VP, VM;
bool check(ll k)
{
ll mins = 0, maxs = 1e18, mind = 0, maxd = 1e18;
ll minis = 1e18, maxis = 0;
int ii = 0;
for(int jj = 0 ; jj < n ; jj++)
{
int j = VP[jj].Y;
while(ii < n && VM[ii].X + k < VP[jj].X)
{
int i = VM[ii].Y;
minis = min(minis, x[i] + d[i]);
maxis = max(maxis, x[i] + d[i]);
ii++;
}
sort(VP.begin(), VP.end());
sort(VM.begin(), VM.end());
return a;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
CAPITOLUL 4. IOI 2016 4.3. SHORTCUT 464
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 3.525
t3-t2 = 10.265
t4-t3 = 0
#include <bits/stdc++.h>
#include "shortcut.h"
int ptr = 0;
if (!(seg_mx[ptr].ft == -OO ||
(seg_mx[ptr].ft == (pf[i] + dst[i]) &&
seg_mx[ptr].sd == OO)))
{
cur.ft = (seg_mx[ptr].ft == (pf[i] + dst[i]) ?
seg_mx[ptr].sd :
seg_mx[ptr].ft);
cur.sd = (seg_mn[ptr].ft == (pf[i] - dst[i]) ?
seg_mn[ptr].sd :
seg_mn[ptr].ft);
if (!was)
{
was = 1;
u = cu; d = cd; l = cl; r = cr;
if (u < d || r < l) return 0;
}
else
{
u = min(u, cu);
d = max(d, cd);
if (u < d) return 0;
l = max(l, cl);
r = min(r, cr);
if (r < l) return 0;
}
}
}
if (!was) return 1;
l >>= 1; r >>= 1;
int l1 = n, r1 = n - 1;
int r2 = -1, l2 = 0;
if (j1 == j2)
{
if (j1 != i)
return 1;
}
else return 1;
}
return 0;
}
c = C * 2;
ll mex = 0;
pf[0] = 0;
dst[n - 1] = d[n - 1] * 2;
mex = max(mex, dst[n - 1]);
// smth smaller
ll l1 = 0, r1 = mex + pf[n - 1] / 2;
if (ok(md * 2))
r1 = md;
else l1 = md + 1;
}
ok(16);
return l1;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, c;
scanf("%d%d", &n, &c);
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
puts("14e047d7a2907b9034950b074822b302");
// END SECRET
printf("%lld\n", t);
auto t4 = clock();
return 0;
}
// END CUT
/*
n = 1000000 c = 1000
t = 1000857674
t2-t1 = 3.673
t3-t2 = 4.234
t4-t3 = 0
Paint By Numbers este un binecunoscut joc. Vom considera varianta simplă unidimensională
a acestui joc. ı̂n acest joc, jucatorul are o linie formată din n celule.
Celulele sunt numerotate de la 0 la n 1 de la stânga la dreapta. Jucătorul trebuie să coloreze
fiecare celulă cu negru sau cu alb. Vom folosi ’X’ pentru a simboliza celulele negre şi ’_’ pentru
a simboliza celulele albe.
Jucătorul primeşte un şir c c0 , ..., ck1 de k numere ı̂ntregi pozitive: indiciile.
El trebuie să coloreze celulele ı̂n aşa fel ı̂ncât celulele negre să formeze exact k blocuri de
celule consecutive. Mai mult, numărul celulelor negre din al i-lea bloc (indexat din 0) din stânga
trebuie sa fie egal cu ci . De exemplu , dacă indiciile sunt c 3, 4, jocul rezolvat trebuie să aibă
CAPITOLUL 4. IOI 2016 4.4. PAINT BY NUMBERS 468
exact două blocuri de celule negre consecutive: unul de lungime 3 şi celălalt de lungime 4. Astfel,
daca n 10 şi c 3, 4, o soluţie care satisface indiciile este ’’_XXX__XXXX’’. Observaţi că
’’XXXX_XXX__’’ nu este o soluţie care satisface indiciile: blocurile de celule negre nu sunt ı̂n
ordinea corectă. De asemenea, ’’__XXXXXXX_’’ nu este o soluţie care satisface indiciile: există
un singur bloc de celule negre, nu două separate.
Se dă un joc Paint By Numbers rezolvat parţial. Adică, se ştie n şi c, şi ı̂n plus se cunoaşte
că anumite celule trebuie să fie negre şi anumite celule trebuie să fie albe. Sarcina voastră este să
deduceţi informaţii suplimentare despre celule.
Mai precis, o soluţie validă este una care satisface indiciile şi respectă culorile din celulele
cunoscute. Pogramul vostru trebuie să găsească celulele care sunt colorate ı̂n negru ı̂n orice
soluţie validă şi celulele care sunt colorate ı̂n alb ı̂n orice soluţie validă.
Se garantează că pentru datele de intrare există ı̂ntotdeauna cel puţin o soluţie validă.
Detalii de implementare
Trebuie să implementaţi următoarea funcţie (metodă):
Se observă că celulele (indexate din 0) cu indicii 2, 6, şi 7 sunt negre ı̂n toate soluţiile.
Toate celelate celule pot fi negre, dar nu neapărat. Deci, răspunsul corect este
’’??X???XX??’’.
Exemplul 2
În acest exemplu soluţia este unic determinată deci răspunsul corect este ’’XXX_XXXX’’.
Exemplul 3
solve_puzzle("..._._....", [3])
În acest exemplu se poate deduce că şi celula 4 trebuie să fie albă - nu este posibil să avem trei
celule negre consecutive ı̂ntre poziţiile 3 şi 5. Deci răspunsul corect este
Exemplul 4
solve_puzzle(".X........", [3])
Există doar două soluţii valide care se potrivesc descrierii de mai sus:
’’XXX_______’’,
’’_XXX______’’.
Sample grader
Sample grader-ul citeşte datele de intrare ı̂n următorul format:
` linia 1: stringul s,
` linia 2: ı̂ntregul k urmat de k ı̂ntregi c0 , ..., ck1 .
their intersection is non-empty, those cells are guaranteed to be black. (Proof of a more general
statement is given below.)
The same approach works for subtask 4 as well. Additionally, we are able to deduce some
white cells. One case is shown in Example 3. The same logic has to be applied at the beginning
and at the end of a row. (In fact, the easiest solution is to prepend and append a white cell as a
sentinel.)
Here’s a tricky test case for subtask D: n 13, k 4, c 3; 1; 1; 3, s = "...._..._....".
Correct output: ?XX?_X_X_?XX?.
The tricky part here is that we can deduce the white cell at index 6. (Whenever two consecutive
blocks have a fixed position, all cells between those positions have to be white.)
Subtask 4 was as far as we could get with an easy greedy approach. In order to solve the
general version we will use dynamic programming.
One possible solution looks as follows:
Step 1: Compute prefix sums of given white cells and given black cells (each sepa- rately).
Step 2: For each i and j, compute the answer P i; j to the following question: ”Is there a
valid solution if we only consider the first i clues and the first j cells of the given puzzle (as
if cutting away and discarding the rest)?”
Base case of the recurrence: If i 0, this is possible iff there is no given black cell among
the first j cells.
Recursive case: If cell j 1 is forced white, P i; j P i; j 1. If cell j 1 is forced black,
we verify that it is possible to place the last block there (the number of forced white cells it
overlaps must be zero, the next cell to the left must be able to be white) and if that is the
case, we make a recursive call P i 1; j c 1 where c was the corresponding clue. Finally,
if cell j 1 isn’t forced, the answer is the logical OR of both above cases.
Step 3: The same in reverse, i.e., with sufixes of the puzzle and the list of clues.
Step 4: For each cell, we verify whether it can be white. A cell cannot be white if it is forced
to be black. If that is not the case, we try all possibilities for the number of black blocks to
the left of the cell, and verify each possibility using the data we precomputed in steps 2+3.
Step 5: For each clue, we mark all the cells where it can be located as cells that can be
black. Suppose we are processing clue t and that its value is ct. For each i we verify whether
the clued block can be placed starting from cell i. This requires a few checks that can all be
done in constant time:
– cells i 1 and i ct must not be forced black
– cells i through i ct 1 must not be forced white
– there must be a valid solution for the first t clues and the first i 1 cells
– there must be a valid solution for the last k t 1 clues and the last n i ct 1 cells
The above solution can conveniently be implemented in O nk , where k is the number of clues.
2
Less efficient implementations may run in O n , these should not solve subtask 7.
2 2
Other implementations may run in something like O n ¶C ¶ or in O n¶C ¶ . These should
solve subtask 5, but not subtasks 6 and 7.
Proof of the greedy solution (subtasks 1-4)
Theorem 1. Consider the version of our puzzle where initially each cell is either unknown or
forced white.
Suppose that there is a cell x such that there are two valid solutions in which this cell belongs
to different black blocks. Then there is also a valid solution in which this cell is white.
Proof. Suppose that we have i $ j such that in the first solution the block that covers cell x
corresponds to clue i and in the second solution it corresponds to clue j.
We will now construct a new solution as follows: take the first j 1 black blocks from the
second solution and the remaining blocks from the first solution.
This is a valid solution because in the second solution the first j 1 black blocks are all strictly
to the left of cell x and in the first solution all the remaining blocks are strictly to the right of cell
x. It is also obvious that for this reason cell x is white in the new solution. q.e.d.
CAPITOLUL 4. IOI 2016 4.4. PAINT BY NUMBERS 471
147 }
148
149 // BEGIN CUT
150 #include <string.h>
151 #include <stdio.h>
152 #include <stdlib.h>
153
154 #define S_MAX_LEN (200 * 1000)
155 char s[S_MAX_LEN + 1];
156
157 int main()
158 {
159 clock_t t1, t2, t3, t4;
160
161 t1=clock();
162
163 //freopen("../tests/subtask_1/001", "r", stdin);
164 //freopen("1-001.out.txt", "w", stdout);
165
166 freopen("../tests/subtask_7/125", "r", stdin);
167 freopen("7-125.out.txt", "w", stdout);
168
169 scanf("%s", s);
170 int n = strlen(s);
171 int k;
172
173 scanf("%d", &k);
174
175 int* c = (int*)malloc(k * sizeof(int));
176
177 for (int i = 0; i < k; i++)
178 {
179 scanf("%d", &c[i]);
180 }
181
182 t2=clock();
183
184 char* result = (char*)malloc((n + 1) * sizeof(char));
185
186 solve_puzzle(n, s, k, c, result);
187
188 t3=clock();
189
190 result[n] = 0;
191
192 // BEGIN SECRET
193 //puts("098d134608c94f7413faac591054ee35");
194 // END SECRET
195
196 printf("%s\n", result);
197
198 t4=clock();
199
200 // reset console output
201 freopen("CON", "w", stdout);
202
203 printf("t2-t1 = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
204 printf("t3-t2 = %f\n", (double)(t3 - t2) / CLOCKS_PER_SEC);
205 printf("t4-t3 = %f\n", (double)(t4 - t3) / CLOCKS_PER_SEC);
206
207 /*
208 printf("%s\n", s);
209 printf("%d ", k);
210 for (int i = 0; i < k; i++)
211 {
212 printf("%d ", c[i]);
213 }
214 printf("\n");
215 printf("%s\n", result);
216 */
217
218 return 0;
219 }
220 // END CUT
221 /*
222 t2-t1 = 0.000000
CAPITOLUL 4. IOI 2016 4.4. PAINT BY NUMBERS 474
#include<ctime>
int k = C.size();
if (it == 2) break;
dp[it][0][0] = 1;
CAPITOLUL 4. IOI 2016 4.4. PAINT BY NUMBERS 475
reverse(C.begin(), C.end());
reverse(B.begin(), B.end());
reverse(W.begin(), W.end());
reverse(dp[1].begin(), dp[1].end());
for (int i = 1; i < n - 1; i++)
{
for (int j = 0; j <= k; j++)
{
if (dp[0][i][j] && dp[1][i][k - j])
{
ans[i - 1] |= 1;
}
}
}
vector<int> a(n);
for (int i = 1; i < n; i++)
{
for (int j = 0; j <= k; j++)
{
if (j > 0 &&
i > C[j - 1] &&
sumW[i - 1] - sumW[i - C[j - 1] - 1] == 0 &&
sumB[i] - sumB[i - 1] == 0 &&
dp[0][i - C[j - 1] - 1][j - 1] &&
dp[1][i][k - j])
{
a[i - C[j - 1]]++;
a[i]--;
}
}
}
return res;
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++) {
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%s\n", ans.data());
auto t4=clock();
/*
printf("%s\n", s);
printf("%d ", k);
for (int i = 0; i < k; i++)
{
printf("%d ", c[i]);
}
printf("\n");
printf("%s\n", result);
*/
return 0;
}
// END CUT
/*
t2-t1 = 0.015000
t3-t2 = 6.432000
t4-t3 = 0.016000
argc = 4
checker
../tests/subtask_7/125
../tests/subtask_7/125.a
7-125.out.txt
----------------------
1
Correct
#include<ctime>
vector<int> load_vector()
{
int size; cin >> size;
vector<int> tmp(size);
for (int &x : tmp)
cin >> x;
return tmp;
}
vector<int> Wsums(L+1,0);
for (int l=0; l<L; ++l)
Wsums[l+1]=Wsums[l]+W[l];
possible[0][0] = true;
for (int l=1; l<=L; ++l)
possible[l][0] = possible[l-1][0] && !B[l-1];
return possible;
}
vector<int> B(L,0);
for (int i = 0; i < L; i++) B[i] = S[i] == ’X’;
vector<int> W(L,0);
for (int i = 0; i < L; i++) W[i] = S[i] == ’_’;
vector<bool> can_be_white(L,false);
vector<int> Wsums(L+1,0);
for (int l=0; l<L; ++l)
Wsums[l+1]=Wsums[l]+W[l];
vector<int> intervals(L+1,0);
vector<bool> can_be_black(L+1,false);
int inside = 0;
for (int l=0; l<L; ++l)
{
inside += intervals[l];
if (inside > 0) can_be_black[l] = true;
}
std::string ans;
for (int l=0; l<L; ++l)
{
if (can_be_black[l] && can_be_white[l]) ans.push_back(’?’);
if (can_be_black[l] && !can_be_white[l]) ans.push_back(’X’);
if (!can_be_black[l] && can_be_white[l]) ans.push_back(’_’);
if (!can_be_black[l] && !can_be_white[l]) ans.push_back(’!’);
}
return ans;
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++) {
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%s\n", ans.data());
auto t4=clock();
/*
printf("%s\n", s);
printf("%d ", k);
for (int i = 0; i < k; i++)
{
printf("%d ", c[i]);
}
printf("\n");
printf("%s\n", result);
*/
return 0;
}
/*
t2-t1 = 0.015000
t3-t2 = 8.406000
t4-t3 = 0.016000
argc = 4
checker
../tests/subtask_7/125
../tests/subtask_7/125.a
7-125.out.txt
----------------------
1
Correct
#include<iostream>
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/subtask_7/125", // input
(char*)"../tests/subtask_7/125.a", // rezultat corect
(char*)"7-125.out.txt", // rezultat de verificat
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
//readBothSecrets(output_secret);
//readBothGraderResults();
//compareRemainingLines(3); // incepand cu linia nr 3
#include "paint.h"
#include <cstdio>
#include <cstdlib>
#include<ctime>
int a[200002];
bool L[200002][111];
bool R[200002][111];
int yes[200002], no[200002];
R[i][j] = true;
if (j ? i > 1 && L[i-2][j] && s[i-2] != ’X’ : L[i-1][0])
{
yes[i - 1]++;
yes[i + c[j] - 1]--;
}
continue;
}
if (s[i - 1] != ’X’ && R[i + 1][j])
R[i][j] = true;
}
std::string res;
for (i = 0; i < n; i++)
{
yes[i + 1] += yes[i];
if (s[i] != ’X’)
{
for (j = 0; j <= m; j++)
if (L[i][j] && R[i + 2][j])
break;
no[i] = j <= m;
}
res.push_back(yes[i] && no[i] ? ’?’ : yes[i] ? ’X’ : ’_’);
}
return res;
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++)
{
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
printf("%s\n", ans.data());
auto t4=clock();
return 0;
}
// END CUT
/*
t2-t1 = 0.031000
t3-t2 = 1.594000
t4-t3 = 0.015000
#include <bits/stdc++.h>
#include "paint.h"
using namespace std;
dp[n+1][k+1] = true;
for (int i = n; i >= 1; --i)
{
for (int j = k+1; j >= 1; --j)
{
if (j <= k && (s[i] == black || s[i] == anyy))
{
bool blackstrip = i+c[j]-1 <= n &&
wqs[i+c[j]-1]-wqs[i-1] == 0;
bool nextwhite = i+c[j] > n || s[i+c[j]] != black;
bool nextdp = dp[min(n+1, i+c[j]+1)][j+1];
if (blackstrip && nextwhite && nextdp)
{
pb[i][j] = true;
dp[i][j] = true;
}
}
reach[1][1] = true;
for (int i = 1; i <= n+1; ++i)
{
for (int j = 1; j <= k+1; ++j) if (reach[i][j] && dp[i][j])
{
if (pb[i][j])
{
bqs[i] += 1;
bqs[i+c[j]] -= 1;
wqs[i+c[j]] = 1;
reach[min(n+1, i+c[j]+1)][j+1] = true;
}
if (pw[i][j])
CAPITOLUL 4. IOI 2016 4.4. PAINT BY NUMBERS 483
{
wqs[i] = 1;
reach[i+1][j] = true;
}
}
}
return ans;
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++)
{
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
printf("%s\n", ans.data());
auto t4=clock();
return 0;
}
// END CUT
/*
t2-t1 = 0.015000
t3-t2 = 1.781000
t4-t3 = 0.016000
#include "paint.h"
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
char A[MAXN];
int B[MAXK];
int N, K;
void reverse()
{
reverse(A+1, A+N+1);
reverse(B+1, B+K+1);
}
string getAns()
{
run(DA[0], DB[0]); reverse();
run(DA[1], DB[1]); reverse();
memset(S, 0, (N+1)<<2);
for(int j = 1; j <= K; j++)
{
for(int s = 1, e = B[j]; e <= N; s++, e++)
{
if(!DB[0][e][j] || !DB[1][N-s+1][K-j+1]) continue;
S[s]++; S[e+1]--;
}
}
string ret;
for(int i = 1; i <= N; i++)
{
S[i] += S[i-1];
if(!S[i])
{
ret.pb(’_’);
continue;
}
bool t = false;
for(int j = 0; j <= K; j++)
{
if(!DA[0][i][j] || !DA[1][N-i+1][K-j]) continue;
t = true;
break;
}
ret.pb(t ? ’?’ : ’X’);
}
return ret;
}
return getAns();
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++)
{
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
printf("%s\n", ans.data());
auto t4=clock();
return 0;
}
// END CUT
/*
t2-t1 = 0.031000
t3-t2 = 11.633000
t4-t3 = 0.016000
#include <bits/stdc++.h>
#include "paint.h"
using namespace std;
n = s.size(), k = _c.size();
copy(_c.begin(), _c.end(), c + 1);
s = "." + s + ".";
f[0][0] = 1;
for(int i = 1; i <= n; ++i)
{
f[i][0] = black[i] == 0;
for(int j = 1; j <= k; ++j)
{
bool w = f[i - 1][j];
bool b = (i >= c[j]) &&
(s[i - c[j]] != ’X’) &&
(white[i] == white[i - c[j]])&&
(i > c[j] ? f[i - c[j] - 1][j - 1] : (j == 1));
return ans;
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++)
{
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
printf("%s\n", ans.data());
auto t4=clock();
return 0;
}
// END CUT
/*
t2-t1 = 0.015000
t3-t2 = 2.203000
t4-t3 = 0.016000
#include "paint.h"
#include <bits/stdc++.h>
n = s.length(), k = _c.size();
s = ’#’ + s + ’#’;
for(int i : _c) c.emplace_back(i);
for(int i = 1; i <= n; i++)
{
w[i] += w[i-1] + (s[i] == ’_’);
b[i] += b[i-1] + (s[i] == ’X’);
}
pre[0][0] = 1;
for(int i = 1; i <= n; i++)
{
pre[i][0] = (b[i] == 0);
for(int j = 1; j <= k; j++)
{
if(s[i] != ’X’) pre[i][j] |= pre[i-1][j];
if(s[i] != ’_’ && i >= c[j] &&
s[i-c[j]] != ’X’ && w[i] == w[i-c[j]])
{
if(j == 1) pre[i][j] |= pre[i-c[j]][j-1];
else if(i > c[j]) pre[i][j] |= pre[i-c[j]-1][j-1];
}
}
}
suf[n+1][k+1] = suf[n+2][k+1] = 1;
for(int i = n; i; i--)
{
suf[i][k+1] = (b[n] == b[i-1]);
for(int j = k; j; j--)
{
if(s[i] != ’X’) suf[i][j] |= suf[i+1][j];
if(s[i] != ’_’ && i + c[j] <= n + 1 &&
s[i+c[j]] != ’X’ && w[i-1] == w[i+c[j]-1])
suf[i][j] |= suf[i+c[j]+1][j+1];
}
}
return ans;
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++)
{
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
printf("%s\n", ans.data());
auto t4=clock();
return 0;
}
// END CUT
/*
t2-t1 = 0.015000
t3-t2 = 3.141000
t4-t3 = 0.015000
#include <bits/stdc++.h>
#include "paint.h"
pre[0][0] = 1;
for( int i = 1 ; i <= n ; i++ )
CAPITOLUL 4. IOI 2016 4.4. PAINT BY NUMBERS 490
{
pre[i][0] = ( b[i] == 0 );
for( int j = 1 ; j <= k ; j++ )
{
if( s[i] != ’X’ ) pre[i][j] |= pre[i-1][j];
if( s[i] != ’_’ && i >= c[j] &&
s[i-c[j]] != ’X’ && w[i] == w[i-c[j]] )
{
if( j == 1 ) pre[i][j] |= pre[i-c[j]][j-1];
else if( i > c[j] ) pre[i][j] |= pre[i-c[j]-1][j-1];
}
}
}
suf[n+1][k+1] = suf[n+2][k+1] = 1;
for( int i = n ; i >= 1 ; i-- )
{
suf[i][k+1] = ( b[n] == b[i-1] );
for( int j = k ; j >= 1 ; j-- )
{
if( s[i] != ’X’ ) suf[i][j] |= suf[i+1][j];
if( s[i] != ’_’ && i + c[j] <= n + 1 &&
s[i+c[j]] != ’X’ && w[i-1] == w[i+c[j]-1] )
suf[i][j] |= suf[i+c[j]+1][j+1];
}
}
return ans;
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
CAPITOLUL 4. IOI 2016 4.4. PAINT BY NUMBERS 491
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++)
{
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
printf("%s\n", ans.data());
auto t4=clock();
return 0;
}
// END CUT
/*
t2-t1 = 0.015000
t3-t2 = 2.855000
t4-t3 = 0.016000
#include "paint.h"
#include <bits/stdc++.h>
nz[1]=nz[n]=1;
dpl[0][0]=true;
for(int i=1;i<=n;i++) for(int j=0;j<=k;j++)
{
if(nz[i]) dpl[j][i]=dpl[j][i-1];
if(nz[i]==1) lw[i]=i;
else lw[i]=lw[i-1];
if(j>0 && i>=lw[i]+c[j-1] &&
dpl[j-1][i-c[j-1]-1] && nz[i-c[j-1]])
dpl[j][i]=true;
}
dpr[k+1][n+1]=true;
for(int i=n;i>0;i--) for(int j=k+1;j>0;j--)
{
CAPITOLUL 4. IOI 2016 4.4. PAINT BY NUMBERS 492
if(nz[i]) dpr[j][i]=dpr[j][i+1];
if(nz[i]==1) nw[i]=i;
else nw[i]=nw[i+1];
if(j<=k && i+c[j-1]<=nw[i] &&
dpr[j+1][i+c[j-1]+1] && nz[i+c[j-1]])
dpr[j][i]=true;
}
for(int i=2;i<n;i++)
for(int j=0;j<=k;j++)
if(dpl[j][i-1] && dpr[j+1][i+1]) mb[i-2]=true;
for(int j=1;j<=k;j++)
{
int nd=1;
for(int i=2;i<n;i++)
{
if(dpl[j-1][i-2] && dpr[j+1][i+c[j-1]+1] &&
nz[i-1] && nz[i+c[j-1]] && nw[i]>=i+c[j-1])
nd=i+c[j-1]-1;
if(i<=nd) mc[i-2]=true;
}
}
string res="";
for(int i=0;i<n;i++)
{
if(s[i]!=’.’) res+=s[i];
else
{
if(mb[i] && mc[i]) res+=’?’;
if(mb[i] && !mc[i]) res+=’_’;
if(!mb[i] && mc[i]) res+=’X’;
}
}
return res;
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++)
{
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
printf("%s\n", ans.data());
auto t4=clock();
return 0;
}
// END CUT
/*
t2-t1 = 0.015000
t3-t2 = 1.672000
t4-t3 = 0.016000
#include "paint.h"
#include <bits/stdc++.h>
using namespace std;
int n, k;
int pref_[N], prefX[N];
int canX[N], can_[N];
bool state[105][N];
char arr[N];
int sz[N];
if(prefX[r-sz[i+1]] - prefX[l] == 0)
canX[l-sz[i]+1]++,
canX[l+1]--,
can_[l+1]++,
can_[r-sz[i+1]+1]--,
l--;
else r--;
}
else l--;
}
else r--;
string str;
for(int j = 2; j <= n+1; ++j)
{
if(canX[j] && can_[j]) str.push_back(’?’);
else
if(canX[j]) str.push_back(’X’);
else str.push_back(’_’);
}
return str;
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++)
{
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
printf("%s\n", ans.data());
auto t4=clock();
return 0;
}
CAPITOLUL 4. IOI 2016 4.4. PAINT BY NUMBERS 495
// END CUT
/*
t2-t1 = 0.015000
t3-t2 = 0.516000
t4-t3 = 0.015000
#include "paint.h"
#include<bits/stdc++.h>
int rs=0;
if(A[i]!=’X’) rs|=f(i+1, lf);
if(lf<k && seg[lf]<=suf[i] && A[i+seg[lf]]!=’X’)
{
if(i+seg[lf]+1<=n)
rs|=f(i+seg[lf]+1, lf+1);
else rs|=f(i+seg[lf], lf+1);
}
return dp[i][lf]=rs;
}
vis[i][lf]=1;
if(A[i]!=’X’ && f(i+1, lf))
{
emptyy[i]=1;
back(i+1, lf);
}
if(lf<k &&
seg[lf]<=suf[i] &&
A[i+seg[lf]]!=’X’ &&
f(i+seg[lf]+(i+seg[lf]+1<=n), lf+1))
{
isi[i]++;
isi[i+seg[lf]]--;
emptyy[i+seg[lf]]=1;
back(i+seg[lf]+1, lf+1);
}
}
f(0, 0);
back(0, 0);
int st=0;
ans.resize(n);
for(int i=0; i<n; i++)
{
st+=isi[i];
if(emptyy[i] && st>0) ans[i]=’?’;
else
if(emptyy[i]) ans[i]=’_’;
else
if(st>0) ans[i]=’X’;
}
return ans;
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++)
{
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
printf("%s\n", ans.data());
auto t4=clock();
return 0;
}
// END CUT
/*
t2-t1 = 0.015000
t3-t2 = 0.125000
t4-t3 = 0.016000
#include "paint.h"
CAPITOLUL 4. IOI 2016 4.4. PAINT BY NUMBERS 497
#include <iostream>
#include<string>
#include<vector>
#include<ctime>
string s;
vector <int> c;
gen(0,0);
string Sol;
for (int i=0; i<N; i++)
{
black+=canblack[i];
if (black && canwhite[i])
{
Sol.push_back(’?’);
}
else
if (black)
{
Sol.push_back(’X’);
}
else
{
Sol.push_back(’_’);
}
}
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 498
return(Sol);
}
// BEGIN CUT
int main()
{
auto t1=clock();
scanf("%s", buf);
std::string s = buf;
int c_len;
scanf("%d", &c_len);
std::vector<int> c(c_len);
for (int i = 0; i < c_len; i++)
{
scanf("%d", &c[i]);
}
auto t2=clock();
auto t3=clock();
printf("%s\n", ans.data());
auto t4=clock();
return 0;
}
// END CUT
/*
t2-t1 = 0.015000
t3-t2 = 0.047000
t4-t3 = 0.016000
Ilshat este un programator care lucrează la dezvoltarea unor structuri de date eficiente. ı̂ntr-o
zi, a inventat o nouă structură de date. Această structură de date poate stoca o mulţime de ı̂ntregi
nenegativi pe biţi, unde este o putere a lui 2.
Mai exact, pentru un ı̂ntreg nenegativ .
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 499
Structura de date este goală iniţial. Un program care foloseşte acestă structură trebuie să
respecte următoarele reguli:
Programul poate insera ı̂ntregi de biţi ı̂n structura de date, unul câte unul, utilizând funcţia
add_element(x). Dacă programul ı̂ncearcă să insereze un element care este deja prezent ı̂n
structură, nu se ı̂ntâmplă nimic.
După ce a inserat ultimul element, programul trebuie să apeleze funcţia compile_set()
exact o dată.
În final, programul poate apela funcţia check_element(x)\verb pentru a verifica dacă
elementul este prezent ı̂n structura de date. Această funcţie poate fi apelată de mai multe ori.
Când Ilshat a implementat prima oară această structură de date, a creat un bug ı̂n funcţia
compile_set(). Acest bug reordonează cifrele binare ale fiecărui element din mulţime ı̂n aceeaşi
manieră. Ilshat vrea ca voi să găsiţi exact ı̂n ce fel au fost reordonate cifrele ca urmare a acestui
bug.
Formal, consideraţi o secvenţă ı̂n care fiecare număr de la la apare exact o dată. Numim o
asemenea secvenţă o permutare. Consideraţi un element din mulţime, ale cărui cifre ı̂n binar sunt
(cu fiind cel mai semnificativ bit). Când funcţia compile_set() este apelată, acest element
este ı̂nlocuit de elementul .
Aceeaşi permutare este folosită pentru a reordona cifrele tuturor elementelor.
Permutarea este arbitrară, poate fi inclusiv adevărat că pentru toţi .
Spre exemplu, să presupunem că , şi aţi inserat ı̂n set ı̂ntregii care au ca reprezentări binare
stringurile 0000, 1100 şi 0111. Apelând funcţia compile_set aceste elemente se vor schimba ı̂n
0000, 0101 şi 1110, respectiv.
Sarcina voastră este să scrieţi un program care găseşte premutarea interacţionând cu structura
de date. Acest program ar trebui să facă următoarele lucruri (ı̂n această ordine):
1. să aleagă o mulţime de ı̂ntregi de biţi,
2. să insereze acei ı̂ntregi ı̂n structura de date,
3. să apeleze funcţia compile_set pentru a declanşa bug-ul,
4. să verifice prezenţa unor elemente din mulţimea modificată,
5. să folosească informaţia primită pentru a determina şi a ı̂ntoarce permutarea .
Reţineţi că programul vostru poate apela funcţia compile_set exact o dată.
În plus, numărul de apeluri ale funcţiilor din librărie este limitat. Mai exact, programul poate
` apela add_element de cel mult ori ( de la ”writes”),
` apela check_element de cel mult ori ( de la ”reads”).
Detalii de implementare
Trebuie să implementaţi o funcţie (metodă):
Dacă programul vostru ı̂ncalcă vreuna din restricţiile de mai sus, rezultatul evaluării va fi
”Wrong Answer”.
Pentru toate stringurile, primul caracter denotă cel mai semnificativ bit al ı̂ntregului core-
spunzător.
Grader-ul fixează permutarea ı̂nainte ca funcţia restore_permutation să fie apelată.
Folosiţi fişierele template furnizate pentru detalii de implementare ı̂n limbajul vostru de pro-
gramare.
Exemple
Grader-ul face următorul apel:
Avem n 4 şi programul poate face cel mult 16 ”writes” şi 16 ”reads”.
Programul face următoarele apeluri de funcţii:
` add_element("0001")
` add_element("0011")
` add_element("0100")
` compile_set()
` check_element("0001") returnează false
` check_element("0010") returnează true
` check_element("0100") returnează true
` check_element("1000") returnează false check_element("0011") returnează
false
` check_element("0101") returnează false
` check_element("1001") returnează false
` check_element("0110") returnează false
` check_element("1010") returnează true
` check_element("1100") returnează false
Sample grader
Sample grader-ul citeşte input-ul ı̂n următorul format:
` linia 1: ı̂ntregii n, w, r,
` linia 2: n ı̂ntregi, reprezentând elementele lui p.
add_element("10000000")
add_element("11000000")
add_element("11100000")
add_element("11110000")
add_element("11111000")
add_element("11111100")
add_element("11111110")
add_element("11111111")
aNow we will get positions of bits one by one. First, lets find the position of bit 0.
This can be done using at most n 1 queries:
check_element("10000000") returned false
check_element("01000000") returned false
check_element("00100000") returned false
check_element("00010000") returned false
check_element("00001000") returned false
check_element("00000100") returned true
a Now we know the position of bit 0 and want to find the position of bit 1. This can be done
using at most n 2 queries:
check_element("10000100") returned false
check_element("01000100") returned false
check_element("00100100") returned false
check_element("00010100") returned true
a And so on, we can find position of i-th bit using n i 1 queries, so the total number of
n n1
queries in the worst case is 2
496.
Subtask 3 can be solved by several optimizations of the previous algorithm. The simplest
n n1
one is to shuffle the order of bytes. This will give us the average number of queries 4
248,
which was enough to pass the tests.
Subtasks 4 and 5 require O n log n solution, in subtasks 4 you can make at most 2n log n
operations of each type, in subtasks 5 you can make only n log n operations.
Subtask 5 may be solved using divide and conquer technique. Lets try to split all bits into
two halves using n requests, and solve problem for each half independently. In this solution we
will make at most n log2 n operations of each type.
a To split group of bits into two halves, we will add into set n©2 elements, i-th element will
have i-th bit set to one, all other set to zero:
add_element("10000000")
add_element("01000000")
add_element("00100000")
add_element("00010000")
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 502
a After this, we will check n elements with single bit set to one. For example:
check_element("10000000") returned false
check_element("01000000") returned true
check_element("00100000") returned false
check_element("00010000") returned false
check_element("00001000") returned true
check_element("00000100") returned true
check_element("00000010") returned false
check_element("00000001") returned true
a Now we know, which n©2 bits correspond to first n©2 bits. In this example we know, that
bits 1, 4, 5, and 7 correspond to bits 0-3. So now we will solve same problem for them only, and
after that solve problem for other n©2 bits.
a In order to solve problem for some subset of bits, we need to make sure that the elements
we use in different subproblems are distinct. We can achieve this by setting all bits that are not
in our subset to ones. For example, when we want to split bits 03 into halves, we will make the
following operations.
add_element("10001111")
add_element("01001111")
check_element("11110010")
check_element("10111010")
check_element("10110110")
check_element("10110011")
#include<iostream>
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/subtask_4/014", // input
(char*)"../tests/subtask_4/014.a", // rezultat corect
(char*)"4-014.out.txt", // rezultat de verificat
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
//readBothSecrets(output_secret);
//readBothGraderResults();
//compareRemainingLines(3); // incepand cu linia nr 3
#include<ctime>
namespace variables
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int readInt()
{
int x;
cin >> x;
return x;
}
}
int main()
{
auto t1 = clock();
n = readInt();
w = readInt();
r = readInt();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
//printf("098d134608c94f7413faac591054ee35\n");
//if (p == answer) { printf("OK\n"); }
//else { printf("WA\n"); }
printf("%d", answer[0]);
for (int i = 1; i < n; i++)
{
printf(" %d", answer[i]);
}
printf("\n");
auto t4 = clock();
//cout<<"res = "<<res<<"\n";
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 504
return 0;
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
printf("WA\n");
exit(0);
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
printf("WA\n");
exit(0);
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
printf("WA\n");
exit(0);
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (const string& s : set_)
{
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[p[i]];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
int nn;
string address;
int x = 1;
int log = 0;
while (x < nn)
{
x *= 2;
log++;
}
for (int length = 1; length < log; length++)
{
for (int i = 0; i < (1 << length); i++)
{
helper(length, i);
}
}
}
#include<ctime>
#include "messy.h"
namespace helper
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int readInt()
{
int x;
cin >> x;
return x;
}
}
int main()
{
auto t1 = clock();
n = readInt();
w = readInt();
r = readInt();
p = vector<int>(n);
p[i] = readInt();
}
auto t2 = clock();
auto t3 = clock();
//printf("098d134608c94f7413faac591054ee35\n");
//if (p == answer) { printf("OK\n"); }
//else { printf("WA\n"); }
printf("%d", answer[0]);
for (int i = 1; i < n; i++)
{
printf(" %d", answer[i]);
}
printf("\n");
auto t4 = clock();
//cout<<"res = "<<res<<"\n";
return 0;
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
printf("WA\n");
exit(0);
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
printf("WA\n");
exit(0);
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
printf("WA\n");
exit(0);
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 508
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (const string& s : set_)
{
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[p[i]];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
#include <vector>
#include <string>
//#include "messy.h"
compile_set();
can[s] = c1;
can[s + len] = c2;
}
}
vector<int> ans(n);
for (int i = 0; i < n; i++) ans[can[i][0]] = i;
return ans;
}
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 509
/*
t2-t1 = 0
t3-t2 = 0.015
t4-t3 = 0
#include<ctime>
#include "messy.h"
namespace helper
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int readInt()
{
int x;
cin >> x;
return x;
}
}
int main()
{
auto t1 = clock();
n = readInt();
w = readInt();
r = readInt();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
//printf("098d134608c94f7413faac591054ee35\n");
//if (p == answer) { printf("OK\n"); }
//else { printf("WA\n"); }
printf("%d", answer[0]);
for (int i = 1; i < n; i++)
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 510
{
printf(" %d", answer[i]);
}
printf("\n");
auto t4 = clock();
//cout<<"res = "<<res<<"\n";
return 0;
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
printf("WA\n");
exit(0);
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
printf("WA\n");
exit(0);
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
printf("WA\n");
exit(0);
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (const string& s : set_)
{
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[p[i]];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 511
#include <bits/stdc++.h>
int N;
bool g[1234][1234];
if (k < 4)
{
string s(N, ’0’);
for (int i = 0; i < N; i++)
{
s[i] = ’1’;
add_element(s);
}
compile_set();
return ans;
}
put(0, 1);
put(0, 2);
put(1, 2);
for (int i = 2; i + 1 < k; i++)
{
put(i, i + 1);
}
put(1, 2, 3);
for (int i = k; i < N; i++)
{
for (int j = 0; j < k; j++)
{
if (i & (1 << j))
{
put(i, j);
}
}
}
compile_set();
assert(imp.size() == k);
for (int i = 0; i < k; i++)
{
for (int j = i + 1; j < k; j++)
{
g[imp[i]][imp[j]] = g[imp[j]][imp[i]] = check(imp[i], imp[j]);
}
}
bool ok = true;
for (int i = 2; i + 1 < k; i++)
{
if (!g[imp[i]][imp[i + 1]])
{
ok = false;
break;
}
}
if (ok)
{
if (!check(imp[1], imp[2], imp[3]))
{
continue;
}
found = true;
break;
}
} while (next_permutation(imp.begin(), imp.end()));
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 513
assert(found);
vector <int> ans(N, -1);
vector <bool> used(N, false);
int u = 0;
for (int j = k - 1; j >= 0; j--)
{
int options = 0;
int any = -1;
for (int z = u; z < u + (1 << (j + 1)); z++)
{
if (!used[z])
{
options++;
any = z;
}
}
if (options == 1)
{
u = any;
break;
}
if (check(i, imp[j]))
{
u |= (1 << j);
}
}
ans[i] = u;
used[u] = true;
}
return ans;
}
/*
t2-t1 = 0
t3-t2 = 0
t4-t3 = 0
//#include "messy.h"
//#include <vector>
//#include <string>
#include <algorithm>
#include <cassert>
#include <vector>
#include <cstdio>
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 514
#include <string>
#include <set>
#include <cstdlib>
#include <iostream>
#include<ctime>
#include "messy.h"
namespace helper
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int read_int()
{
int x;
cin >> x;
return x;
}
}
// A convenience function.
int get_p(int i)
{
int ret = p[i];
return ret;
}
int main()
{
auto t1 = clock();
n = read_int();
w = read_int();
r = read_int();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
if (answer.size() != n)
{
printf("WA\n");
return 0;
}
printf("%d", answer[0]);
auto t4 = clock();
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 515
//cout<<"res = "<<res<<"\n";
return 0;
}
void wa()
{
printf("WA\n");
exit(0);
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
wa();
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
wa();
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
wa();
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
{
string s = *it;
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[get_p(i)];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
int N;
vector<int> ans_rev;
compile_set();
ans_rev.resize(N, -1);
vector<int> A;
for(int i = 0; i < N; i++) A.push_back(i);
solve(0, N - 1, A, {});
vector<int> ans(N);
for(int i = 0; i < N; i++) ans[ans_rev[i]] = i;
return ans;
}
/*
t2-t1 = 0
t3-t2 = 0.015
t4-t3 = 0
// https://oj.uz/submission/23726
#include <bits/stdc++.h>
#include "messy.h"
#include <vector>
#include <cstdio>
#include <string>
#include <set>
#include <cstdlib>
#include <iostream>
#include<ctime>
#include "messy.h"
namespace helper
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int read_int()
{
int x;
cin >> x;
return x;
}
}
// A convenience function.
int get_p(int i)
{
int ret = p[i];
return ret;
}
int main()
{
auto t1 = clock();
n = read_int();
w = read_int();
r = read_int();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
if (answer.size() != n)
{
printf("WA\n");
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 518
return 0;
}
printf("%d", answer[0]);
auto t4 = clock();
//cout<<"res = "<<res<<"\n";
return 0;
}
void wa()
{
printf("WA\n");
exit(0);
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
wa();
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
wa();
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
wa();
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
{
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 519
string s = *it;
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[get_p(i)];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
// [l, r)
void go (int n, int l, int r)
{
if (l + 1 == r) return;
int m = l + r >> 1;
string s = "";
for (int i = 0; i < n; ++i)
{
s += ’1’;
}
for (int i = l; i < r; ++i)
{
s[i] = ’0’;
}
for (int i = l; i < m; ++i)
{
s[i] = ’1’;
add_element(s);
s[i] = ’0’;
}
go(n, l, m);
go(n, m, r);
}
vector <int> v;
kill(n, l, m, y);
kill(n, m, r, x);
}
#include "messy.h"
#include <bits/stdc++.h>
#include <vector>
#include <cstdio>
#include <string>
#include <set>
#include <cstdlib>
#include <iostream>
#include<ctime>
#include "messy.h"
namespace helper
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int read_int()
{
int x;
cin >> x;
return x;
}
}
// A convenience function.
int get_p(int i)
{
int ret = p[i];
return ret;
}
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 521
int main()
{
auto t1 = clock();
n = read_int();
w = read_int();
r = read_int();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
if (answer.size() != n)
{
printf("WA\n");
return 0;
}
printf("%d", answer[0]);
auto t4 = clock();
//cout<<"res = "<<res<<"\n";
return 0;
}
void wa()
{
printf("WA\n");
exit(0);
}
void add_element(string x)
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 522
{
if (--w < 0 || compiled || !check(x))
{
wa();
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
wa();
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
wa();
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
{
string s = *it;
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[get_p(i)];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
//int n, occ[128];
int occ[128];
{
str.push_back(’0’);
}
for(auto &i : c)
{
str[i] = ’1’;
}
vector<int> l, h;
for(auto &j : c)
{
str[j] = ’0’;
if(check_element(str)) h.push_back(j);
else l.push_back(j);
str[j] = ’1’;
}
solve2(s, m, l);
solve2(m+1, e, h);
}
#include "messy.h"
#include <bits/stdc++.h>
#include <vector>
#include <cstdio>
#include <string>
#include <set>
#include <cstdlib>
#include <iostream>
#include<ctime>
#include "messy.h"
namespace helper
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int read_int()
{
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 524
int x;
cin >> x;
return x;
}
}
// A convenience function.
int get_p(int i)
{
int ret = p[i];
return ret;
}
int main()
{
auto t1 = clock();
n = read_int();
w = read_int();
r = read_int();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
if (answer.size() != n)
{
printf("WA\n");
return 0;
}
printf("%d", answer[0]);
auto t4 = clock();
//cout<<"res = "<<res<<"\n";
return 0;
}
void wa()
{
printf("WA\n");
exit(0);
}
{
return false;
}
for (int i = 0; i < n; i++)
{
if (x[i] != ’0’ && x[i] != ’1’)
{
return false;
}
}
return true;
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
wa();
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
wa();
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
wa();
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
{
string s = *it;
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[get_p(i)];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
string s;
//int n;
vector<int> ans;
rec1(m+1, r);
}
#include <vector>
#include "messy.h"
#include <string>
#include <vector>
#include <cstdio>
#include <string>
#include <set>
#include <cstdlib>
#include <iostream>
#include<ctime>
#include "messy.h"
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 527
namespace helper
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int read_int()
{
int x;
cin >> x;
return x;
}
}
// A convenience function.
int get_p(int i)
{
int ret = p[i];
return ret;
}
int main()
{
auto t1 = clock();
n = read_int();
w = read_int();
r = read_int();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
if (answer.size() != n)
{
printf("WA\n");
return 0;
}
printf("%d", answer[0]);
auto t4 = clock();
//cout<<"res = "<<res<<"\n";
return 0;
}
void wa()
{
printf("WA\n");
exit(0);
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
wa();
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
wa();
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
wa();
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
{
string s = *it;
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[get_p(i)];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
// [l..r)
void Add(int l, int r, string base)
{
if (l + 1 == r) return;
int mid = (l + r) / 2;
for (int i = l; i < mid; ++i)
{
base[i] = ’1’;
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 529
add_element(base.c_str());
base[i] = ’0’;
}
vector<int> ans;
compile_set();
ans.resize(n);
vector<int> all;
for (int i = 0; i < n; ++i) all.push_back(i);
Solve(0, n, all, string(n, ’0’));
return ans;
}
/*
t2-t1 = 0
t3-t2 = 0.015
t4-t3 = 0
#include <bits/stdc++.h>
#include "messy.h"
//#include "grader.cpp"
#include <vector>
#include <cstdio>
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 530
#include <string>
#include <set>
#include <cstdlib>
#include <iostream>
#include<ctime>
#include "messy.h"
namespace helper
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int read_int()
{
int x;
cin >> x;
return x;
}
}
// A convenience function.
int get_p(int i)
{
int ret = p[i];
return ret;
}
int main()
{
auto t1 = clock();
n = read_int();
w = read_int();
r = read_int();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
if (answer.size() != n)
{
printf("WA\n");
return 0;
}
printf("%d", answer[0]);
auto t4 = clock();
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 531
//cout<<"res = "<<res<<"\n";
return 0;
}
void wa()
{
printf("WA\n");
exit(0);
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
wa();
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
wa();
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
wa();
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
{
string s = *it;
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[get_p(i)];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
//int n;
string s;
vector <int> ans, vv;
int md = (l + r) >> 1;
for(int i = l; i <= md; i ++)
{
s[i] = ’1’;
add_element(s);
s[i] = ’0’;
}
fun(l, md);
fun(md + 1, r);
}
int p1 = 0, p2 = 0;
for(int i = l; i <= r; i ++)
{
if(i <= md)
{
ans[i] = v1[p1 ++];
}
else
{
ans[i] = v2[p2 ++];
}
}
rec(l, md);
rec(md + 1, r);
}
#include <vector>
#include<string>
#include "messy.h"
using namespace std;
#include <vector>
#include <cstdio>
#include <string>
#include <set>
#include <cstdlib>
#include <iostream>
#include<ctime>
#include "messy.h"
namespace helper
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int read_int()
{
int x;
cin >> x;
return x;
}
}
// A convenience function.
int get_p(int i)
{
int ret = p[i];
return ret;
}
int main()
{
auto t1 = clock();
n = read_int();
w = read_int();
r = read_int();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
if (answer.size() != n)
{
printf("WA\n");
return 0;
}
printf("%d", answer[0]);
auto t4 = clock();
//cout<<"res = "<<res<<"\n";
return 0;
}
void wa()
{
printf("WA\n");
exit(0);
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
wa();
}
set_.insert(x);
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 535
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
wa();
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
wa();
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
{
string s = *it;
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[get_p(i)];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
//int n;
string s[1000];
vector<int> g;
void add_build(int l,int r,int v)
{
if(l==r)
return;
string t;
for(int i=0;i<n;i++)
{
if(i>=l && i<=r)
t+=’0’;
else
t+=’1’;
}
int mid=(l+r)/2;
for(int i=l;i<=mid;i++)
{
t[i]=’1’;
add_element(t);
t[i]=’0’;
}
add_build(l,mid,2*v);
add_build(mid+1,r,2*v+1);
}
s[2*v]=s[v];
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 536
s[2*v+1]=s[v];
for(int i=0;i<n;i++)
{
if(s[v][i]==’1’)
continue;
s[v][i]=’1’;
if(check_element(s[v]))
s[2*v+1][i]=’1’;
else
s[2*v][i]=’1’;
s[v][i]=’0’;
}
int mid=(l+r)/2;
check_build(l,mid,2*v);
check_build(mid+1,r,2*v+1);
}
#include <bits/stdc++.h>
#include "messy.h"
using namespace std;
#include <vector>
#include <cstdio>
#include <string>
#include <set>
#include <cstdlib>
#include <iostream>
#include<ctime>
#include "messy.h"
namespace helper
{
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int read_int()
{
int x;
cin >> x;
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 537
return x;
}
}
// A convenience function.
int get_p(int i)
{
int ret = p[i];
return ret;
}
int main()
{
auto t1 = clock();
n = read_int();
w = read_int();
r = read_int();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
if (answer.size() != n)
{
printf("WA\n");
return 0;
}
printf("%d", answer[0]);
auto t4 = clock();
//cout<<"res = "<<res<<"\n";
return 0;
}
void wa()
{
printf("WA\n");
exit(0);
}
}
for (int i = 0; i < n; i++)
{
if (x[i] != ’0’ && x[i] != ’1’)
{
return false;
}
}
return true;
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
wa();
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
wa();
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
wa();
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
{
string s = *it;
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[get_p(i)];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
//int n;
//vector<int> p;
return;
}
int m = l + r >> 1;
string base(n, ’1’);
vector<int> L, R;
for(int i : v) base[i] = ’0’;
for(int i : v)
{
string s = base;
s[i] = ’1’;
if(check_element(s))
L.push_back(i);
else R.push_back(i);
}
solve(l, m, L);
solve(m + 1, r, R);
}
#include <vector>
#include <cstdio>
#include <string>
#include <set>
#include <cstdlib>
#include <iostream>
#include<ctime>
#include "messy.h"
namespace helper
{
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 540
set<string> set_;
bool compiled = false;
int n;
vector<int> p;
int w;
int r;
int read_int()
{
int x;
cin >> x;
return x;
}
}
// A convenience function.
int get_p(int i)
{
int ret = p[i];
return ret;
}
int main()
{
auto t1 = clock();
n = read_int();
w = read_int();
r = read_int();
p = vector<int>(n);
auto t2 = clock();
auto t3 = clock();
if (answer.size() != n)
{
printf("WA\n");
return 0;
}
printf("%d", answer[0]);
auto t4 = clock();
//cout<<"res = "<<res<<"\n";
return 0;
}
CAPITOLUL 4. IOI 2016 4.5. UNSCRAMBLING A MESSY BUG 541
void wa()
{
printf("WA\n");
exit(0);
}
void add_element(string x)
{
if (--w < 0 || compiled || !check(x))
{
wa();
}
set_.insert(x);
}
bool check_element(string x)
{
if (--r < 0 || !compiled || !check(x))
{
wa();
}
return set_.count(x);
}
void compile_set()
{
if (compiled)
{
wa();
}
compiled = true;
set<string> compiledSet;
string compiledElement = string(n, ’ ’);
for (set<string>::iterator it = set_.begin(); it != set_.end(); it++)
{
string s = *it;
for (int i = 0; i < n; i++)
{
compiledElement[i] = s[get_p(i)];
}
compiledSet.insert(compiledElement);
}
set_ = compiledSet;
}
#include "messy.h"
string t;
vector<int> ans;
for(int i=l;i<=m;++i)
t[i]=’1’,add_element(t),t[i]=’0’;
for(int i=m+1;i<=r;++i)
t[i]=’1’;
add(l,m);
for(int i=m+1;i<=r;++i)
t[i]=’0’;
for(int i=l;i<=m;++i)
t[i]=’1’;
add(m+1,r);
for(int i=l;i<=m;++i)
t[i]=’0’;
}
4.6 Aliens
Problema 6 - Aliens 100 de puncte
interes pe fotografie. Punctele sunt numerotate de la 0 la n 1. Acum dorim să obţinem fotografii
de rezoluţie ı̂naltă care să conţină toate aceste n puncte.
Satelitul a divizat aria fotografiei de rezoluţie joasă ı̂ntr-un caroiaj de m pe m celule pătrate
cu laturi unitare. Atât liniile, cât şi coloanele caroiajului sunt numerotate consecutiv de la 0 la
m 1 (pornind din stânga, respectiv -sus). Vom folosi s, t pentru a marca celula din linia s şi
coloana t. Punctul cu numărul i se află ı̂n celula ri , ci . Fiecare celulă poate conţine un număr
arbitrar de asemenea puncte.
Satelitul nostru are o orbită stabilă care trece direct pe diagonala principală a caroiajului.
Diagonala principală este segmentul de linie care uneşte colţul de stı̂ngasus cu colţul de dreapta-
jos al caroiajului. Satelitul poate face fotografii de rezoluţiie ı̂naltă pe orice suprafaţă care satisface
următoarelor condiţii:
` conturul suprafeţei este un pătrat,
` două colţuri diagonal opuse ale pătratului aparţin diagonalei principale a caroiajului,
` Oricare celulă a caroiajului este ı̂n ı̂ntregime sau ı̂n interiorul suprafeţei fotografiate, sau ı̂n
afara ei.
Sarcina ta este să găseşti cel mai mic număr total posibil al celulelor fotografiate.
Detalii de implementare
Trebuie să implementezi următoarea funcţie (metodă):
Te rugăm să foloseşti fişierele-template furnizate pentru detalii de implementare ı̂n limbajul
de programare pe care ı̂l utilizezi.
Exemple
Exemplul 1
În acest exemplu avem un caroiaj 7 7 cu 5 puncte de interes. Punctele de interes sunt
localizate ı̂n patru celule disticte: (0,3), (4,4), (4,5) şi (4,6). Poţi face cel mult 2 fotografii de
rezoluţie ı̂naltă.
O soluţie pentru a captura toate cele cinci puncte de interes este de a face două fotografii:
prima, un pătrat de dimensiunea 6 6 conţinând celulele (0,0) şi (5,5), şi a doua, un pătrat de
dimensiunea 3 3 conţinând celulele (4,4) şi (6,6). Dacă satelitul va face aceste două fotografii,
vor fi transmise date despre 41 de celule. Această soluţie nu este optimă.
Soluţia optimă foloseşte o fotografie pentru a captura imaginea unui pătrat 4 4 care va conţine
celulele (0,0) şi (3,3) şi o a doua fotografie pentru a captura imaginea unui pătrat 3 3 care va
conţine celulele (4,4) şi (6,6). Acest rezultat conţine doar 25 de celule fotografiate, rezultat optim.
Astfel take_photos va returna 25.
De remarcat că este suficient ca celula (4,6) să fie fotografiată o singură dată, chiar dacă conţine
două puncte de interes.
CAPITOLUL 4. IOI 2016 4.6. ALIENS 544
Acest exemplu este prezentat ı̂n figurile care urmează. Figura din stânga prezintă caroiajul care
corespunde exemplului. Figura din mijloc prezintă soluţia suboptimală, ı̂n care sunt fotografiate
41 celule. Figura din dreapta prezintă soluţia optimă.
Exemplul 2
Aici avem 2 puncte de interes localizate simetric ı̂n celulele (1,4) şi (4,1). Oricare fotofrafie
validă care conţine unul dintre puncte, ı̂l va conţine şi pe celălalt. Prin urmare, este suficient să
fie făcută o singură fotografie.
Figura care urmează prezintă acest exemplu şi soluţia lui optimă. În această soluţie satelitul
captează o singură fotografie cu imagini a 16 celule.
Subtask-uri
Pentru toate subtask-urile, 1 & k & n.
1. (4 puncte) 1 & n & 50, 1 & m & 100, k n,
2. (12 puncte) 1 & n & 500, 1 & m & 1000, pentru toţi i astfel ı̂ncât 0 & i & n 1, ri ci ,
3. (9 puncte) 1 & n & 500, 1 & m & 1000,
4. (16 puncte) 1 & n & 50, 1 & m & 100, 1 & n & 50,
5. (19 puncte) 1 & n & 50 000, 1 & k & 100, 1 & m & 1 000 000,
6. (40 puncte) 1 & n & 100 000, 1 & m & 1 000 000.
Sample grader
` linia 1: ı̂ntregii , şi ,
` linia 2 i (0 & i & n 1): ı̂ntregii ri şi ci .
If a photo covers two points x; x and y; y , then it also covers all points between them.
Each photo’s boundary must be equal to some ri .
Now we can treat this problem as a dynamic programming problem: cover n points on line
using k segments such that sum of squares of their lengths is as small as possible. Start with
pre-processing the input data: sort all points by ri and remove duplicates. Notice that each photo
should cover some contiguous set of points.
Let fi,j be the minimum cost to cover first i points with at most j photos.
f0,j 0 for all 0 & j & k.
2
fi,j mint$i ft,j 1 ri1 lt 1 .
fn,k contains the answer.
O nk states, calculating transitions from each state takes O n time.
2
Overall running time: O n k .
Subtask 3 dropped the ri ci restriction. We’ll describe the similar DP solution for this
subtask. It’s possible to prove that photo containing points x; x and y; y covers point r; c if
and only if segment min r, c; max r, c is fully contained in segment x, y (x & y).
So if we consider segments min ri , ci ; max ri , ci instead of points ri , ci , the problem is
reduced to the following: cover all n segments with k larger segments such that their total area
(considering intersections) is minimized.
If segment Si is included in some other segment Sj , then any photo that covers Sj also covers
Si , so we can safely remove Si . Removing all such segments can be done in O n log n time:
Now, since all left endpoints are increasing and no segment is included in the other, then for
all i $ j ri $ rj and ci $ cj . Observations and definition of fi,j are almost identical to previous
solution:
Subtasks 4 and 5. Here you were required to come up with an optimization of the DP
2
solution described above. Subtask 4 allowed O n solutions. One possible solution uses the
Knuth’s optimization.
2 2
Define Ai,j as the optimal t in (1) and cost t, i ri1 lt 1 max 0, rt1 lt 1 .
Lemma: Ai,j 1 & Ai,j & Ai1,j
2
This allows us to prune the search space on each step, reducing the running time to O n .
If you calculate fi,j in order of increasing j and decreasing i, then at the moment of calculating
fi,j , values of Ai,j 1 and Ai1,j are already known, so you can only check t " Ai,j 1 ; Ai1,j .
CAPITOLUL 4. IOI 2016 4.6. ALIENS 546
It can be rather dificult to prove the correctness formally, but it’s easy to be convinced this is
true. A possible strategy for the competition would be to implement this solution without a formal
proof, then test the hypothesis on smaller inputs using the solution for subtask 3. It is known
2
that this optimization results in O n running time. Also, don’t forget about 64 bit integers.
Subtask 5 required a different kind of optimization, running in O nk or O nk log n time.
Implementing any of the two following optimizations was enough to pass all the tests from this
subgroup.
2 2
fi,j min ft,j 1 ri1 lt 1 max 0, rt1 lt 1
t$i
2 2 2
min ft,j 1 ri1 2 lt 1ri1 lt 1 max 0; rt1 lt 1
t$i
Ci min Mt ri1 Bt,j
t$i
2 2 2
where Ci ri1 , Mt 2 lt 1, Bt,j ft,j 1 lt 1 max 0, rt1 lt 1 .
We see that the formula can be expressed in terms of minimum of linear functions Mt x Bt,j ,
evaluated at x ri1 . Notice that as i increases, Mi decreases and ri increases. That allows us to
maintain the lower envelope of these linear functions using a stack and query the minimum value
at given x.
Adding a line and querying a point can be implemented in O 1 amortized time, so the total
running time is O nk . This technique is often referred to as the Convex Hull Trick. We will also
use it to get the 100 point solution for this problem.
Subtask 6. Let’s look at fi,k as a function of k and study the differences between two
adjacent values. The following theorem states that these differences are non-increasing. We’ll call
such functions convex.
Theorem: fi,j 1 fi,j ' fi,j fi,j 1
Let’s assign some constant penalty C for each photo. The new cost function e fi,j fi,j jC x
x x
is still convex, because fi,j 1 fi,j fi;j 1 fi,j C.
Let’s introduce another optimization problem without the restriction on number of photos.
gi
n
x
min fi,k
k 1
n
min fi,k kC
k 1
This equation for gi can also be expressed only in terms of previous values of gj (j $ i).
2 2
gi min gt ri1 lt 1 max 0, rt1 lt 1 C
t$i
CAPITOLUL 4. IOI 2016 4.6. ALIENS 547
Using this formula, all gi can be computed in O n time using Convex Hull Trick optimization,
if all li and ri are sorted beforehand. The solution from subtask 5 can also be modified to find
the minimum number of photos required to achieve the optimum, call it p C .
x x x
Since e f is convex, p C is also equal to the minimum x such that fn,x fn,x1 & 0 which is
equivalent to fn,x fn,x1 & C, so p C is monotone.
2
Also if we set C 0, optimum value of gn is achieved with the n photos, and if we set C M ,
then the optimal solution only contains one photo.
Combining everything above, we can use binary search to find such Copt that p1 p Copt ' k
and p2 p Copt 1 & k.
This means that all differences fn,p2 fn,p2 1 ; fn,p2 1 fn,p2 2 , ..., fn,p1 1 fn,p1 are
equal, and fn,j is a linear function of j on this interval. Since the desired value of fn,k is somewhere
in this interval, it’s possible to calculate it just by linear interpolation, because all slopes are equal.
This solution requires sorting the segments once and doing O log m iterations of binary search
to find Copt , each iteration running in linear time.
Total running time: O n log n n log m.
#include<iostream>
int main()
//int main(int argc, char* argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/subtask_6/175", // input
(char*)"../tests/subtask_6/175.a", // rezultat corect
(char*)"6-175.out.txt", // rezultat de verificat
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
registerTestlibCmd(argc, argv);
if (pans != jans)
{
quitf(_wa, "Wrong answer: output = %lld, expected = %lld", pans, jans);
}
CAPITOLUL 4. IOI 2016 4.6. ALIENS 548
else
{
quitf(_ok, "Correct answer: answer = %lld", pans);
}
}
#include<ctime>
struct range
{
ll s, e;
friend bool operator < (const range &a, const range &b)
{
if (a.s == b.s)
return (a.e > b.e) ? true : false;
else
return (a.s < b.s) ? true : false;
}
};
struct point
{
ll x, y;
};
struct line
{
ll m, c;
};
struct hull_line
{
ll m, c;
ll k;
};
class Hull
{
private:
int cur, len;
hull_line *L;
double getx(ll m1, ll c1, ll m2, ll c2);
public:
void addline(ll m, ll c, ll k);
pair<ll,ll> getmin(ll x);
void resetline();
Hull();
˜Hull();
};
Hull::Hull()
{
L = (hull_line*)malloc(MAXN * sizeof(hull_line));
}
Hull::˜Hull()
{
free(L);
CAPITOLUL 4. IOI 2016 4.6. ALIENS 549
void Hull::addline(ll m, ll c, ll k)
{
while (len >= 2)
{
double a = getx(m, c, L[len-1].m, L[len-1].c);
double b = getx(m, c, L[len-2].m, L[len-2].c);
if (a > b) break;
len--;
}
L[len].m = m;
L[len].c = c;
L[len].k = k;
len++;
}
pair<ll,ll> Hull::getmin(ll x)
{
if (cur >= len) cur = len-1;
while (cur < len-1)
{
double a = getx(L[cur].m, L[cur].c, L[cur+1].m, L[cur+1].c);
if (x > a)
cur++;
else
break;
// in case x==a first such line is considered
// It can be proven using convex property
// that k increase as cur increases
}
return make_pair(L[cur].m * x + L[cur].c, L[cur].k);
}
void Hull::resetline()
{
len = 0;
cur = 0;
}
if (found)
{
return res.first - (med+1LL) * K;
}
else
if (kr - kl > 1)
{
// slope is equal from kl to kr.
// Since odd C values are used in hull() it always returns
// leftmost k out of those slopes for given C. i.e. slopes are always even
res = hull(r, cl+1LL, h);
ll fl = res.first - (cl + 1LL) * kl;
res = hull(r, cr+1LL, h);
ll fr = res.first - (cr + 1LL) * kr;
ll h = (fl-fr) / (kr - kl); // interpolate
return fl - (K - kl) * h;
}
else
{
if (kr == K)
{
res = hull(r, cr + 1LL, h);
return res.first - (cr + 1LL) * K;
}
else
{ //kr = K
res = hull(r, cl + 1LL, h);
return res.first - (cl + 1LL) * kl;
}
}
}
return res;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.328
t3-t2 = 0.906
t4-t3 = 0
#include<ctime>
llong sqr(int x)
{
return 1ll * x * x;
}
struct vt
{
llong x, y;
int num = -1;
vt(llong _x, llong _y)
{
x = _x, y = _y;
}
vt() {}
friend vt operator -(vt a, vt b)
{
return vt(a.x - b.x, a.y - b.y);
}
friend llong operator ˆ(vt a, vt b)
{
return a.x * b.y - b.x * a.y;
}
friend llong operator *(vt a, vt b)
{
return a.x * b.x + a.y * b.y;
}
};
vector<int> L, R;
for (auto pr : M)
{
while (!L.empty() && L.back() >= pr.second)
L.pop_back(), R.pop_back();
R.push_back(pr.first);
L.push_back(pr.second);
}
n = L.size();
assert(is_sorted(R.begin(), R.end()));
assert(is_sorted(L.begin(), L.end()));
if (i)
{
int r2 = R[i - 1];
vt dir(1, r2);
while (pt + 1 < (int)st.size())
{
llong scal1 = st[pt] * dir;
llong scal2 = st[pt + 1] * dir;
if (scal2 < scal1)
pt++;
else
break;
}
val = st[pt] * dir + x + (llong)r2 * r2;
}
st.push_back(cur);
pt = min(pt, (int)st.size() - 1);
}
return ans;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.312
t3-t2 = 1.609
t4-t3 = 0
#include<ctime>
llong sqr(int x)
{
return 1ll * x * x;
}
struct vt
{
double x, y;
int num = -1;
vt(double _x, double _y)
{
x = _x, y = _y;
}
vt() {}
friend vt operator -(vt a, vt b)
{
return vt(a.x - b.x, a.y - b.y);
}
friend llong operator ˆ(vt a, vt b)
{
return a.x * b.y - b.x * a.y;
}
friend llong operator *(vt a, vt b)
{
return a.x * b.x + a.y * b.y;
}
double slope()
{
return y / x;
}
};
x = row[i];
y = column[i];
if (x < y)
swap(x, y);
if (!M.count(x))
M[x] = x;
M[x] = min(M[x], y);
}
vector<int> L, R;
for (auto pr : M)
{
while (!L.empty() && L.back() >= pr.second)
L.pop_back(), R.pop_back();
R.push_back(pr.first);
L.push_back(pr.second);
}
n = L.size();
assert(is_sorted(R.begin(), R.end()));
assert(is_sorted(L.begin(), L.end()));
st.push_back(cur);
pt = min(pt, (int)st.size() - 1);
}
return ans;
}
CAPITOLUL 4. IOI 2016 4.6. ALIENS 556
// BEGIN CUT
int main()
{
auto t1 = clock();
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
// END CUT
/*
t2-t1 = 0.343
t3-t2 = 1.719
t4-t3 = 0
#include "aliens.h"
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#include<ctime>
struct point
{
int x, y;
bool operator<(const point &p) const
{
CAPITOLUL 4. IOI 2016 4.6. ALIENS 557
int n, m, k;
vector<point> _ps;
vector<point> ps;
llong sqr(int x)
{
return (llong)x * x;
}
struct line
{
int cnt;
llong m, b;
} st[100000];
void push(line x)
{
while (top > bot && (ld)(x.b - st[top].b) / (st[top].m - x.m)
<= (ld)(st[top - 1].b - st[top].b) / (st[top].m - st[top - 1].m))
--top;
st[++top] = x;
}
llong dp[100000];
int cnt[100000];
int getPhoto(llong c)
{
top = -1; bot = 0;
push({ 0, -2ll * ps[0].x, sqr(ps[0].x) });
for (int i = 0; i < n; ++i)
{
auto ret = query(ps[i].y + 1);
dp[i] = ret.second + sqr(ps[i].y + 1) + c;
cnt[i] = ret.first + 1;
if (i < n - 1)
push({ cnt[i],
-2ll * ps[i + 1].x,
dp[i] + sqr(ps[i + 1].x) -
sqr(max(0, ps[i].y - ps[i + 1].x + 1)) });
}
return cnt[n - 1];
}
_ps.reserve(n);
ps.reserve(n);
sort(_ps.begin(), _ps.end());
n = ps.size();
k = min(n, k);
llong s = 0ll, e = (llong)m * m;
int l = -1, r = n + 1;
llong lvalue, rvalue;
while (s <= e)
{
llong m = (s + e) / 2;
int ret = getPhoto(m);
if (ret == k) return dp[n - 1] - ret * m;
if (ret < k)
{
e = m - 1;
if (l < ret)
{
l = ret; lvalue = dp[n - 1] - ret * m;
}
}
else
{
s = m + 1;
if (ret < r)
{
r = ret; rvalue = dp[n - 1] - ret * m;
}
}
}
return rvalue + ((lvalue - rvalue) / (r - l)) * (r - k);
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
CAPITOLUL 4. IOI 2016 4.6. ALIENS 559
return 0;
}
// END CUT
/*
t2-t1 = 0.328
t3-t2 = 0.609
t4-t3 = 0
#include <bits/stdc++.h>
#include "aliens.h"
pp po[100010];
ll x[100010];
ll y[100010];
int pn;
ll dp[100010];
int top;
ll grad[100010];
ll yint[100010];
int lid[100010];
void add_line(ll g, ll y, int id)
{
while(top>=2)
{
if((yint[top-2]-yint[top-1])*(grad[top-1]-g)>
(yint[top-1]-y)*(grad[top-2]-grad[top-1])) break;
--top;
}
grad[top] = g;
yint[top] = y;
lid[top] = id;
++top;
}
int bx;
ll f(int p, ll x){ return grad[p]*x + yint[p]; }
inline ll sqr(ll x){ return x*x; }
int lst[100010];
}
}
int cnt = 0;
for(int i=pn-1; i!=-1; i=lst[i]) ++cnt;
return cnt;
}
sort(po, po+n);
ll cl = -1, cr = m*1LL*m;
while(cl+1 < cr)
{
ll mid = (cl+cr)/2;
(F(mid) <= k ? cr : cl) = mid;
}
F(cr);
return dp[pn-1]-cr*k;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.281
t3-t2 = 0.406
t4-t3 = 0
#include <bits/stdc++.h>
#include "aliens.h"
using namespace std;
struct cht
{
vector<ll> m, b, k; int ptr = 0;
bool bad(int l1, int l2, int l3)
{
return 1.0 * (b[l3] - b[l1]) * (m[l1] - m[l2]) <=
1.0 * (b[l2] - b[l1]) * (m[l1] - m[l3]);
}
li query(ll x)
{
if(ptr >= m.size()) ptr = m.size() - 1;
while(ptr < m.size() - 1 &&
f(ptr, x) > f(ptr + 1, x)) ptr++;
return { f(ptr, x), k[ptr] };
}
void clear() { m.clear(), b.clear(), k.clear(); ptr = 0; }
} ds;
li get(ll C)
{
int n = l.size() - 1;
li dp[n + 1];
dp[0] = {0, 0};
ds.clear(); ds.add(-2ll * l[1], sq(l[1]), 0);
CAPITOLUL 4. IOI 2016 4.6. ALIENS 562
sort(tmp.begin(), tmp.end());
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
CAPITOLUL 4. IOI 2016 4.6. ALIENS 563
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.296
t3-t2 = 4.025
t4-t3 = 0
#include "aliens.h"
#include <bits/stdc++.h>
using namespace std;
vector<pii> V;
void compress()
{
sort(all(V), [](pii a, pii b)
{ if(a.x == b.x) return a.y > b.y; return a.x < b.x; });
int en = -1;
vector<pii> ret;
for(auto x : V)
if(x.y > en)
en = x.y, ret.emplace_back(x);
V = ret;
}
struct cht
{
struct line
{
long long m, c;
int cnt;
line(long long m, long long c, int cnt) : m(m), c(c), cnt(cnt) {}
long long get(long long x) { return m * x + c; }
};
vector<line> f;
bool bad(line l1, line l2, line l3)
{
return (l1.c - l3.c) * (l2.m - l1.m) <=
(l3.m - l1.m) * (l1.c - l2.c);
}
f.emplace_back(l);
}
int idx;
pair<long long, int> query(long long x)
{
while(idx + 1 < f.size() and f[idx+1].get(x) < f[idx].get(x))
++idx;
return make_pair(f[idx].get(x), f[idx].cnt);
}
void clear()
{
f.clear(), idx = 0;
}
} hull;
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
CAPITOLUL 4. IOI 2016 4.6. ALIENS 565
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.296
t3-t2 = 1.313
t4-t3 = 0
#include <bits/stdc++.h>
#include "aliens.h"
sort(p.begin(), p.end());
{
vector<pair<int, int>> new_p;
for (int i = 0, j = 0; i < n; i = j)
{
while (j < n && p[j].first == p[i].first)
{
++j;
}
if (new_p.empty() || p[j - 1].second > new_p.back().second)
{
new_p.push_back(p[j - 1]);
}
}
swap(p, new_p);
n = p.size();
}
k = min(k, n);
vector<int> x(n), y(n);
q[r++] = i;
while (r - l > 1 && f[q[l]] + sqr(y[i] - x[q[l]] + 1) >
f[q[l + 1]] + sqr(y[i] - x[q[l + 1]] + 1))
{
++l;
}
solve(high);
return f[n] - k * high;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
CAPITOLUL 4. IOI 2016 4.6. ALIENS 567
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.296
t3-t2 = 1.282
t4-t3 = 0
#include<bits/stdc++.h>
#include "aliens.h"
struct node
{
LL x,y,i;
}V[MAX_N],line[MAX_N];
LL n,m,k,s,e;
LL dp[MAX_N],from[MAX_N];
LL is_ok(LL x)
{
LL i;
s=e=0;
add(-2*V[1].x,sq(V[1].x)-2*V[1].x,0);
for(i=1;i<=n;i++)
{
while(e-s>1 && get_val(s,V[i].y)>=get_val(s+1,V[i].y)) s++;
dp[i]=get_val(s,V[i].y)+sq(V[i].y+1)+x;
from[i]=line[s].i;
add(-2*V[i+1].x,
sq(V[i+1].x)+
dp[i]-2*V[i+1].x-
sq(max(0LL,V[i].y-V[i+1].x+1)),
i);
}
i=n;
LL c;
for(c=0;i;i=from[i],c++);
return c;
}
sort(V+1,
V+n+1,
[&](const node x,const node y)
{
return (x.x==y.x)?x.y>y.y:x.x<y.x;
});
m=n;
n=0;
x=-inf;
for(i=1;i<=m;i++)
{
if(x>=V[i].y) continue;
V[++n]=V[i];
x=V[i].y;
}
LL l,rr;
l=0;
rr=sq((LL)M);
k=min(k,n);
LL mid,ans=0;
while(l<=rr)
{
mid=(l+rr)>>1;
x=is_ok(mid);
if(x==k) return dp[n]-k*mid;
if(x<k) rr=mid-1;
else
{
l=mid+1;
ans=max(ans,dp[n]-k*mid);
}
}
return ans;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
CAPITOLUL 4. IOI 2016 4.6. ALIENS 569
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.312
t3-t2 = 0.438
t4-t3 = 0
#include "aliens.h"
#include <bits/stdc++.h>
#define fi first
#define se second
int c[100009];
ll D[100009];
struct line
{
ll a, b;
int idx;
};
void add(line P)
{
while(1<=t && del(stk[t-1], stk[t], P)) --t, j = min(j, t);
stk[++t] = P;
}
ll nw = A[i].se * stk[j].a +
stk[j].b + p(A[i].se) +
2*A[i].se + 1 +
lambda;
add({-2LL * A[i+1].fi,
D[i] +
p(A[i+1].fi) -
2*A[i+1].fi -
p(max(0LL, A[i].se - A[i+1].fi + 1)),
i});
}
B.push_back({0, 0});
long long L = 0, R = 1LL*1e12, f = 0;
while(L <= R)
{
long long m = L+R >> 1, v; int cnt;
tie(v, cnt) = DP(B, m);
if(cnt > k) L = m+1;
else R = m-1, f = v - m * k;
CAPITOLUL 4. IOI 2016 4.6. ALIENS 571
}
return f;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.312
t3-t2 = 0.672
t4-t3 = 0
#include "aliens.h"
#include <bits/stdc++.h>
#define eb emplace_back
#define sz(V) ((int)(V).size())
#define allv(V) ((V).begin()),((V).end())
#define sorv(V) sort(allv(V))
#define univ(V) (V).erase(unique(allv(V)),(V).end())
#define befv(V) ((V)[sz(V)-2])
#define upmin(a,b) (a)=min((a),(b))
#define INFLL (0x3f3f3f3f3f3f3f3fll)
struct CHT
{
pll P[MAXN];
int I[MAXN], n, pv;
void init() { n = pv = 0; }
void push(ll a, ll b, int c)
{
pll p(a, b);
for(; 1 < n && 0 <= ccw(P[n-2], P[n-1], p); n--);
P[n] = p;
I[n] = c;
n++;
}
pil get(ll X)
{
if(n <= pv) pv = n-1;
for(ll nw, nxt; pv+1 < n; pv++)
{
nw = f(pv, X); nxt = f(pv+1, X);
if(nw <= nxt) break;
}
return pil(I[pv], f(pv, X));
}
} cht;
ll C[MAXN], D[MAXN];
int E[MAXN];
int N, M, K;
void push(int i)
{
cht.push(-2ll*X[i], D[i-1] + pw(X[i]) - C[i] - 2ll*X[i], i);
}
int f(ll L)
{
cht.init();
for(int i = 1; i <= N; i++)
{
push(i);
pil ret = cht.get(Y[i]);
E[i] = E[ret.first-1] + 1;
D[i] = ret.second + pw(Y[i]+1) + L;
}
return E[N];
}
ll getAns()
{
{
CAPITOLUL 4. IOI 2016 4.6. ALIENS 573
vector<pii> V, T;
for(int i = 1; i <= N; i++)
{
if(X[i] > Y[i]) swap(X[i], Y[i]);
V.eb(X[i], Y[i]);
}
sorv(V);
for(auto &v : V)
{
int x, y; tie(x, y) = v;
if(!T.empty() && T.back().first == x) T.back().second = y;
if(T.empty() || T.back().second < y) T.eb(x, y);
}
N = sz(T);
for(int i = 1; i <= N; i++) tie(X[i], Y[i]) = T[i-1];
}
if(N < K) K = N;
ll s = 0, e = pw(M)+5;
ll l = -1, ly, r = e+1, ry;
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
CAPITOLUL 4. IOI 2016 4.6. ALIENS 574
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.3
t3-t2 = 0.781
t4-t3 = 0
#include "aliens.h"
#include <bits/stdc++.h>
#define f first
#define s second
pp a[100005];
long long dp[100005];
pair<pp,int> ss[100005];
int nn;
pp aa[100005];
int p[100005];
aa[i].f*aa[i].f+
dp[i-1]+c-
(long long)(i>=2)*
max((long long)0,aa[i-1].s-aa[i].f)*
max((long long)0,aa[i-1].s-aa[i].f)},
p[i-1]};
ss[++t]=k;
for( ; j<t &&
cr(ss[j].f,ss[j+1].f)<=(long double)aa[i].second ;
j++);
dp[i]=ss[j].f.f*aa[i].s+ss[j].f.s+aa[i].s*aa[i].s;
p[i]=ss[j].s+1;
}
return {p[nn],dp[nn]};
}
sort(a+1,a+n+1);
a[0].f=-1;
a[0].s=-1;
a[n+1].f=-1;
for(i=1 ; i<=n ; i++)
{
if(a[i].s<=a[j].s || a[i].f==a[i+1].f);
else
{
aa[++nn]=a[i];
j=i;
}
}
while(rig>=lef)
{
long long mid=(lef+rig)/2;
pp v=CHT(mid);
ans=max(ans,-mid*k+v.s);
if(v.f<=k)rig=mid-1;
else lef=mid+1;
}
return ans;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
CAPITOLUL 4. IOI 2016 4.6. ALIENS 576
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.359
t3-t2 = 0.812
t4-t3 = 0
#include "aliens.h"
#include <bits/stdc++.h>
struct Point { ll y, x; };
struct CHT
{
struct Line { ll a, b, k; };
vector<Line> S;
void update(Line p)
{
while(S.size()>1 &&
cross(S[S.size()-1], p) <=
CAPITOLUL 4. IOI 2016 4.6. ALIENS 577
cross(S[S.size()-1], S[S.size()-2]))
S.pop_back();
S.push_back(p);
}
int pos=0;
pll query(ll x)
{
if(S.size()<=pos)
pos=S.size()-1;
else
while(pos+1<S.size() && cross(S[pos], S[pos+1])<=x)
pos++;
void init()
{
S.clear();
pos=0;
}
} cht;
int N, M, K;
Point B[MAXN+10], A[MAXN+10];
pll dp[MAXN+10];
ll solve(ll lambda)
{
int i, j;
cht.init();
for(i=1; i<=N; i++)
{
dp[i]={2*(A[i].y-A[1].x+1)*(A[i].y-A[1].x+1)+lambda, 1};
if(i!=1)
{
pll val=cht.query(A[i].y);
dp[i]=min(dp[i],
{val.first+2*A[i].y*A[i].y+lambda, val.second+1});
}
cht.update({-2*2*(A[i+1].x-1),
2*(A[i+1].x-1)*(A[i+1].x-1)-
2*max(0ll, A[i].y-A[i+1].x+1)*
max(0ll, A[i].y-A[i+1].x+1)+
dp[i].first,
dp[i].second});
}
return dp[N].second;
}
int cnt=1;
ll val=-1;
for(i=1; i<=N; i++)
if(val<B[i].x)
A[cnt++]=B[i], val=B[i].x;
N=cnt-1;
for(i=1; i<=N; i++)
if(A[i].x>A[i].y)
CAPITOLUL 4. IOI 2016 4.6. ALIENS 578
swap(A[i].x, A[i].y);
ll lo=-1, hi=1e15;
while(lo+1<hi)
{
ll mid=lo+hi>>1;
if(solve(mid*2+1)>K) lo=mid;
else hi=mid;
}
solve(hi*2);
ll ans=dp[N].first/2-K*hi;
return ans;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.296
t3-t2 = 1.469
t4-t3 = 0
#include<bits/stdc++.h>
#include<ext/rope>
CAPITOLUL 4. IOI 2016 4.6. ALIENS 579
#define fi first
#define se second
#define fastio ios_base::sync_with_stdio(false);cin.tie(0)
#define fopen freopen("input.txt", "r", stdin)
#define pb push_back
#define prec(a) cout<<fixed;cout.precision(a);
#define all(a) (a).begin(), (a).end()
template<class T>
void pr(T t) {cout << t << " ";}
template<class ...Args>
void prl(Args ...args) {pr(args...);cout << endl;}
ll dp[101010];
vector<pll> tmp, p;
int cur=0;
struct Line
{
ll a, b;
int cnt;
Line(){}
Line(ll aa, ll bb, int cc){a=aa;b=bb;cnt=cc;}
};
vector<Line> line;
double cross(Line A, Line B)
{
return (double)(B.b-A.b)/(double)(A.a-B.a);
}
pll get(ll x)
{
while(cur+1<line.size()&&cross(line[cur],line[cur+1])<=(double)x)
cur++;
return pll(line[cur].a*x+line[cur].b,line[cur].cnt);
}
int get_take(ll c)
{
cur=0;
line.clear();
add(Line(-2*(p[1].fi-1),c+(p[1].fi-1)*(p[1].fi-1),1));
pll t;
for(int i=1;i<(int)p.size();i++)
{
if(i>1)
CAPITOLUL 4. IOI 2016 4.6. ALIENS 580
{
if(p[i].fi<=p[i-1].se)
add(Line(-2*(p[i].fi-1),
c+t.fi+
(p[i].fi-1)*(p[i].fi-1) -
(p[i-1].se-p[i].fi+1)*(p[i-1].se-p[i].fi+1),
t.se+1));
else
add(Line(-2*(p[i].fi-1),
c+t.fi+(p[i].fi-1)*(p[i].fi-1),
t.se+1));
}
t = get(p[i].se);
t.fi+=p[i].se*p[i].se;
dp[i]=t.fi;
}
return (int)t.se;
}
k=min(k,(int)p.size()-1);
ll s = 0,e=(ll)m*m;
ll l=-1,r=e+1,ly,ry;
while(s<=e)
{
ll mid = (s+e)/2;
int num = get_take(mid);
if(num==k) return dp[p.size()-1]-mid*k;
if(num>k)
{
s = mid+1;
if(r>num) r=num,ry=dp[p.size()-1]-mid*num;
}
if(num<k)
{
e = mid-1;
if(l<num) l=num,ly=dp[p.size()-1]-mid*num;
}
}
// BEGIN CUT
int main()
{
auto t1 = clock();
CAPITOLUL 4. IOI 2016 4.6. ALIENS 581
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.296
t3-t2 = 1.188
t4-t3 = 0
#include "aliens.h"
#include <bits/stdc++.h>
int N, M, K;
vector<pii> vt;
vector<ll> C;
ll dp[MAX_N+1];
struct S
{
ll a, b;
int idx;
};
vector<S> st;
int idx = 0;
int cnt[MAX_N+1];
ll calc(ll x, int i)
{
while(idx+1<st.size())
{
if(st[idx+1].a * x + st[idx+1].b < st[idx].a * x + st[idx].b)
idx++;
else break;
}
cnt[i] = cnt[st[idx].idx]+1;
return st[idx].a * x + st[idx].b;
}
int solve(ll x)
{
st.clear();
idx = 0;
for(int i=0; i<vt.size(); i++)
{
add(-4LL * (ll)vt[i].first,
dp[i] - 2LL * C[i] + 2LL * (ll)vt[i].first * (ll)vt[i].first,
i);
return cnt[vt.size()];
}
int mx = -1;
for(int i=0 ;i<N; i++)
{
if(mx>=vt[i].second)
{
vt[i].second = INF;
vt[i].first = INF;
}
else
mx = max(mx, vt[i].second);
}
sort(vt.begin(), vt.end());
C.pb(0LL);
for(int i=1; i<vt.size(); i++)
{
C.pb(max(0LL, (ll)(vt[i-1].second - vt[i].first)) *
max(0LL, (ll)(vt[i-1].second - vt[i].first)));
}
ll s = 0, e = (ll)M*(ll)M, mid;
while(s<e)
{
mid = (s+e)/2LL;
int t = solve(2LL*mid+1LL);
if(t<=K)
{
e = mid;
}
else
{
s = mid+1LL;
}
}
solve(2LL*s);
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
CAPITOLUL 4. IOI 2016 4.6. ALIENS 584
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.296
t3-t2 = 1.422
t4-t3 = 0
#include "aliens.h"
#include <bits/stdc++.h>
#define x first
#define y second
#define all(v) v.begin(), v.end()
int n, m, k;
ll dp[101010];
int cut[101010];
p a[101010];
vector<p> v;
struct CHT
{
struct Line
{
ll a, b, c;
Line(ll a = 0, ll b = 0, ll c = 0) : a(a), b(b), c(c) {}
ll f(ll x){ return a * x + b; }
};
Line v[101010];
int pv, top;
int chk(const Line &a, const Line &b, const Line &c)
CAPITOLUL 4. IOI 2016 4.6. ALIENS 585
{
return (double)(a.b - b.b) / (b.a - a.a) >=
(double)(c.b - b.b) / (b.a - c.a);
}
void update(Line l)
{
while(top >= pv+2 && chk(v[top-2], v[top-1], l)) top--;
v[top++] = l;
}
p query(ll x)
{
while(pv+1 < top && v[pv].f(x) >= v[pv+1].f(x)) pv++;
return {v[pv].f(x), v[pv].c};
}
} cht;
void init(int N, int M, int K, const vector<int> &R, const vector<int> &C)
{
m = M, k = K; v.clear();
for(int i=0; i<N; i++)
v.emplace_back(max(R[i], C[i]) + 1, min(R[i], C[i]));
sort(all(v));
int chk(ll c)
{
cht.init();
cht.update(CHT::Line(-2 * a[1].y * 2, a[1].y * a[1].y * 2, 0));
return cut[n];
}
ll l = 0, r = 1e15;
while(l < r)
{
ll m = l + r >> 1;
if(chk(m << 1 | 1) <= q) r = m;
else l = m + 1;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
CAPITOLUL 4. IOI 2016 4.6. ALIENS 586
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.296
t3-t2 = 0.672
t4-t3 = 0
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include<ctime>
ll sq(ll x)
{
CAPITOLUL 4. IOI 2016 4.6. ALIENS 587
return (ll)x * x;
}
ll f(int x, ll y)
{
return l[x].s.f * y + l[x].s.s;
}
pi solve(ll x)
{
s = e = 0;
g(-2 * (a[0].f - 1), sq(a[0].f - 1), 0);
for(int i = 1; i <= n; i++)
{
while(e - s > 1 && f(s, a[i - 1].s) >= f(s + 1, a[i - 1].s))
s++;
dp[i] = {f(s, a[i - 1].s) + sq(a[i - 1].s) + x, dp[l[s].f].s + 1};
g(-2 * (a[i].f - 1),
dp[i].f + sq(a[i].f - 1) - sq(max((ll)0, a[i - 1].s - a[i].f + 1)),
i);
}
return dp[n];
}
sort(a, a + N, [&](pi x, pi y)
{
return x.f == y.f ? x.s > y.s : x.f < y.f;
});
n = 1;
for(int i = 1; i < N; i++)
if(a[i].s > a[n - 1].s)
a[n++] = a[i];
ll l = 0, r = sq(m);
while(r - l > 1)
{
ll mid = (l + r) / 2;
if(k <= solve(mid).s) l = mid;
else r = mid;
}
return solve(l).f - k * l;
}
// BEGIN CUT
int main()
{
auto t1 = clock();
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
CAPITOLUL 4. IOI 2016 4.6. ALIENS 588
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.312
t3-t2 = 0.797
t4-t3 = 0
#include "aliens.h"
#include <bits/stdc++.h>
struct TConvexHullTrick
{
struct TLine
{
ll a;
ll b;
int id;
TLine(ll a = 0, ll b = 0, int id = 0)
: a(a), b(b), id(id) {
}
};
std::deque<TLine> Lines;
TConvexHullTrick()
{
Lines.clear();
}
bool bad(const TLine& l1, const TLine& l2, const TLine& l3)
{
return (l1.b - l3.b) * (l2.a - l1.a) <
(l1.b - l2.b) * (l3.a - l1.a);
CAPITOLUL 4. IOI 2016 4.6. ALIENS 589
namespace Solver
{
const int N = 1e5 + 5;
std::pair<int, int> input[N];
int l[N], r[N];
int n, m, k;
ll dp[N];
int trace[N];
void process()
{
std::sort(input, input + n, [](const auto& x, const auto& y)
{
return x.first < y.first ||
(x.first == y.first && x.second > y.second);
});
n = cnt;
}
else
{
return 0ll;
}
};
ll solve()
{
process();
ll l = 0, r = 1e13;
while(l < r)
{
ll mid = ((l + r) >> 1);
if (check(mid) <= k)
{
r = mid;
}
else
{
l = mid + 1;
}
}
check(l); // l = lambda_opt
return dp[n] - l * k;
}
};
Solver::input[i].first = r[i];
Solver::input[i].second = ++c[i];
}
return Solver::solve();
}
// BEGIN CUT
int main()
{
auto t1 = clock();
CAPITOLUL 4. IOI 2016 4.6. ALIENS 591
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
std::vector<int> r(n), c(n);
for (int i = 0; i < n; i++)
{
scanf("%d %d", &r[i], &c[i]);
}
auto t2 = clock();
auto t3 = clock();
// BEGIN SECRET
//puts("098d134608c94f7413faac591054ee35");
// END SECRET
printf("%lld\n", ans);
auto t4 = clock();
//cout<<"ans = "<<ans<<"\n";
return 0;
}
// END CUT
/*
t2-t1 = 0.296
t3-t2 = 3.047
t4-t3 = 0
Ultima din activităţile din cadrul ceremoniei de deschidere a IOI 2015 este ı̂n plină desfăşuare.
Se presupune că ı̂n timpul ceremoniei de deschidere fiecare echipă va primi câte o cutie, conţinând
un suvenir din partea gazdelor. Totuşi, toţi voluntarii sunt atât de fascinaţi de ceremonie, ı̂ncât
au uitat totalmente de suvenire. Unica persoană care mai ţine minte despre suvenire este Aman.
El este un voluntar entuziast şi doreşte ca organizarea IOI să fie perfectă, prin urmare, el doreşte
să livreze toate suvenirele ı̂ntr-un timp minim.
Scena pe care se desfăşoară ceremonia de deschidere reprezintă un cerc divizat ı̂n L sectoare
identice. Sectoarele de pe cerc sunt numerotate consecutiv de la 0 la L 1. Aşa dar, pentru
0 & i & L 2 , sectorul i şi sectorul i 1 sunt adiacente, sectorul L 1 si sectorul 0 sunt si ele
adiacente. Sunt N echipe pe scenă. Fiecare echipă este amplasată ı̂n unul din sectoare. ı̂n fiecare
sector se poate afla un număr oarecare de echipe. Unele sectoare pot fi libere.
Sunt N suvenire identice. Iniţial, atât Aman, cât şi toate suvenirele se găsesc ı̂n sectorul 0.
Aman trebuie să repartizeze câte un suvenir pentru fiecare echipă, iar după livrarea ultimului
suvenir urmează să revină ı̂n sectorul 0. De remarcat că unele echipe se pot afla ı̂n sectorul 0.
Într-un moment arbitrar de timp, Aman poate duce cel mult K suvenire. Aman ia suvenirele
din sectorul 0, fără a consuma timp. Fiecare suvenir trebuie dus până ı̂n momentul ı̂n care acesta
este livrat uneia dintre echipe. La fiecare moment Aman duce unul sau mai multe suvenire până
ajunge la un sector ı̂n care se află o echipă ce nu a primit ı̂ncă suvenir. El poate oferi acestei
echipe unul din suvenirele pe care le are. Oferirea suvenirului nu consumă timp. Singurul lucru
care consumă timp este deplasarea. Aman se poate deplasa pe cerc ı̂n ambele direcţii. Deplasarea
ı̂n sectorul adiacent (ı̂n direcţia mişcării acelor de ceasornic sau ı̂n direcţia opusă mişcării acelor
de ceasornic) ı̂i ia exact o secundă, indiferent de aceea, câte suvenire el duce.
Sarcina ta este să determini timpul minim, ı̂n secunde, de care are nevoie Aman pentru a livra
toate suvenirele şi a reveni ı̂n poziţia iniţială.
Exemplu
În acest exemplu avem N 3 echipe, numărul maximal de suvenire pe care le poate duce Aman
concomitent este K 2, numărul de sectoare este L 8. Echipele sunt amplasate ı̂n sectoarele 1,
2 şi 5.
35
aur: Rareş Darius Buhai, Liviu Rebreanu (Bistriţa)
. argint: Alexandru Velea, Tiberiu Popoviciu (Cluj),
. argint: Valentin-Marius Hărşan, ICHB (Bucureşti)
. bronz: Andrei Popa, Mihail Kogalniceanu (Vaslui).
592
CAPITOLUL 5. IOI 2015 5.1. BOXES WITH SOUVENIRS 593
Una dintre soluţiile optime este prezentată ı̂n desenul de mai sus. ı̂n prima tură Aman ia două
suvenire, livrează unul dintre ele echipei din sectorul 2, apoi altul echipei din sectorul 5 şi, ı̂n
final, revine ı̂n sectorul 0. Această tură durează 8 secunde. ı̂n tura secundă Aman oferă suvenirul
rămas echipei din sectorul 1 şi revine ı̂n sectorul 0. El are nevoie de alte 2 secunde pentru aceasta.
Astfel, timpul total este de 10 secunde.
Cerinţă
Sunt date valorile N , K, L, precum şi poziţiile tuturor echipelor. Calculează timpul minim ı̂n
secunde necesar lui Aman pentru a livra toate suvenirele şi a reveni ı̂n sectorul 0. Urmează să
implementezi funcţia delivery:
delivery(N, K, L, positions) - Această funcţie va fi apelată de grader o singură dată.
a N : numărul de echipe.
a K: numărul maximal de suvenire pe care Aman le poate duce concomitent.
a L: numărul de sectoare ı̂n care este divizată scena ceremoniei de deschidere.
a positions: un tablou de lungime N . positions[0], ..., positions[N-1] descriu
numerele sectoarelor ı̂n care se află toate echipele. Valorile elementelor tabloului positions
sunt ı̂n ordine nedescrescătoare.
a Funcţia urmează să returneze timpul minim ı̂n secunde necesar lui Aman pentru a finaliza
activitatea sa.
Subprobleme
subproblemă puncte N K L
1&N & 1, 000 1 & L & 10
9
1 10 K 1
1&N & 1, 000 1 & L & 10
9
2 10 K N
1&N & 10 1&K&N 1 & L & 10
9
3 15
1&N & 1, 000 1&K&N 1 & L & 10
9
4 15
1&N & 106 1 & K & 3, 000 1 & L & 10
9
5 20
1&N & 107 1&K&N 1 & L & 10
9
6 30
The problem has a solution in linear time. The solution is basically greedy, and it is based on
several observations. Discovering only a subset of those observations usually leads to a correct
but slower solution.
CAPITOLUL 5. IOI 2015 5.1. BOXES WITH SOUVENIRS 594
We will use the word trip to denote the part of a solution between two visits to a warehouse.
The numbering of locations increases in the CW direction. (Imagine the circle as a clock face with
the warehouse at 12 = 0, and locations at 1 through 11.)
Clearly, in an optimal solution we will never go twice along the same segment in the same
direction during the same trip - any such trip can be shortened while still visiting the same set of
locations. The moment when we deliver boxes also do not matter. WLOG we may assume that
we deliver a box we want the first time we visit its location. Hence, we can divide the trips into
three groups:
CW trips: The boxes are delivered while going CW, we return by going CCW.
CCW trips: The same with directions reversed.
Full-circle trips: The entire circle is traversed once in either direction.
Also, we may easily note that each CW/CCW trip must end at one of the boxes we leave in
that trip - going any farther can be skipped.
Lemma 3 In an optimal solution, the distance traveled CW in a CW trip is at most l/2 (half
of the circle). The same holds for CCW trips.
The proof is trivial: if you travel more than l/2 while delivering the boxes and now you want
back, it is cheaper to continue in the same direction than to return - i.e., to make a full-circle trip
instead.
Lemma 4 There exists an optimal solution satisfying the property from Lemma 3 where in
each trip we deliver a contiguous subset of boxes (i.e., boxes with no other box located between
them).
Proof: Consider any optimal solution.
First of all, note that in each half of the circle, the boxes that are delivered during full-circle
trips are all at least as far from the warehouse as the boxes delivered in CW/CCW trips.
This is because we could take the farthest box delivered in a CW/CCW trip and swap it for
one that is closer but delivered in a full-circle trip. The full-circle trip will remain the same length,
the CW/CCW trip will now be shorter, which contradicts the optimality of the original solution.
Now we know that the set of boxes delivered by all full-circle trips is contiguous. As we can
pick any of them during each full-circle trip, we can easily plan the full-circle trips so that each of
them delivers a contiguous subset of these boxes.
Now let us look at the boxes delivered during the CW trips. Obviously, the k farthest from
the warehouse can be delivered in the same trip - this can be proved using a switching argument
similar to the one above. QED.
Lemma 5 There is always an optimal solution with at most one full-circle trip. Additionally,
we deliver exactly k boxes during that trip (or all of them if n $ k).
Proof: It always makes sense to drop as many boxes as we can during a full-circle trip, because
we can move boxes from CW/CCW trips to full-circle trips at no cost.
As we already know, there is an optimal solution in which each trip drops a contiguous segment
of boxes. For any partition of boxes into contiguous segments, at most one such segment contains
boxes on both sides of the circle. Only that one segment needs to be delivered in a full-circle trip,
for each other segment of boxes a CW/CCW trip is at most as expensive as a full-circle one.
Theorem 6 The problem can be solved in O n time.
Proof: Let li be the optimal distance to deliver the first i boxes in the CW direction using
CW trips. These values can be precomputed in O n time. Let ri be the same values for the
CCW direction.
There may be no full-circle trip. In O n, try all possibilities for how many boxes are delivered
in CW trips. (This is overkill but the benefit is that we do not have to handle boxes opposite the
warehouse as a special case.) Look for the minimum of li rni .
There may be one full-circle trip. Again in O n, try all possibilities for the k boxes delivered
during such a trip. Look for the minimum of li l rnki . Return the minimum of all those
values.
Another proof: If there are fewer than k boxes in the location opposite the warehouse, there
are clearly O k different possibilities for the segment delivered during a full-circle trip, and O k
possibilities to consider if there is no full-circle trip.
If there are k or more boxes in the location opposite the warehouse, there is an optimal solution
with no full-circle trip. Additionally, we can obviously assume that less than k of those boxes are
CAPITOLUL 5. IOI 2015 5.1. BOXES WITH SOUVENIRS 595
delivered in CW trips. This gives us, again, O k possibilities for the split between boxes delivered
in either direction.
In either case, we have O k possibilities to try. For each of those O k possibilities, we can
compute the optimal total cost without any precomputation: we simply go through the locations
of the remaining boxes with step k and add those distances up. Thus, each single possibility can
be evaluated in O n©k , which gives a total time complexity of O n again.
#include <algorithm>
#include <stdio.h>
{
int c, x, s;
c = _read();
while (c <= 32) c = _read();
x = 0;
s = 1;
if (c == ’-’)
{
s = -1;
c = _read();
}
while (c > 32)
{
x *= 10;
x += c - ’0’;
c = _read();
}
if (s < 0) x = -x;
return x;
}
int main()
{
_inputFile = fopen("../tests/subtask6/09", "rb");
_outputFile = fopen("boxes.out", "w");
int N, K, L, i;
N = _readInt();
K = _readInt();
L = _readInt();
#include "boxes.h"
#include <map>
#include <iostream>
#include <algorithm>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
if (n == 1)
{
return std::min(p[0] * 2LL, (l - p[0]) * 2LL);
}
int here = n;
for (int i = 0; i < n; ++i)
{
if (p[i] > l - p[i] && here == n)
{
here = i;
}
if (i >= here)
CAPITOLUL 5. IOI 2015 5.1. BOXES WITH SOUVENIRS 597
{
p[i] = l - p[i];
}
}
if (here == 0)
{
long long int sumleft = p[0], leftleft = -1;
int cur = k - 1;
return sumleft;
}
else
if (here == n)
{
long long int sumright = p[here - 1], leftright = -1;
int cur = k - 1;
return sumright;
}
{
if (cur == 0)
{
sumright += p[i - 1] + p[i] * 1LL;
cur = k - 1;
}
else
{
sumright += p[i - 1] - p[i] * 1LL;
--cur;
}
}
if (k == 1)
return curmin;
curval = l;
if (i != 0)
{
start = i - 1;
while (1)
{
if (start == i - 1)
curval += p[start] * 1LL;
else
curval += p[start] * 2LL;
if (start - k >= 0)
{
curval += p[start] - p[start - k] * 1LL;
start -= k;
}
else
{
curval += p[start] * 1LL;
break;
}
}
}
if (i + k < n)
{
start = i + k;
while (1)
{
if (start == i + k)
curval += p[start] * 1LL;
else
curval += p[start] * 2LL;
if (start + k < n)
{
curval += p[start] - p[start + k] * 1LL;
start += k;
}
else
{
curval += p[start] * 1LL;
break;
}
}
CAPITOLUL 5. IOI 2015 5.1. BOXES WITH SOUVENIRS 599
int main()
{
_inputFile = fopen("../tests/subtask6/09", "rb");
_outputFile = fopen("boxes.out", "w");
int N, K, L, i;
N = _readInt();
K = _readInt();
L = _readInt();
#include "boxes.h"
#include <bits/stdc++.h>
ll dp[NN];
for(int i=n-1;i>=id;i--)
dp[i]=2*(l-p[i])+((i+k>=n)?0:dp[i+k]);
ll ans=min((ll)(n+k-1)/k*l,((id>0)?dp[id-1]:0)+dp[id]);
int lft=max(0,id-k),rght=lft+k;
while(lft<=id && rght<=n)
ans=min(ans,dp[rght]+((lft>0)?dp[lft-1]:0)+l),
lft++,rght++;
return ans;
}
c = _read();
while (c <= 32) c = _read();
x = 0;
s = 1;
if (c == ’-’)
{
s = -1;
c = _read();
}
while (c > 32)
{
x *= 10;
x += c - ’0’;
c = _read();
}
if (s < 0) x = -x;
return x;
}
int main()
{
_inputFile = fopen("../tests/subtask6/09", "rb");
_outputFile = fopen("boxes.out", "w");
int N, K, L, i;
N = _readInt();
K = _readInt();
L = _readInt();
#include<iostream>
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/subtask6/09", // argv[1]=<input-file>
(char*)"boxes.out", // argv[2]=<output-file>
(char*)"../tests/subtask6/09.a", // argv[3]=<answer-file>
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
CAPITOLUL 5. IOI 2015 5.2. SCALES 602
registerTestlibCmd(argc, argv);
if (pans != jans)
{
quitf(_wa, "Wrong answer: output = %lld, expected = %lld", pans, jans);
}
else
{
quitf(_ok, "Correct answer: answer = %lld", pans);
}
}
5.2 Scales
Problema 2 - Scales 100 de puncte
Amina are şase monezi numerotate de la 1 la 6. Ea ştie că monezile au greutăţi diferite. Ea ar
dori să le ordoneze ı̂n raport cu greutatea. Pentru acest scop ea a construit un nou tip de balanţă.
O balanţă traditională are două talere. Pentru a utiliza o astfel de balanţă, se aşează câte o
monedă pe fiecare taler şi balanţa determină care dintre monezi este mai grea.
Noua balanţă a Aminei este mult mai complexă. Aceasta are patru talere, etichetate A, B, C
şi D.
Balanţa are patru setari diferite, fiecare răspunzând unei anumite ı̂ntrebari ı̂n legatură cu
monezile.
Pentru a utiliza balanţa, Amina trebuie să plaseze exact câte o monedă pe fiecare dintre talerele
A, B şi C. ı̂n plus, pentru a patra setare ea trebuie sa aşeze deasemenea exact o monedă pe talerul
D.
Cele patru setari vor răspunde la următoarele patru ı̂ntrebări:
1. Care dintre monezile de pe talerele A, B şi C este cea mai grea?
2. Care dintre monezile de pe talerele A, B şi C este cea mai uşoară?
3. Care dintre monezile de pe talerele A, B şi C este cea mediană? ( Adică nu este nici cea
mai grea nici cea mai uşoară dintre cele trei.)
4. Dintre monezile de pe talerele A, B şi C se consideră doar cele care sunt mai grele decât cea
situată pe talerul D. Dacă există astfel de monezi, care dintre aceste monezi este cea mai
usoară? Altfel, dacă nu există o astfel de monedă , care dintre monezile situate pe talerele
A, B şi C este cea mai usoară?
Cerinţă
Scrie un program care ordonează cele şase monezi ale Aminei ı̂n funcţie de greutate. Programul
poate să ceară balanţei Aminei să compare greutăţi ale monezilor. Programului tău i se vor da
câteva teste spre rezolvare, fiecare corespunzând unui nou set de şase monede.
Programul tău trebuie sa implementeze funcţiile init şi orderCoins. Pe parcursul fiecărei
rulări, grader-ul va apela iniţial functia init exact o dată. Aceasta va furniza numărul de teste
şi vă va permite sa iniţializaţi orice variabilă. Apoi grader-ul va apela functia orderCoins()
câte o dată pentru fiecare test.
init(T)
– T : Numărul de teste pe care programul tău va trebui să ı̂l rezolve la rularea curentă.
T este un ı̂ntreg din intervalul 1, ..., 18.
– Aceasată funcţie nu va returna nicio valoare.
orderCoins()
CAPITOLUL 5. IOI 2015 5.2. SCALES 603
Punctaj
Această problemă nu are subprobleme. ı̂n schimb scorul tău va fi calculat ı̂n funcţie de numărul
de cântăriri (adică de numărul total de apeluri ale funcţiilor grader getLightest()\verb,
getHeaviest(), getMedian() şi/sau getNextLightest()) pe care le face programul tău.
Programul tău va fi rulat de mai multe ori şi pe mai multe teste la fiecare rulare. Fie r numărul
de rulări ale programului tău. Acest număr este fixat ı̂n datele de test. Dacă programul tău nu
ordonează monezile corect la oricare test din oricare rulare, vei obţine 0 puncte. Altfel, fiecare
rulare va fi punctată individual după cum urmează.
Fie Q cel mai mic număr posibil de cântı̂riri astfel ı̂ncât să se poată sorta orice şir de şase
monezi folosind Q cântăriri cu balanţa Aminei. Pentru a face problema mai interesantă nu vom
dezvălui aici valoarea lui Q.
Să presupunem că cel mai mare număr de cântăriri pe toate testele din toate rulările este
Q y unde y este un ı̂ntreg. Să considerăm apoi o singură rulare a programului tău. Fie Q x
cel mai mare număr de cântı̂riri dintre toate cele T teste - unde x este un ı̂ntreg nenegativ. (
Dacă utilizaţi mai putin de Q cântăriri pe fiecare test atunci x 0.) Scorul rulării curente va fi
100
r xy ©51
, rotunjit ı̂n jos la două zecimale.
ı̂n particular, dacă programul face cel mult Q cântăriri pe fiecare test vei obţine 100 de puncte.
Exemplu
Presupunem că monezile sunt ordonate 3 4 6 2 1 5 de la cea mai uşoară la cea mai grea.
CAPITOLUL 5. IOI 2015 5.2. SCALES 604
This is based on the well-known problem of ordering five coins with 7 (binary) weighing. There
are 120 permutations and 128 possible sequences of seven answers, and it is indeed possible to
find a strategy which always works.
In our problem, there are 720 possible answers, and with at most 6 ternary weighing, theoret-
6
ically we could obtain 3 729 possible answers. The gap is very small, but it turns out that it
is again possible to find a strategy which uses just 6 weighing.
The easiest solution here is to generate a memorization function which, for each possible subset
of possible permutations, tries all the possible questions, and returns the best one. It is possible
to bound the branching, as follows:
Always take care that there are at most 243 consistent results after 1 weighing, at most 81
consistent results after 2 weighing, etc.
If, for the given subset of power P , we have already found a solution which uses N weighing,
and P % 3 N 1, then do not look further (we have already found the best possible answer).
With these optimizations, we could write a program which generates the strategy tree, in the
form of a program which could be submitted for judging (see builder.cpp, which does not build
it in the right format yet, but is close enough). With the optimizations above the builder runs
fast enough, so it is also possible to erate it on the fly.
75 {
76 if (A < 1 || A > 6 || B < 1 || B > 6 || C < 1 || C > 6 || D<1 || D>6)
77 assert(0);
78 if (A == B || A == C || A == D || B == C || B == D || C == D)
79 assert(0);
80 }
81 }
82
83 int getMedian(int A, int B, int C)
84 {
85 _numQueries++;
86 _checkQuery(A, B, C, -1);
87
88 A--; B--; C--;
89
90 if (_ind[B] < _ind[A] && _ind[A] < _ind[C])
91 return A + 1;
92
93 if (_ind[C] < _ind[A] && _ind[A] < _ind[B])
94 return A + 1;
95
96 if (_ind[A] < _ind[B] && _ind[B] < _ind[C])
97 return B + 1;
98
99 if (_ind[C] < _ind[B] && _ind[B] < _ind[A])
100 return B + 1;
101
102 return C + 1;
103 }
104
105 int getHeaviest(int A, int B, int C)
106 {
107 _numQueries++;
108 _checkQuery(A, B, C, -1);
109
110 A--; B--; C--;
111
112 if (_ind[A] > _ind[B] && _ind[A] > _ind[C])
113 return A + 1;
114
115 if (_ind[B] > _ind[A] && _ind[B] > _ind[C])
116 return B + 1;
117
118 return C + 1;
119 }
120
121 int getLightest(int A, int B, int C)
122 {
123 _numQueries++;
124 _checkQuery(A, B, C, -1);
125
126 A--; B--; C--;
127
128 if (_ind[A] < _ind[B] && _ind[A] < _ind[C])
129 return A + 1;
130
131 if (_ind[B] < _ind[A] && _ind[B] < _ind[C])
132 return B + 1;
133
134 return C + 1;
135 }
136
137 int getNextLightest(int A, int B, int C, int D)
138 {
139 int allLess = 1;
140
141 _numQueries++;
142 _checkQuery(A, B, C, D);
143
144 A--; B--; C--; D--;
145
146 if (_ind[A] > _ind[D] || _ind[B] > _ind[D] || _ind[C] > _ind[D])
147 allLess = 0;
148
149 if (allLess == 1)
150 {
CAPITOLUL 5. IOI 2015 5.2. SCALES 607
#include "graderlib.c"
#include "scales.h"
#include <bits/stdc++.h>
struct query
{
query() {}
query(int t, int a, int b, int c, int d) : t(t),a(a),b(b),c(c),d(d) {}
int t, a, b, c, d;
int moi(int k)
{
if (t==1)
{ // Heaviest
if (p[k][a] > p[k][b] and p[k][a] > p[k][c]) return 0;
else return (p[k][b] > p[k][c]) ? 1 : 2;
}
if (t==2)
{ // Lightest
if (p[k][a] < p[k][b] and p[k][a] < p[k][c]) return 0;
else return (p[k][b] < p[k][c]) ? 1 : 2;
}
if (t==3)
{ // Median
if (p[k][a] < p[k][b])
{
if (p[k][b] < p[k][c]) return 1;
else return p[k][a] < p[k][c] ? 2 : 0;
}
else
{
if (p[k][a] < p[k][c]) return 0;
else return p[k][b] < p[k][c] ? 2 : 1;
}
}
if (t==4)
{ // NextHeaviest
int x = p[k][a], y = p[k][b], z = p[k][c];
if (not (x < p[k][d] and y < p[k][d] and z < p[k][d]))
CAPITOLUL 5. IOI 2015 5.2. SCALES 608
{
if (x < p[k][d]) x = 7;
if (y < p[k][d]) y = 7;
if (z < p[k][d]) z = 7;
}
if (x<y and x<z) return 0;
else return y<z ? 1 : 2;
} return -1;
}
int real()
{
int res;
if (t==1) res = getHeaviest(a, b, c);
if (t==2) res = getLightest(a, b, c);
if (t==3) res = getMedian(a, b, c);
if (t==4) res = getNextLightest(a, b, c, d);
if (res == a) return 0;
if (res == b) return 1;
if (res == c) return 2;
return -123; // ... !!!
}
};
vector<query> q;
struct node
{
query q;
node *ch[3];
set<int> s;
} *root;
void init(int T)
{
for (int x=1; x<=6; x++)
for (int y=x+1; y<=6; y++)
for (int z=y+1; z<=6; z++)
{
q.emplace_back(1, x, y, z, -1);
q.emplace_back(2, x, y, z, -1);
q.emplace_back(3, x, y, z, -1);
set<int> st;
for (int i=0; i<720; i++) st.insert(i);
root = new node();
make_tree(root, st);
}
void orderCoins()
{
node *now = root;
while (now->s.size() > 1)
{
now = now->ch[now->q.real()];
}
int ans[6], *rans = p[ *now->s.begin() ];
for (int i=1; i<=6; i++)
ans[rans[i]-1] = i;
answer(ans);
}
int main()
{
auto t1 = clock();
int T, i;
auto t2 = clock();
T = _getNumberOfTests();
init(T);
auto t3 = clock();
auto t4 = clock();
return 0;
}
#include "graderlib.c"
#include "scales.h"
#include <bits/stdc++.h>
struct Ord
{
int a[7];
Ord(vector<int>& v)
{
for(int i = 0; i < 6; i++)
a[i + 1] = v[i];
}
};
struct Query
{
int a, b, c, d;
Query(int _a, int _b, int _c, int _d)
{
a = _a;
b = _b;
c = _c;
d = _d;
}
int ask()
{
int res;
if(d == a) res = getLightest(a, b, c);
else
if(d == b) res = getMedian(a, b, c);
else
if(d == c) res = getHeaviest(a, b, c);
else
res = getNextLightest(a, b, c, d);
if(res == a) return 1;
if(res == b) return 2;
if(res == c) return 3;
return -123; // ... !!!
}
if(res == a) return 1;
if(res == b) return 2;
if(res == c) return 3;
return -123; // ... !!!
}
};
vector<Query> lists;
struct Node
{
int dep;
Query* q;
vector<Ord*> pos;
Node* go[4];
bool init()
CAPITOLUL 5. IOI 2015 5.2. SCALES 611
{
if(pos.size() <= 1) return 1;
int cnt[4] = {0};
bool ok = 0;
for(auto& qq : lists)
{
cnt[1] = 0;
cnt[2] = 0;
cnt[3] = 0;
ok = 1;
break;
}
return ok;
}
} *root;
void create()
{
for(int i = 1; i < 5; i++)
{
for(int j = i + 1; j < 6; j++)
{
for(int l = j + 1; l <= 6; l++)
{
for(int k = 1; k <= 6; k++)
{
lists.push_back(Query(i, j, l, k));
}
}
}
}
}
void init(int T)
{
create();
CAPITOLUL 5. IOI 2015 5.2. SCALES 612
do
{
root -> pos.push_back(new Ord(v));
} while(next_permutation(v.begin(), v.end()));
root -> dep = 1;
root -> init();
}
void orderCoins()
{
int W[] = {1, 2, 3, 4, 5, 6};
Node* ans = root;
while(ans -> pos.size() != 1)
ans = ans -> go[ans -> q -> ask()];
for(int i = 1; i <= 6; i++)
{
W[ans -> pos[0] -> a[i] - 1] = i;
}
answer(W);
}
int main()
{
auto t1 = clock();
int T, i;
auto t2 = clock();
T = _getNumberOfTests();
init(T);
auto t3 = clock();
auto t4 = clock();
return 0;
}
#include "graderlib.c"
#include "scales.h"
CAPITOLUL 5. IOI 2015 5.2. SCALES 613
#include <bits/stdc++.h>
int ids[] = {0, 107, 107, 107, 49, 48, 46, 45, 44, 42, 38, 37, 35, 88,
95, 28, 67, 74, 15, 8, 40, 40, 85, 95, 28, 64, 74, 15, 11, 40, 40, 85,
88, 28, 64, 67, 15, 11, 33, 33, 31, 11, 9, 31, 11, 9, 10, 52, 52, 31,
24, 22, 31, 24, 22, 23, 52, 52, 72, 99, 79, 29, 18, 70, 29, 83, 5, 34,
8, 6, 34, 8, 6, 52, 7, 52, 34, 21, 19, 34, 21, 19, 52, 20, 52, 72, 103,
83, 32, 18, 69, 32, 79, 5, 41, 5, 3, 41, 5, 3, 55, 55, 4, 41, 18, 16,
41, 18, 16, 55, 55, 17, 103, 79, 83, 39, 21, 76, 39, 72, 8, 75, 55, 75,
65, 65, 55, 75, 18, 31, 68, 52, 68, 65, 65, 52, 18, 68, 31, 65, 65, 1,
8, 21, 58, 5, 75, 58, 96, 96, 55, 86, 86, 55, 96, 5, 31, 89, 89, 52,
86, 86, 52, 5, 89, 31, 86, 86, 1, 8, 8, 58, 5, 73, 58, 96, 16, 18, 58,
52, 68, 18, 52, 22, 68, 52, 65, 55, 96, 96, 55, 58, 8, 66, 86, 52, 21,
21, 86, 55, 75, 75, 75, 58, 75, 68, 68, 58, 75, 18, 34, 65, 52, 65, 68,
68, 52, 18, 65, 34, 19, 6, 55, 68, 68, 1, 75, 5, 55, 96, 96, 58, 89, 89,
58, 96, 5, 34, 86, 86, 52, 89, 89, 52, 5, 86, 34, 6, 6, 55, 89, 89, 1,
73, 5, 55, 16, 96, 18, 55, 52, 65, 18, 52, 19, 65, 52, 68, 96, 58, 96, 55,
55, 11, 63, 89, 52, 24, 24, 89, 75, 58, 75, 68, 58, 68, 75, 75, 58, 68,
21, 41, 65, 55, 65, 75, 75, 55, 21, 65, 41, 16, 3, 52, 68, 3, 52, 75,
75, 1, 89, 89, 58, 96, 96, 58, 89, 8, 41, 86, 86, 55, 96, 96, 55, 8, 86,
41, 3, 3, 52, 66, 3, 52, 96, 96, 1, 55, 52, 65, 16, 89, 21, 52, 21, 16,
65, 55, 75, 89, 58, 89, 52, 52, 11, 63, 96, 55, 24, 24, 96, 68, 58, 68, 0};
int mx = 0;
int zzz;
for(int v : vec)
{
vector<pii> val;
for(int i = 0; i < 3; ++i)
val.emplace_back(perm[v][z.y[i]], z.y[i]);
sort(val.begin(), val.end());
if(z.x == 0)
Mp[val[2].y].emplace_back(v);
else
if(z.x == 1)
Mp[val[0].y].emplace_back(v);
else
if(z.x == 2)
Mp[val[1].y].emplace_back(v);
else
{
bool st = false;
for(int i = 0; i < 3; ++i)
{
if(val[i].x > perm[v][z.y[3]])
{
Mp[val[i].y].emplace_back(v);
CAPITOLUL 5. IOI 2015 5.2. SCALES 614
st = true;
break;
}
}
if(!st) Mp[val[0].y].emplace_back(v);
}
int step = 0;
for(int i = 0; i < 6; ++i) if(Mp[i].size())
{
step++;
if(i == abc-1)
return dfs(u*3 + step, Mp[i], lv / 3);
}
}
return false;
}
int nth = 6;
void init(int T)
{
for(int i = 0; i < (1 << nth); ++i)
{
vector<int> vec;
for(int j = 0; j < nth; ++j) if(i >> j & 1)
vec.emplace_back(j);
if(vec.size() == 3)
for(int j = 0; j < 3; ++j) que.emplace_back(j, vec);
if(vec.size() == 4)
{
for(int i = 0; i < 4; ++i)
{
vector<int> ret;
for(int j = 0; j < 4; ++j)
if(i != j)
ret.emplace_back(vec[j]);
ret.emplace_back(vec[i]);
que.emplace_back(3, ret);
}
}
}
vector<int> now;
for(int i = 0; i < nth; ++i)
now.emplace_back(i+1);
do
{
perm.emplace_back(now);
} while(next_permutation(now.begin(), now.end()));
}
void orderCoins()
{
int* ans = new int[6];
vector<int> zz;
for(int i = 0; i < perm.size(); ++i)
zz.emplace_back(i);
int k = dfs(0, zz, 2187);
for(int i = 0; i < 6; ++i)
ans[perm[k][i]-1] = i+1;
answer(ans);
}
int main()
{
auto t1 = clock();
int T, i;
CAPITOLUL 5. IOI 2015 5.3. TEAMS 615
auto t2 = clock();
T = _getNumberOfTests();
init(T);
auto t3 = clock();
auto t4 = clock();
return 0;
}
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/40", // argv[1]=<input-file>
(char*)"scales.out", // argv[2]=<output-file>
(char*)"../tests/40.a", // argv[3]=<answer-file>
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
return 0;
}
5.3 Teams
Problema 3 - Teams 100 de puncte
CAPITOLUL 5. IOI 2015 5.3. TEAMS 616
Avem o clasă cu studenţi numerotaţi de la 0 la N 1. ı̂n fiecare zi profesorul clasei are unele
proiecte pentru studenţi. Fiecare proiect trebuie realizat de o echipă de studenţi ı̂n decursul
aceleiaşi zi. Proiectele pot avea diverse solicitări. Pentru fiecare proiect profesorul cunoaşte
numărul exact de studenţi care formează echipa ce va lucra la el.
Fiecare student preferă să lucreze ı̂n echipe cu număr de membri dintr-un anumit interval. Mai
exact, studentul i poate fi inclus numai ı̂ntr-o echipă care conţine ı̂ntre Ai şi B i membri. ı̂n
fiecare zi un student poate fi inclus ı̂n cel mult o echipă. Unii studenţi pot să nu fie incluşi ı̂n nicio
echipă. Fiecare echipă va lucra la un singur proiect.
Profesorul a ales deja proiectele pentru fiecare din următoarele Q zile. Pentru fiecare dintre
aceste zile, determinaţi dacă este posibil să asociaţi studenţii cu echipele astfel ı̂ncât să existe câte
o echipă care să lucreze la fiecare proiect.
Exemplu
Presupunem N 4 studenţi şi Q 2 zile. Constrângerile de dimensiune a echipelor pentru
studenţi sunt date ı̂n următorul tabel:
student 0 1 2 3
A 1 2 2 2
B 2 3 3 4
În prima zi sunt M 2 proiecte. Dimensiunile cerute pentru echipe sunt K 0 1 si K 1 3.
Aceste două echipe pot fi alcătuite incluzând studentul 0 ı̂n echipa de dimensiune 1 şi ceilalti 3
studenţi ı̂n echipa de dimensiune 3.
În a doua zi sunt din nou M 2 proiecte dar timpii ceruţi pentru echipe sunt K 0 1 şi
K 1 1.
În acest caz nu este posibil să formam echipele fiind un singur student ce poate inclus ı̂ntr-o
echipă de dimensiune 1.
Cerinţă
Se dă descrierea pentru toţi studenţii: N , A, şi B, precum şi o secvenţă de Q ı̂ntrebări - câte
una pentru fiecare zi. Fiecare ı̂ntrebare constă din numarul M al proiectelor din acea zi şi o
secvenţă K de lungime M conţinând dimensiunile solicitate ale echipelor. Pentru fiecare ı̂ntrebare
programul tău trebuie să returneze dacă este posibil sa formezi toate echipele.
Trebuie să implementezi funcţiile init şi can:
init(N, A, B) - Grader-ul va apela această funcţie la ı̂nceput exact o dată.
– N : numărul de studenţi.
– A: un şir de lungime N : Ai dimensiunea minimă a unei echipe ı̂n care poate să
lucreze studentul i.
– B: un şir de lungime N : B i dimensiunea maximă a unei echipe ı̂n care poate să
lucreze studentul i.
– Aceasta funcţie nu returnează nicio valoare.
– Se ştie că 1 & Ai & B i & N pentru fiecare i 0, ..., N 1.
can(M, K) - După apelul lui init, grader-ul va apela aceasta funcţie de Q ori la rând,
câte o dată pentru fiecare zi.
– M : numărul de proiecte pentru această zi.
– K: un şir de lungime M conţinând dimensiunile cerute pentru echipă fiecarui proiect.
– Funcţia trebuie să returneze 1 dacă este posibil să se formeze toate echipele cerute şi 0
ı̂n caz contrar.
– Se ştie ca 1 & M & N , şi pentru fiecare i 0, ..., M 1 avem 1 & K i & N . De
remarcat că suma tuturor K i poate depăşi N .
Subprobleme
Să presupunem că S este suma tuturor valorilor lui M ı̂n toate apelurile can(M, K).
CAPITOLUL 5. IOI 2015 5.3. TEAMS 617
in its rectangle, then we can binary search for the y of new corner directly: each guess will involve
a range sum in the corners structure and a single query to the points structure.
2
Thus, the running time is O m log n.
Non-constructive approach
The above solutions, although implicitly, construct the assignments. However, our question is
binary and thus another approach is possible.
The Hall theorem says the following:
It’s not possible to assign children to teams if there exists such subset A of team sizes ki , that
the set of points that can be assigned to any team from A (let’s call those points neighbors) is
smaller than the sum of numbers in A.
Therefore, we want to construct such set A, that the number c A = —neighbors of A— -
(sum of numbers in A) is smallest possible. If the smallest c A turns out to be negative, then
the answer is NO, otherwise it’s YES.
Assume that ki ’s are distinct and sorted (just for clarity).
We can propose a simple dynamic programming solution.
Let Di be the minimal c A such that ki is the greatest element of A. Then: Di minrDj
Z j, i ki j $ ix, where Z j, i = —children a, b s.t. a " kj 1, ki , b % ki —
Optimal c A is thus equal to minrDi x.
2
Another O m log n solution
As computing Z j, i is asking about number of points in some rectangle, we can implement
2
this DP in O m log n.
Ó
Another O m n log n amortized solution
This can be again combined with the brute force solution to speed it up.
O m log n solution
Let us assume, that we have three indices i $ j $ k, such that it’s more beneficial to take index
i than j, while computing the minimum in the formula for Dk . Then, for any l % k, it’s also more
beneficial to take index i instead of j. Why? We have from out assumption:
Di Z i, k & Dj Z j, k , which is equivalent to:
Dj Di ' — children a, b s.t. a " ki 1, kj , b ' kk —.
If we replace kk with kl ' kk , the right side won’t increase, so indeed Di Z i, l & Dj Z j, l.
Therefore, for any indices i $ j we can compute the exact moment W i, j of DP computation,
when the index i will be better than j.
It can be done in time O log n.
The improved DP goes like this: when computing Dk , we maintain a set of those indices that
might be useful according to our current knowledge. It also means that if indices i and j, i $ j
are in the set right now, then j is more beneficial. Hence, the last index from the set constitutes
an optimal transition for Dk .
Maintaining the set of indices involves a queue of events. For each two indices i $ j that
happen to be neighbors in the set at some point of time, we push the event ”remove j from the
set once you reach computation of Dl ”, for some l.
There are O m set updates/accesses and each time we use O log n time to compute a moment
when j % i is useless.
It remains to show, how to preprocess the input points to be able to find W i, j in time
O log n.
Let B Dj Di .
We need to find smallest y, such that there are at least B input points in ki 1, kj y, .
This can be solved with a variant of a segment tree.
However, in a node A, B of the segment tree we store all the points (children) with y in
A, B . The points inside a single node are sorted by increasing x and each point stores the
pointers to:
¬ ¬
the first point with x ' x and last with x & xinA, mid
¬ ¬
the first point with x ' x and last with x & xinmid 1, B .
This allows us to binary search for ki and kj only in the root of the segment tree, and then just
follow the pointers on a path to the leaf.
CAPITOLUL 5. IOI 2015 5.3. TEAMS 619
#include "teams.h"
#include <stdio.h>
#include <stdlib.h>
#include <bits/stdc++.h>
ii a[N];
class node
{ public:
int x, l, r, lazy;
node()
{
x = l = r = lazy = 0;
}
};
int cnt = 1;
int n;
init(t[x].l, l, m);
init(t[x].r, m + 1, r);
}
sort(a + 1, a + n + 1);
sort(vs.begin(), vs.end());
int ptr = 0;
ps[0] = cnt++;
init(ps[0], 1, n);
for(int i = 1; i <= n; i++)
{
ps[i] = ps[i - 1];
while(ptr < vs.size() and vs[ptr].first <= i)
{
ps[i] = insert(ps[i], 1, n, vs[ptr].second);
ptr++;
}
}
del = cnt++;
init(del, 1, n);
}
void push(int x)
{
if(t[x].lazy)
{
t[t[x].l].x = t[t[t[x].lazy].l].x;
t[t[x].r].x = t[t[t[x].lazy].r].x;
t[t[x].l].lazy = t[t[x].lazy].l;
t[t[x].r].lazy = t[t[x].lazy].r;
t[x].lazy = 0;
}
}
int get(int x, int del, int l, int r, int x1, int x2, int k)
{
if(x1 <= l and r <= x2 and t[x].x - t[del].x <= k)
{
t[del].lazy = x;
int ret = t[x].x - t[del].x;
t[del].x += ret;
return ret;
}
void clear(int x)
{
CAPITOLUL 5. IOI 2015 5.3. TEAMS 621
if (_charsNumber <= 0)
{
return -1;
}
return _buffer[_currentChar++];
}
}
if (s < 0) x = -x;
return x;
}
int main()
{
_inputFile = fopen("../tests/72", "rb");
_outputFile = fopen("teams.out", "w");
int N;
N = _readInt();
init(N, A, B);
int Q;
Q = _readInt();
for (int i = 0; i < Q; ++i)
{
int M;
M = _readInt();
int *K = (int*)malloc(sizeof(int)*(unsigned int)M);
for (int j = 0; j < M; ++j)
{
K[j] = _readInt();
}
fprintf(_outputFile,"%d\n", can(M, K));
}
return 0;
}
// --------------- end grader ----------------------
/*
execution time : 3.156 s
*/
#include "teams.h"
#include <stdio.h>
#include <stdlib.h>
#include<bits/stdc++.h>
#define mx 500005
#define tm (tl+tr >> 1)
int s[mx*20],L[mx*20],R[mx*20],root[mx],nw;
#define mp make_pair
#define st first
#define nd second
int n;
l = bs(root[x],root[y],1,n,
req+ex+qry(root[x],
root[y],1,n,1,las-1) );
return 1;
}
n = ss;
int i,j,p=0;
for(i=0;i<n;i++) V[ a[i] ].push_back(b[i]);
for(i=1;i<=n;i++)
{
for(j=0;j<V[i].size();j++)
p = up(p,1,n,V[i][j]);
root[i] = p;
}
}
if (_charsNumber <= 0)
{
return -1;
}
return _buffer[_currentChar++];
}
int main()
{
_inputFile = fopen("../tests/72", "rb");
_outputFile = fopen("teams.out", "w");
int N;
N = _readInt();
{
A[i] = _readInt();
B[i] = _readInt();
}
init(N, A, B);
int Q;
Q = _readInt();
for (int i = 0; i < Q; ++i)
{
int M;
M = _readInt();
int *K = (int*)malloc(sizeof(int)*(unsigned int)M);
for (int j = 0; j < M; ++j)
{
K[j] = _readInt();
}
fprintf(_outputFile,"%d\n", can(M, K));
}
return 0;
}
// --------------- end grader ----------------------
/*
execution time : 2.250 s
*/
#include "teams.h"
#include <stdio.h>
#include <stdlib.h>
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb emplace_back
#define em emplace
#define all(v) v.begin(), v.end()
struct Node
{
int l, r, val;
Node(int l, int r, int val) : l(l), r(r), val(val) {}
};
tree[cnd].l = tree.size();
tree.eb(0, 0, 0);
expand_tree(s, m, k, tree[pnd].l, tree[cnd].l);
}
else
{
tree[cnd].l = tree[pnd].l;
tree[cnd].r = tree.size();
tree.eb(0, 0, 0);
expand_tree(m+1, e, k, tree[pnd].r, tree[cnd].r);
}
}
sort(all(num));
sort(all(numx));
sort(arr, arr+n, [](pii a, pii b)
{
if(a.se == b.se) return a.fi < b.fi;
return a.se < b.se;
});
for(int i = 0; i < n; i++)
{
arr[i].se = i + 1;
}
sort(arr, arr+n);
tree.eb(0, 0, 0);
for(int i = 0; i < n; i++)
{
root[i+1] = tree.size();
tree.eb(0, 0, 0);
expand_tree(1, n, arr[i].se, root[i], root[i+1]);
}
return;
}
sort(K, K+M);
stack <pii> stk;
stk.em(0, n+1);
for(int i = 0; i < M; i++)
CAPITOLUL 5. IOI 2015 5.3. TEAMS 627
{
int last = lower_bound(all(num), K[i]) - num.begin() + 1,
cnt = K[i];
int rx = upper_bound(all(numx), K[i]) - numx.begin();
while(!stk.empty() && stk.top().se < last) stk.pop();
while(!stk.empty())
{
int x = stk.top().fi, y = stk.top().se;
int temp = cal(1, n, last, y, root[x], root[rx]);
if(temp < cnt)
{
cnt -= temp;
last = y + 1;
stk.pop();
}
else
{
int l = cal(1, n, 1, last - 1, root[x], root[rx]);
int ny = get_r(1, n, l + cnt, root[x], root[rx]);
stk.em(rx, ny);
break;
}
}
if(stk.empty()) return 0;
}
return 1;
}
// --------------- begin grader ----------------------
if (_charsNumber <= 0)
{
return -1;
}
return _buffer[_currentChar++];
}
}
if (s < 0) x = -x;
return x;
}
int main()
{
_inputFile = fopen("../tests/72", "rb");
_outputFile = fopen("teams.out", "w");
int N;
N = _readInt();
init(N, A, B);
int Q;
Q = _readInt();
for (int i = 0; i < Q; ++i)
{
int M;
M = _readInt();
int *K = (int*)malloc(sizeof(int)*(unsigned int)M);
for (int j = 0; j < M; ++j)
{
K[j] = _readInt();
}
fprintf(_outputFile,"%d\n", can(M, K));
}
return 0;
}
// --------------- end grader ----------------------
/*
execution time : 6.203 s
*/
#include<iostream>
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/72", // argv[1]=<input-file>
(char*)"teams.out", // argv[2]=<output-file>
(char*)"../tests/72.a", // argv[3]=<answer-file>
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
5.4 Horses
Problema 4 - Horses 100 de puncte
Lui Mansur ı̂i place să crească cai urmând tradiţia strămoşilor săi. El are acum ce mai mare
herghelie din Kazakhstan. Nu aşa stăteau lucrurile cu N ani ı̂n urmă. Când Mansur era doar un
dzhigit ( cuvântul Kazakh pentru tânăr ) el avea doar un singur cal. El visa să facă o grămadă
de bani şi ı̂n cele din urmă să ajungă un bai ( cuvântul kazakh pentru om foarte bogat).
Să numerotăm anii de la 0 la N 1 ı̂n ordine cronologică (adică anul N 1 este cel mai recent
an). Clima din fiecare an influenţa creşterea hergheliei. Pentru fiecare an i Mansur memorează
un coeficient de creştere ı̂ntreg şi pozitiv X i. Dacă la ı̂nceputul anului i aveai h cai atunci la
sfârşitul acestuia aveai h X i cai ı̂n herghelie.
Caii puteau fi vânduţi numai la sfârşitul unui an. Pentru fiecare an i, Mansur memorează un
ı̂ntreg pozitiv Y i: preţul unui cal la sfârşitul anului i. La sfârşitul fiecărui an era posibil să vinzi
oricâţi cai, fiecare la acelasi preţ Y i.
Mansur se ı̂ntreabă care este cea mai mare sumă de bani pe care ar putea să o obţină dacă
alege cele mai bune momente ı̂n care să vândă cai pe parcursul celor N ani. Tu ai onoarea să fii
invitaltul lui Mansur ı̂n toi ( cuvântul kazakh pentru vacanţă ) şi să răspunzi la ı̂ntrebarea lui.
Memoria lui Mansur se ı̂mbunătăţeşte seara, aşa ca va face un şir de M modificări. Fiecare
modificare va schimba fie una dintre valorile X i, fie una dintre valorile Y i. După fiecare
modificare el te ı̂ntreabă dinnou care e suma cea mai mare pe care o poate obţine din vânzarea
cailor. Modificările lui Manur sunt cumulative: fiecare răspuns trebuie să ţină cont de toate
modificările precedente. Reţineţi că oricare dintre valorile X i sau Y i ar putea fi modificată
de mai multe ori.
Răspunsul lui Mansur poate fi un număr foarte mare. Pentru a evita lucrul cu numere mari
9
se cere doar restul modulo 10 7 al răspunsului.
Exemplu
Să presupunem că N 3 ani, cu următoarele informaţii:
0 1 2
X 2 1 3
Y 3 4 1
Pentru valorile iniţiale Mansur poate obţine cel mai mult dacă vinde ambii săi cai la sfârşitul
anului 1.
Procesul decurge după cum urmează:
Iniţial, Mansur are un cal.
După anul 0 el are 1 X 0 2 cai.
După anul 1 el are 2 X 1 2 cai .
El poate acum să vândă cei doi cai. Profitul total va fi 2 Y 1 8.
Să presupunem acum că există M 1 modificări: Schimbă valoarea lui Y 1 ı̂n 2.
După modificare avem:
0 1 2
X 2 1 3
Y 3 2 1
În acest caz, una dintre soluţiile optime este să vinzi un cal după anul 0 şi apoi trei cai după
anul 2.
Procesul decurge după cum urmează:
Iniţial, Mansur are un cal.
După anul 0 el are 1 X 0 2 cai.
El poate să vândă unul dintre cai pentru Y 0 3, şi ı̂i mai rămâne un cal.
După anul 1 el are 1 X 1 1 cal.
CAPITOLUL 5. IOI 2015 5.4. HORSES 630
Cerinţă
Se dau N , X, Y , şi lista de modificări. ı̂nainte de prima modificare şi după fiecare modificare,
9
calculează suma maximă pe care o poate obţine Mansur pe caii săi, modulo 10 7.
Trebuie să implementezi funcţiile init, updateX şi updateY.
init(N, X, Y) - Grader-ul va apela prima această funcţie, exact o dată.
– N : Numărul de ani.
– X: un şir de lungime N . Pentru 0 & i & N 1, X i dă coeficientul de creştere pentru
anul i.
– Y : un şir de lungime N . Pentru 0 & i & N 1, Y i dă preţul unui cal după anul i.
– Remarcaţi că atât X cât şi Y specifică valorile iniţiale date de Mansur (ı̂nainte de orice
modificare).
– După ce apelul init se ı̂ncheie, şirurile X şi Y rămân valabile, şi poţi modifica
conţinutul lor după cum doreşti.
– Această funcţie trebuie să returneze suma maximă pe care o poate obţine Mansur pe
9
caii săi pentru aceste valori iniţiale ale lui X şi Y , modulo 10 7.
updateX(pos, val)
– pos: un ı̂ntreg din intervalul 0, ..., N 1.
– val: noua valoare a lui X pos.
– Această funcţie trebuie să returneze suma maximă pe care o poate obţine Mansur după
9
această modificare, modulo 10 7.
updateY(pos, val)
– pos: un ı̂ntreg din intervalul 0, ..., N 1.
– val: noua valoare a lui Y pos.
– Această funcţie trebuie să returneze suma maximă pe care o poate obţine Mansur după
9
această modificare, modulo 10 7.
9
Se asigură că atât valorile iniţiale cât şi cele modificate pentru X i şi Y i sunt ı̂ntre 1 şi 10
inclusiv.
După init, grader-ul va apela updateX şi updateY de câteva ori. Numărul total de apeluri
ale funcţiilor updateX şi updateY va fi M .
Subprobleme
Grader-ul de pe calculatorul tău afişează valoarea returnată de apelul init urmată de valorile
returnate de toate apelurile updateX şi updateY.
Timp maxim de executare/test: 1.5 secunde
Memorie: total 1500 MB
To solve 1-st subtask we need just calculate our answer using dynamic programming dpij -
what is maximal profit if we pass i 1 days and we have j horses then we got j xi horses and
check all number of horses that we sell today and go to the next day.
#1 Observation
First of all let’s consider to points i and j, what if we sell k horses in i-th and j-th day.
And check in what day it’s more preferable.
Profit of i-th day: x1 x2 ... xi yi
Profit of j-th day: x1 x2 ... xi xi1 ... xj yj
It depends on this
yi ? xi1 ... xj yj
¿
¡
=
so
if it’s ¿ then it’s profitably sell horses in i-th day
if it’s ¡ then it’s profitably sell horses in j-th day
if it’s = then it’s no matter when we sell them in i-th day or in j-th day.
From this point it’s clear that it is better to sell all our horses in one day that gives us maximal
profit.
Using this observation we can solve 2 subtasks.
After each query we can solve problem in O n
#2 Observation
If all xi ' 2, then after 30 days xi xi1 xi2 ... xi29 ' 2 % 10 , so position less
30 9
9
then and equal n 30 never can be optimal solution, because even if yn 30 10 and yn 1,
2 yn % yn 30
30
#include "horses.h"
#include <stdio.h>
#include <stdlib.h>
#include <bits/stdc++.h>
ll x[maxn], y[maxn];
int n;
struct node
{
double maior, soma;
ll maiorp, prod;
} tree[4*maxn];
tree[node].prod = (tree[2*node].prod*tree[2*node+1].prod)%mod;
}
tree[node].maiorp = (x[l]*y[l])%mod;
tree[node].prod = x[l]%mod;
return;
}
tree[node].maiorp = (x[l]*y[l])%mod;
tree[node].prod = x[l]%mod;
return;
}
join(node);
}
return (int)tree[1].maiorp;
}
return (int)tree[1].maiorp;
}
return (int)tree[1].maiorp;
}
if (s < 0) x = -x;
return x;
}
int main()
{
_inputFile = fopen("../tests/59", "rb");
_outputFile = fopen("horses.out", "w");
int N; N = _readInt();
fprintf(_outputFile,"%d\n",init(N,X,Y));
int M; M = _readInt();
if (type == 1)
{
fprintf(_outputFile,"%d\n",updateX(pos,val));
}
else
if (type == 2)
{
fprintf(_outputFile,"%d\n",updateY(pos,val));
}
}
return 0;
}
#include "horses.h"
#include <stdio.h>
#include <stdlib.h>
#include <bits/stdc++.h>
class node
{
CAPITOLUL 5. IOI 2015 5.4. HORSES 635
public:
int all;
int left;
int right;
int sell;
int prod;
int ans;
};
vector<node> tree;
vector<int> a, b;
int n;
}
}
if (s < 0) x = -x;
return x;
}
int main()
{
_inputFile = fopen("../tests/59", "rb");
_outputFile = fopen("horses.out", "w");
int N; N = _readInt();
fprintf(_outputFile,"%d\n",init(N,X,Y));
int M; M = _readInt();
if (type == 1)
{
fprintf(_outputFile,"%d\n",updateX(pos,val));
}
else
if (type == 2)
{
fprintf(_outputFile,"%d\n",updateY(pos,val));
}
}
return 0;
}
#include "horses.h"
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
LL n, x[MAXN], y[MAXN];
class Segtree
{
LL ST[MAXN*4][5]; // mod product, actual (or inf), opt product,
CAPITOLUL 5. IOI 2015 5.4. HORSES 638
LL opt() {return(ST[1][3]);}
} ST;
n=N;
for (int i=0; i<N; i++)
{
x[i] = X[i];
y[i] = Y[i];
}
ST.build(0, N-1, 1);
LL p = ST.opt(), prod = ST.ask(p, 0, N-1, 1);
LL ans = (prod * y[p])%MOD;
return( (int) ans);
}
if (s < 0) x = -x;
return x;
}
int main()
{
_inputFile = fopen("../tests/59", "rb");
_outputFile = fopen("horses.out", "w");
int N; N = _readInt();
fprintf(_outputFile,"%d\n",init(N,X,Y));
int M; M = _readInt();
if (type == 1)
{
fprintf(_outputFile,"%d\n",updateX(pos,val));
}
else
if (type == 2)
{
fprintf(_outputFile,"%d\n",updateY(pos,val));
}
}
return 0;
}
#include<iostream>
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/59", // argv[1]=<input-file>
(char*)"horses.out", // argv[2]=<output-file>
(char*)"../tests/59.a", // argv[3]=<answer-file>
};
cout<<"argc = "<<argc<<"\n";
CAPITOLUL 5. IOI 2015 5.5. SORTING 641
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
5.5 Sorting
Problema 5 - Sorting 100 de puncte
Aizhan are un şir de N numere ı̂ntregi S 0, S 1, ..., S N 1. Acesta constă ı̂n numere
distincte de la 0 la N 1. Ea incearcă să sorteze aceast şir ı̂n ordine crescătoare interschimbând
anumite perechi de elemente. Prietenul său Ermek interschimbă, de asemenea anumite perechi de
elemente - dar nu neapărat ı̂ntr-un mod care să o ajute.
Ermek şi Aizhan modifica şirul ı̂ntr-o serie de runde. ı̂n fiecare rundă, ı̂ntâi Ermek face o
interschimbare şi atunci Aizhan face şi ea o alta. Mai exact, persoana care face interschimbarea
alege doi indici valizi şi interschimbă elementele cu aceşti indici. De remarcat că cei doi indici nu
trebuie neapărat ca să fie distincţi. Dacă ei sunt egali, persoana schimbă un element cu el ı̂nsuşi,
deci nu afectează şirul.
Aizhan ştie că lui Ermek nu ı̂i pasă să sorteze şirul S. Ea ştie, de asemenea, indicii pe care
Ermek ı̂i va alege. Ermek plănuieşte să ia parte la M runde de interschimbări. Numerotăm aceste
runde de la 0 la M 1. Pentru fiecare i cuprins ı̂ntre 0 şi M 1 inclusiv, Ermek va alege indicii
X i şi Y i pentru runda i.
Aizhan vrea să sorteze şirul S. ı̂naintea fiecărei runde, dacă Aizhan vede că şirul este deja
sortat crescător, ea va ı̂ncheia procesul. Fiind dat şirul S şi indicii pe care ı̂i va alege Ermek,
sarcina ta este să găseşti secvenţa de interschimbări prin care Aizhan să ordoneze şirul S. ı̂n plus,
ı̂n unele subprobleme ţi se cere să găseşti o secvenţă de interschimbări cât mai scurtă posibil. Poţi
presupune că şirul S se poate ordona ı̂n M sau mai puţine runde.
De remarcat că, dacă Aizhan observă şirul S sortat după o mutare a lui Ermek, ea poate
alege doi indici egali (de exemplu 0 şi 0). şirul rezultat este de asemenea sortat, deci Aizhan ı̂şi
ı̂ndeplineşte scopul. De remarcat, de asemenea, că dacă şirul iniţial S este deja sortat, numărul
minim de runde necesar ordonării este 0.
Examplul 1
Presupunem următoarele:
şirul iniţial este S 4, 3, 2, 1, 0.
Ermek ı̂şi propune să facă M 6 mutări.
şirurile X şi Y care descriu indicii pe care Ermek ı̂i foloseşte sunt: X 0, 1, 2, 3, 0, 1 şi
Y 1, 2, 3, 4, 1, 2. Cu alte cuvinte, perechile de indici pe care Ermek plănuieşte să ı̂i aleagă
sunt: (0,1), (1,2), (2,3), (3,4), (0,1) şi (1,2).
În această situaţie Aizhan poate ordona şirul S ı̂n ordinea 0, 1, 2, 3, 4 ı̂n trei runde. Ea poate
face asta alegând indicii (0,4), (1,3) şi (3,4).
Tabelul următor arată cum Ermek şi Aizhan modifică şirul.
CAPITOLUL 5. IOI 2015 5.5. SORTING 642
Examplul 2
Presupunem următoarele:
Şirul iniţial este S 3, 0, 4, 2, 1.
Ermek ı̂şi propune să facă M 5 mutări.
Perechile de indici pe care Ermek plănuieşte să ı̂i aleagă sunt: (1,1), (4,0), (2,3), (1,4) şi
(0,4).
În această situaţie Aizhan poate sorta secvenţa S ı̂n trei runde, de exemplu alegând perechile
de indici (1,4), (4,2) şi (2,2). Următorul tabel arată cum Ermek şi Aizhan modifică secvenţa.
Cerinţa
Ţi se dă şirul S, numărul M şi şirurile de indici X şi Y . Determină o secvenţă de inter-
schimbări pe care Aizhan o poate folosi pentru a sorta şirul S. ı̂n subproblemele 5 şi 6 secvenţa
de interschimbări pe care să o găseşti trebuie să fie cea mai scurtă posibilă.
Trebuie să implementezi funcţia findSwapPairs:
findSwapPairs(N, S, M, X, Y, P, Q) - Această funcţie va fi apelată de grader ex-
act o dată.
– N : lungimea şirului S.
– S: un şir de ı̂ntregi reprezentând şirul S iniţial.
– M : numărul de paşi pe care Ermek plănuieşte să ı̂i facă.
– X, Y : tablouri de ı̂ntregi de lungime M . Pentru 0 & i & M 1, ı̂n runda i, Ermek
plănuieşte să aleagă perechea de indici X i şi Y i.
– P , Q: tablouri de ı̂ntregi. Utilizează aceste tablouri pentru a returna o posibilă
secvenţă de interschimbări prin care Aizhan poate ordona şirul S. Notăm cu R lungimea
secvenţei de interschimbări pe care programul tău a găsit-o. Pentru fiecare i cuprins
ı̂ntre 0 şi R 1 inclusiv, indicii pe care Aizhan trebuie să ı̂i aleagă ı̂n runda sunt
memoraţi ı̂n P i şi Qi. Poţi presupune că tablourile P şi Q au deja alocate câte M
elemente fiecare.
– Această funcţie trebuie să returneze valoarea lui R (definită mai sus).
Subprobleme
CAPITOLUL 5. IOI 2015 5.5. SORTING 643
Poţi presupune că există o soluţie care să necesite maxim M runde.
Grader-ul de pe calculatorul tău
Grader-ul de pe calculatorul tău citeşte intrarea din fişierul sorting.in ı̂n următorul format:
linia 1: N
linia 2: S 0 ... S N 1
linia 3: M
liniile 4, ..., M 3: X i Y i
Subtask 1
In subtask 1, Bob do not change sequence s, thus any method that can sort the sequence in
increasing order will be a solution.
2
A bubble sort or insertion sort may cost at most O n swaps. A merge sort or quick sort may
cost at most O n log n swaps.
The optimized solutions is selection sort. Since the sequence contains 0, 1, ..., n 1 exactly
once, we can swap value i into position i one by one (i=0, 1, ..., n 1). This costs at most n 1
swaps. It can be proved that the number of swaps is minimized.
Subtask 2
In subtask 2, Bob will swap positions 0 and 1, which makes the problem more complicated.
However, the solution does not change much. We can swap value i into position i one by one from
the rightmost position to the leftmost one (i n 1, n 2, ..., 1, 0). The number of swaps is also
minimized.
Subtask 3
In subtask 3, we distinguish Alice and Bobs swaps. Let a0 0, a1 1, ..., an 1 n 1
be n plates in a queue, and b0 s0, b1 s1, ..., bn 1 sn 1 be n apples on plates
0, 1, ..., n 1. Then si bai.
If Bob swap two positions x and y, it can be viewed as two plates are swapped. For example,
in the above case, if Bob swaps numbers at positions 0 and 1, the result sequence will be:
CAPITOLUL 5. IOI 2015 5.5. SORTING 644
If Alice swap two positions p and q, it can be viewed as two apples sp and sq are swapped.
For example, if Alice swaps numbers are positions 0 and 4, it can be viewed as apples s0 3
and s4 0 are swapped:
Now Bob swaps two plates in each round and Alice swaps two apples. Since they operates on
difference objects, the sequence of operations can be separated. Let t be the number of rounds
Alice takes. It can be viewed as Bob first swap t pairs of plates, then Alice swap t pairs of apples.
Since Alice can sort all apples in increasing order in less than n swaps, the minimum number of
rounds is less than n.
Solution: One solution for this problem would be enumerate t from 0 to n 1, and check
whether Alice can sort all apples within t swaps after Bob swap first t pairs of plates. This costs
2
O n time and will get timeout for some test cases.
Binary Search: For this problem, if p0 , q0 , p1 , q1 , ..., pt1 , qt1 be a solution for Alice
in t swaps, then p0 , q0 , p1 , q1 , ..., pt1 , qt1 , xt , yt , ..., xe1 , ye1 must be a solution for
Alice in e swaps (e % t). Which means that if there is a feasible solution in t swaps, then there
must be feasible solutions in more than t swaps. Which makes the problem solvable using binary
search. The time complexity reduces to O n log n and full mark is expected.
Implementation: The implementation of this problem may be a little bit error prone. It is
recommended that programs first find out pairs of numbers (i.e. pairs of apples) to swap, then
transform numbers into their positions. An inversed array that maps each number to its position
is helpful.
Comments
2
The O n time solution is essentially updating a set of cycles under splicing (edge insertion
/ deletion) operations. Some care is needed in test data making to distinguish it from O n log n
time solutions, perhaps the bounds can be raised to ease this process.
1.5
This solution can also be made to run in O n or O n log n time using BBST-like data
structures (e.g. http://contest.felk.cvut.cz/11cerc/solved/r/). This is way more
work than the intended solution though.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "sorting.h"
#include<algorithm>
#include<vector>
#include<iostream>
vector<pair<int,int> > v;
int n,ps[300000],s[300000],x[300000],y[300000],rev_ps[300000],r[300000];
CAPITOLUL 5. IOI 2015 5.5. SORTING 645
int qayl_qan()
{
int q=0;
for(int i=0;i<n;i++)
rev_ps[ps[i]]=i;
for(int i=0;i<n;i++)
{
if(ps[rev_ps[i]]==ps[i])
continue;
int e=ps[i];
swap(ps[rev_ps[i]],ps[i]);
q++;
swap(rev_ps[i],rev_ps[e]);
}
return q;
}
int stug(int e)
{
for(int i=0;i<n;i++)
ps[i]=s[i];
for(int i=0;i<=e;i++)
swap(ps[x[i]],ps[y[i]]);
if(qayl_qan()<=e+1)
return 1;
else
return 0;
}
int mid=(l+r)/2;
if(stug(mid))
bin(l,mid);
else
bin(mid+1,r);
}
int findSwapPairs(int N, int S[], int M, int X[], int Y[], int P[], int Q[])
{
if(M>=N)
M=N-1;
for(int i=0;i<N;i++)
s[i]=S[i];
for(int i=0;i<M;i++)
{
x[i]=X[i];
y[i]=Y[i];
}
n=N;
for(int i=0;i<n;i++)
ps[i]=s[i];
if(qayl_qan()==0)
return 0;
int t=bin(0,M-1);
t++;
for(int i=0;i<n;i++)
ps[i]=s[i];
for(int i=0;i<t;i++)
swap(ps[x[i]],ps[y[i]]);
for(int i=0;i<n;i++)
rev_ps[ps[i]]=i;
for(int i=0;i<n;i++)
{
if(ps[rev_ps[i]]==ps[i])
continue;
int e=ps[i];
swap(ps[rev_ps[i]],ps[i]);
v.push_back({ps[i],e});
swap(rev_ps[i],rev_ps[e]);
}
for(int i=0;i<n;i++)
CAPITOLUL 5. IOI 2015 5.5. SORTING 646
r[s[i]]=i;
for(int i=0;i<t;i++)
{
swap(s[x[i]],s[y[i]]);
swap(r[s[x[i]]],r[s[y[i]]]);
if(v.size()>i)
{
P[i]=r[v[i].first];
Q[i]=r[v[i].second];
}
else
{
P[i]=0;
Q[i]=0;
}
swap(s[P[i]],s[Q[i]]);
swap(r[s[P[i]]],r[s[Q[i]]]);
}
return t;
}
if (_charsNumber <= 0)
{
return -1;
}
return _buffer[_currentChar++];
}
int main()
{
CAPITOLUL 5. IOI 2015 5.5. SORTING 647
int N, M;
N = _readInt();
int *S = (int*)malloc(sizeof(int) * (unsigned int)N);
M = _readInt();
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "sorting.h"
#include <bits/stdc++.h>
#define NN 200005
int val[NN];
int loc[NN];
int S[NN];
int n;
vector<pii> sw;
bool in[NN];
n = N;
for(int i = 0; i < N; i++)
{
S[i] = qq[i];
val[i] = S[i];
loc[val[i]] = i;
}
int l = 0, r = N, m;
while(l != r)
{
int cyc = 0;
m = (l + r) >> 1;
for(int i = 0; i < m; i++)
swap(S[X[i]], S[Y[i]]);
return l;
}
if (_charsNumber <= 0)
{
return -1;
}
return _buffer[_currentChar++];
}
int main()
{
_inputFile = fopen("../tests/subtaskf/25", "rb");
_outputFile = fopen("sorting.out", "w");
int N, M;
N = _readInt();
int *S = (int*)malloc(sizeof(int) * (unsigned int)N);
M = _readInt();
return 0;
}
#include <vector>
#include <iostream>
int findSwapPairs(int n, int S[], int M, int X[], int Y[], int P[], int Q[])
{
vector<int> perm(n);
bool bc = true;
for (int i = 0; i < n; i++)
{
perm[i] = S[i];
if (perm[i] != i) bc = false;
}
if (bc) return 0;
vector<int> b = perm;
vector<int> beg = perm;
for (int i = 0; i < n; i++)
{
swap(perm[X[i]], perm[Y[i]]);
}
vector<int> end = perm;
int l = 0;
int r = n;
while (r - l > 1)
{
int m = (l + r)/2;
vector<int> mv = beg;
for (int i = l; i < m; i++)
{
swap(mv[X[i]], mv[Y[i]]);
}
if (ctr <= m)
{
r = m;
end = mv;
}
else
{
l = m;
beg = mv;
}
}
vector<pair<int,int>> swp;
perm = b;
CAPITOLUL 5. IOI 2015 5.5. SORTING 651
vector<int> revind(n);
for (int i = 0; i < n; i++)
{
revind[perm[i]] = i;
}
return r;
}
if (_charsNumber <= 0)
{
return -1;
}
return _buffer[_currentChar++];
}
{
s = -1;
c = _read();
}
while (c > 32)
{
x *= 10;
x += c - ’0’;
c = _read();
}
if (s < 0) x = -x;
return x;
}
int main()
{
_inputFile = fopen("../tests/subtaskf/25", "rb");
_outputFile = fopen("sorting.out", "w");
int N, M;
N = _readInt();
int *S = (int*)malloc(sizeof(int) * (unsigned int)N);
M = _readInt();
return 0;
}
#include <bits/stdc++.h>
int n,m,*x,*y,*s,*p,*q;
int a[500010],b[500010],c[500010],d[500010];
bool f(int z)
{
int i,j;
for(i=0;i<n;i++)
{
a[i]=b[i]=s[i];
}
CAPITOLUL 5. IOI 2015 5.5. SORTING 653
for(i=0;i<z;i++)
{
swap(a[x[i]],a[y[i]]);
}
for(i=0;i<n;i++)
{
c[a[i]]=i;
d[b[i]]=i;
}
j=0;
for(i=0;i<z;i++)
{
swap(d[b[x[i]]],d[b[y[i]]]);
swap(b[x[i]],b[y[i]]);
while(j<n&&a[j]==j)j++;
if(j==n)p[i]=q[i]=0;
else
{
p[i]=d[j],q[i]=d[a[j]];
swap(b[d[j]],b[d[a[j]]]);
swap(d[j],d[a[j]]);
c[a[j]]=c[j];
swap(a[j],a[c[j]]);
c[j]=j;
}
}
int findSwapPairs(int N, int S[], int M, int X[], int Y[], int P[], int Q[])
{
n=N;s=S;m=M;x=X;y=Y;p=P;q=Q;
int lo=0,hi=M;
while(lo<hi)
{
int mid=(lo+hi)/2;
if(f(mid))hi=mid;
else lo=mid+1;
}
f(lo);
return lo;
}
if (_charsNumber <= 0)
{
return -1;
}
return _buffer[_currentChar++];
}
CAPITOLUL 5. IOI 2015 5.5. SORTING 654
int main()
{
_inputFile = fopen("../tests/subtaskf/25", "rb");
_outputFile = fopen("sorting.out", "w");
int N, M;
N = _readInt();
int *S = (int*)malloc(sizeof(int) * (unsigned int)N);
M = _readInt();
return 0;
}
#include<bits/stdc++.h>
#include "sorting.h"
int findSwapPairs(int N, int S[], int M, int X[], int Y[], int P[], int Q[])
{
auto check = [&](int R)
{
vector<int> s(N), ws(N), wf(N);
REP(i, N) s[i] = S[i];
auto f = s;
REP(i, R) swap(f[X[i]], f[Y[i]]);
REP(i, N)
{
ws[S[i]] = i;
wf[f[i]] = i;
}
int j = 0;
REP(i, R)
{
int &p = s[X[i]], &q = s[Y[i]];
swap(p, q);
swap(ws[p], ws[q]);
int l = 0, r = M;
while(l < r)
{
int m = (l + r) / 2;
if(check(m))
r = m;
else
l = m + 1;
}
check(l);
return l;
}
if (_charsNumber <= 0)
{
return -1;
}
return _buffer[_currentChar++];
}
int main()
{
_inputFile = fopen("../tests/subtaskf/25", "rb");
_outputFile = fopen("sorting.out", "w");
int N, M;
N = _readInt();
int *S = (int*)malloc(sizeof(int) * (unsigned int)N);
M = _readInt();
return 0;
}
#include <string.h>
#include "sorting.h"
#include <bits/stdc++.h>
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int N,S[200001];
int M,X[600001],Y[600001];
int arr[200001];
bool vis[200001];
int to[200001];
deque<pair<int,int>>q;
int pos[200001];
int findSwapPairs(int n,int s[],int m, int x[], int y[], int P[], int Q[])
{
N=n;
for (int i=0;i<N;i++)
S[i]=s[i];
M=m;
for (int i=1;i<=M;i++)
{
X[i]=x[i-1];
Y[i]=y[i-1];
}
int low=-1,high=M+1;
while (low+1<high)
{
int mid=(low+high)/2;
if (check(mid))
CAPITOLUL 5. IOI 2015 5.5. SORTING 658
high=mid;
else
low=mid;
}
check(high);
for (int i=high;i>=1;i--)
{
if (!q.empty()){
P[i-1]=pos[q[0].first];
Q[i-1]=pos[q[0].second];
swap(pos[arr[X[i]]],pos[arr[Y[i]]]);
swap(arr[X[i]],arr[Y[i]]);
q.pop_front();
}
}
if (_charsNumber <= 0)
{
return -1;
}
return _buffer[_currentChar++];
}
}
if (s < 0) x = -x;
return x;
}
int main()
{
_inputFile = fopen("../tests/subtaskf/25", "rb");
_outputFile = fopen("sorting.out", "w");
int N, M;
N = _readInt();
int *S = (int*)malloc(sizeof(int) * (unsigned int)N);
M = _readInt();
return 0;
}
5.6 Towns
Problema 6 - Towns 100 de puncte
Fiecare autostradă are o lungime pozitivă ı̂ntreagă. Distanţa dintre două localităţi este suma
minimă a lungimilor autostrăzilor necesare pentru a ajunge dintr-o localitate ı̂n cealaltă.
Pentru fiecare municipiu C putem măsura distanţa r C până la cel mai depărtat de el orăşel.
Municipiul C este un hub dacă distanţa r C este cea mai mică dintre toate municipiile.
Distanţa dintre hub şi cel mai depărtat de el orăşel este notată prin R. Astfel, R este cea mai
mică dintre toate valorile r C .
În exemplul de mai sus cel mai depărtat orăşel de municipiul a este cel cu numărul 8 şi distanţa
dintre ele este r a 1 4 12 17. Pentru municipiul g de asemena avem r g 17. (Unul
dintre orăşelele cele mai depărtate de g este cel cu numărul 6). Unicul hub din exemplu este
municipiul f cu r f 16. Astfel, ı̂n exemplul de mai sus R este 16.
Eliminarea unui hub ı̂mparte reţeaua ı̂n multiple componente conexe. Un hub este echilibrat
dacă fiecare dintre aceste componente conţine cel mult N ©2$ orăşele. (Subliniem că municipiile
nu se numără). Prin x$ se notează cel mai mare ı̂ntreg care nu depăşeşte x.
În exemplul nostru municipiul f este hub. Dacă f este eliminat, reţeaua se va ı̂mpărţi ı̂n patru
componente conexe. Aceste patru componente sunt formate din următoarele seturi de orăşele:
{0,1,10}, {2,3}, {4,5,6,7}, şi {8,9}. Niciuna dintre componente nu are mai mult de 11©2$ 5
orăşele, astfel municipiul f este un hub echilibrat.
Cerinţă
Iniţial, unica informaţie despre reţeaua localităţilor şi autostrăzilor de care dispunem este
numărul de orăşele. Numărul de municipii nu este cunoscut. De asemenea nu se ştie nimic despre
schema autostrăzilor din ţară. Putem obţine informaţii noi doar prin interogări privind distanţa
dintre perchi de orăşele.
Sarcina ta este să determini:
ı̂n toate subproblemele: distanţa .
ı̂n subproblemele de la 3 la 6: dacă există un hub echilibrat ı̂n reţea.
Urmează să implementezi funcţia hubDistance. Grader-ul va evalua teste multiple ı̂ntr-o
singură execuţie. Numărul de teste pentru o execuţie va fi cel mult 40. Pentru fiecare test grader-
ul va apela funcţia ta hubDistance exact o singură dată. Asigură-te că funcţia ta iniţializează
toate variabilele necesare de fiecare dată când este apelată.
hubDistance(N, sub)
– N : numărul de orăşele.
– sub: numărul subproblemei (explicat ı̂n secţiunea Subprobleme).
– Dacă sub este 1 sau 2, funcţia poate returna R sau R
– Dacă sub este mai mare decât 2 şi există un hub echilibrat, atunci funcţia va returna
R, ı̂n caz contrar va returna R.
Funcţia ta hubDistance poate obţine informaţia despre reţeaua de autostrăzi apelând funcţia
graderului getDistance(i, j). Această funcţie returnează distanţa dintre orăşelele i şi j. De
remarcat că, pentru i şi j egale, funcţia returnează 0. Ea de asemena va returna 0 ı̂n cazul ı̂n care
argumentele sunt nevalide.
Subprobleme
În fiecare test:
CAPITOLUL 5. IOI 2015 5.6. TOWNS 661
Numărul de interogări pe care le poate face programul tău este limitat. Limita variază ı̂n
funcţie de subproblemă, după cum este indicat ı̂n tabelul care urmează. Dacă programul tău
ı̂ncearcă să depăşească limita de interogări, el va fi terminat şi se va considera că ai obţinut un
răspuns incorect.
Amintim că, prin *x0 se notează cel mai mic ı̂ntreg care este mai mare sau egal cu x.
Grader-ul de pe calculatorul tău
Atenţionăm că, numărul subproblemei este o parte din input. Grader-ul de pe calculatorul tău
ı̂şi schimbă comportamentul ı̂n concordanţă cu numărul subproblemei.
Grader-ul de pe calculatorul tău citeşte input-ul din fişierul towns.in ı̂n următorul format:
linia 1: Numărul subproblemei şi numărul de teste.
linia 2: N1 , numărul de orăşele ı̂n primul test.
următoarele N1 linii: Al j-lea număr (1 & j & N1 ) ı̂n a i-a din aceste linii 1 & i & N1 este
distanţa dintre orăşelele i 1 şi j 1.
Urmează celelalte teste. Ele sunt descrise ı̂n acelaşi format ca şi primul test.
Pentru fiecare test grader-ul afişează valoarea returnată de hubDistance şi numărul de
apeluri efectuate, ı̂n linii separate.
Fişierul input care corespunde exemplului descris anterior este:
1 1
11
0 17 18 20 17 12 20 16 23 20 11
17 0 23 25 22 17 25 21 28 25 16
18 23 0 12 21 16 24 20 27 24 17
20 25 12 0 23 18 26 22 29 26 19
17 22 21 23 0 9 21 17 26 23 16
12 17 16 18 9 0 16 12 21 18 11
20 25 24 26 21 16 0 10 29 26 19
16 21 20 22 17 12 10 0 25 22 15
23 28 27 29 26 21 29 25 0 21 22
20 25 24 26 23 18 26 22 21 0 19
11 16 17 19 16 11 19 15 22 19 0
Acest format este diferit de specificarea listei de autostrăzi. De notat că este permis să modifici
grader-ele de pe calculatorul tău, astfel ı̂ncât ele să folosească un format diferit pentru input.
Timp maxim de executare/test: 1.0 secunde
Memorie: total 1500 MB
CAPITOLUL 5. IOI 2015 5.6. TOWNS 662
The graph given in this task is an edge-weighted tree T ), in which the degree of each internal node
is at least three.
Let n denote the number of leaves of T ).
The goal is to find the centers of the tree and determine if any center is also a leaf median (an
internal node such that after removing the node, every component contains at most n/2 leaves.
In this task, the tree is not given, and the contestants must solve the task by using limited
number of queries for distances between leaves.
An algorithm using 7n©2 queries is sketched as follows. The details are in the next sections.
* First, find the centers by at most 2n 3 queries; and then
* for each center (at most two centers), determine if it is also a leaf median by using no more
than 3n©2 queries.
Radius and centers
The diameter of a tree can be found with 2n 3 queries as follows.
* Farthest to-Farthest: Pick an arbitrary vertex v and find a vertex s farthest to r. Find a
vertex t farthest to s. It can be shown that d s, t is a diameter of the tree.
* Any center must be one the vs-path.
* Then the vertices on the vs-path with its distance to s closest to d s, t©2 are centers.
Determining if a center is also a median
Let v, s be the two leaves in the above process and m be a center on the vs-path with
d s, m r. We need to determine if each component of T m has at most n©2.
Let S be the set of all leaves.
First we compute the multiset
B r d u, s d s, v d u, v ©2¶¾u " S x.
Each of the different values in B identifies a unique internal vertex on the sv-path.
0 0
Let m be the internal vertex on the sv-path with d s, m α, where α is the median of the
multiset B.
0
If we root T at the sv-path, the leaf median must be in the subtree rooted at m . Therefore if
0
r α (i.e., m m ), then m is not a median. Note that there are two medians in B if ¶B ¶ is even.
Otherwise it remains to solve the ”giant component” problem: checking if there is a component
in T m with more than n©2 leaves.
Let
X ru " S ¶d u, s d s, v d u, v 2rx
which is the set of the leaves branching from sv-path at m.
For x1 , x2 " X, we have that x1 , x2 are in the same component of T m iff
Then, we can solve the giant component problem by algorithms for the following problem:
There are n color balls and we want to determine if there are more than n©2 balls of the same
color.
The cost is counted by the number of performed queries R u, v which returns Equal/NotEqual
according to if u and v are of the same color.
It was shown that *3n©20 2 queries are necessary and sufficient in Fischer and Salzberg
(1982), Solution to problem 81-5, J. Algorithms, pp. 376-379.
(https://www.researchgate.net/publication/
242568474_Finding_a_majority_among_n_votes_Solution_to_problem_81-5)
The following is another similar approach.
Initially each element is itself a set. At each iteration, we arbitrarily pair up the survival
sets and compare their representatives. If they are equal, then join the two sets into their union.
Otherwise, mark both dead.
In the case that the number of alive sets is odd, mark anyone dead. Repeating this process,
eventually either there is exactly one survival set or all sets are dead.
It can be shown that if there is a majority originally, then it must be the survival one.
CAPITOLUL 5. IOI 2015 5.6. TOWNS 663
So the remaining work is to compare the survival representative with the representatives of all
DEAD sets.
The number of comparisons: Let Ai denote the number of alive sets in the i-th iteration
(A0 n). The number of comparisons to obtain the only survival set is
1©2 A0 A1 A2 ....
In the second stage the number of comparisons is the number of dead sets.
Let Di denote the number of sets die at iteration i. Then, we have D1 A0 2A1 .
Similarly Di Ai1 2Ai .
Therefore, the total number of dead sets is
#include "towns.h"
#include <assert.h>
CAPITOLUL 5. IOI 2015 5.6. TOWNS 664
#include <stdio.h>
#include <stdlib.h>
#include "graderlib.c"
#include <bits/stdc++.h>
int qs[maxn][maxn];
int deb = 0;
int n;
int query(int a, int b)
{
assert(a < n && b < n && a >= 0 && b >= 0);
if (a > b) swap(a, b);
if (qs[a][b] == -1) qs[a][b] = getDistance(a, b);
return qs[a][b];
}
int a, b;
int B;
bool subtree(int x, int y)
{
int xd = (query(a, x) + query(b, x) - query(a, b)) / 2;
int yd = (query(a, y) + query(b, y) - query(a, b)) / 2;
return (xd + yd) > query(x, y);
}
a = 0, b = 0;
for (int i = 0; i < n; i++)
if (query(0, a) < query(0, i)) a = i;
B = b; b = 0;
int hu = -1, out = inf;
for (int i = 0; i < n; i++)
{
int cd = (query(a, i) + query(b, i) - query(a, b)) / 2;
int ad = query(a, i) - cd;
int bd = query(a, B) - ad;
hu = query(a, B) - hu;
if (v.size() == 0)
{
if (max(lef, rig) > n / 2) return -out;
else return out;
}
int cnt = 0;
int kan = li.back();
cnt += buk.size();
int main()
{
FILE *f;
f = freopen("../tests/subtask_6/03","r",stdin);
assert(f != NULL);
f = freopen("towns.out","w",stdout);
assert(f != NULL);
int ncase, R, N;
int subtask;
int ret;
ret = scanf("%d%d",&subtask,&ncase);
assert(ret == 2);
_ini_query(N,subtask);
R=hubDistance(N,subtask);
printf("%d\n",R);
}
return 0;
}
#include <bits/stdc++.h>
#define ff first
#define ss second
int d[2][115], v;
map<int, int> cntr;
int T = d[0][v], D = 0;
for(int i = 0; i < N; i++)
D = max(D, d[1][i] = getDistance(v, i));
int r = 1000000000;
for(auto& x : cntr)
{
if(l <= N / 2 && N - (l += x.ss) <= N / 2)
{
if(max(x.ff, D - x.ff) == r)
{
if(x.ss <= N / 2) return r;
chk = x.ff << 1;
}
}
}
while(s.size() > 1)
{
for(int i = 1; i < s.size(); i += 2)
{
if(getDistance(s[i - 1][0],
s[i][0]) == d[0][s[i - 1][0]] + d[1][s[i][0]] - T)
{
de.push_back(s[i - 1]);
de.push_back(s[i]);
}
else
{
for(int& x : s[i - 1])
s[i].push_back(x);
t.push_back(s[i]);
}
}
if(s.size() & 1)
{
de.push_back(s.back());
la = s.back();
}
swap(s, t);
t.clear();
}
int sz = 0;
if(s.empty()) s.push_back(la);
else sz = s[0].size();
if(s[0].empty()) return r;
for(auto& x : de)
{
if(getDistance(x[0], s[0][0]) != d[0][s[0][0]] + d[1][x[0]] - T)
sz += x.size();
}
int main()
{
FILE *f;
f = freopen("../tests/subtask_6/03","r",stdin);
assert(f != NULL);
f = freopen("towns.out","w",stdout);
assert(f != NULL);
CAPITOLUL 5. IOI 2015 5.6. TOWNS 668
int ncase, R, N;
int subtask;
int ret;
ret = scanf("%d%d",&subtask,&ncase);
assert(ret == 2);
_ini_query(N,subtask);
R=hubDistance(N,subtask);
printf("%d\n",R);
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <vector>
int n;
int d[2][nmax];
int to[nmax],wh[nmax],sz[nmax];
vector<int> domin[nmax];
bool checkHub(int x)
{
vector<int> cand;
for(int i=0;i<n;i++)
{
domin[i].clear();
sz[i]=0;
}
for(int i=0;i<n;i++)
if(wh[i]==x)
cand.push_back(i);
int act=0,bal=0;
for(auto it: cand)
{
if(bal==0)
{
act=it;
bal++;
}
else
{
if(eq(act,it)) bal++;
CAPITOLUL 5. IOI 2015 5.6. TOWNS 669
else
{
domin[act].push_back(it);
bal--;
}
}
sz[act]++;
}
int ap=0;
for(auto it:cand)
{
if(sz[it])
{
if(eq(act,it)) ap+=sz[it]-(int)domin[it].size();
else
{
for(auto oth: domin[it])
{
ap+=eq(act,oth);
}
}
}
}
return (ap<=n/2);
}
int minDist=(1<<30);
int lim=d[1][d2]-(d[0][d2]+d[1][d2]-d[0][d1])/2;
for(int i=0; i<n; i++)
{
to[i]=(d[0][i]+d[1][i]-d[0][d1])/2;
wh[i]=(d[1][i]-to[i]);
if(max(wh[i],mx-wh[i])<minDist&&wh[i]<=lim)
minDist=max(wh[i],mx-wh[i]);
}
vector<int> hubs;
for(int i=0;i<n;i++)
if(max(wh[i],mx-wh[i])==minDist&&wh[i]<=lim)
hubs.push_back(wh[i]);
sort(hubs.begin(),hubs.end());
hubs.resize(unique(hubs.begin(),hubs.end())-hubs.begin());
bool ok=0;
for(auto cen :hubs)
{
int mici=0,mari=0;
for(int i=0;i<n;i++)
{
if(wh[i]<cen) mici++;
if(wh[i]>cen) mari++;
}
CAPITOLUL 5. IOI 2015 5.6. TOWNS 670
if(mici<=n/2&&mari<=n/2)
ok=checkHub(cen);
}
R=minDist;
if(!ok) R=-R;
return R;
}
int main()
{
FILE *f;
f = freopen("../tests/subtask_6/03","r",stdin);
assert(f != NULL);
f = freopen("towns.out","w",stdout);
assert(f != NULL);
int ncase, R, N;
int subtask;
int ret;
ret = scanf("%d%d",&subtask,&ncase);
assert(ret == 2);
_ini_query(N,subtask);
R=hubDistance(N,subtask);
printf("%d\n",R);
}
return 0;
}
#include<iostream>
int main()
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/subtask_6/03", // argv[1]=<input-file>
(char*)"towns.out", // argv[2]=<output-file>
(char*)"../tests/subtask_6/03.a", // argv[3]=<answer-file>
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
6.1 Game
Problema 1 - Game 100 de puncte
Jian-Jia este un tânăr căruia ı̂i plac jocurile. Când i se pune o ı̂ntrebare, el preferă să joace
jocuri ı̂n loc să răspundă direct. Jian-Jia a ı̂ntâlnit-o pe prietena sa Mei-Yu şi i-a povestit despre
reţeaua aeriană din Taiwan. Există n oraşe ı̂n Taiwan (numerotate 0, ..., n 1), dintre care unele
sunt conectate prin zboruri directe. Fiecare zbor conectează două oraşe şi poate fi folosit ı̂n ambele
direcţii.
Mei-Yu l-a ı̂ntrebat pe Jian-Jia dacă este posibil să călătorească cu avionul ı̂ntre oricare două
oraşe (fie direct, fie indirect). Jian-Jia nu a vrut să răspundă, dar ı̂n schimb, a sugerat să joace
un joc. Mei- Yu poate să ı̂i pună ı̂ntrebări de forma: ”Există un zbor direct ı̂ntre oraşele x şi y?”,
şi Jian-Jia va răspunde acestor ı̂ntrebări imediat. Mei-Yu va ı̂ntreba despre fiecare pereche de
oraşe o singură dată, punând r n n 1©2 ı̂ntrebări ı̂n total. Mei-Yu câştigă jocul dacă, după
ce obţine răspunsurile la primele i ı̂ntrebări cu i $ r, poate afirma cu certitudine dacă reţeaua
de zbor este conexă, adică dacă este posibil zborul (direct sau indirect) ı̂ntre oricare două oraşe.
Altfel, adică dacă are nevoie de toate cele r ı̂ntrebări, ı̂nvingător este considerat Jian-Jia.
Pentru a face jocul mai amuzant pentru Jian-Jia, cei doi au convenit că el poate răspunde după
cum doreşte, fără a ţine cont de reţeaua aeriană reală din Taiwan, inventând reţeaua pe măsură
ce jocul progresează, alegându-şi răspunsurile ı̂n funcţie de ı̂ntrebările puse anterior de Mei-Yu.
Sarcina ta este să-l ajuţi pe Jian-Jia să câştige jocul, decizând, care ar trebui să fie răspunsurile
lui.
Exemple
Vom explica regulile jocului prin următoarele trei exemple. Fiecare exemplu are n 4 oraşe
şi r 6 runde de ı̂ntrebări şi răspunsuri.
În primul exemplu (din următorul tabel), Jian-Jia pierde deoarece după runda 4, Mei-Yu ştie
cu certitudine că se poate zbura ı̂ntre oricare două oraşe, indiferent de răspunsurile lui Jian-Jia la
ı̂ntrebările 5 sau 6.
rundă ı̂ntrebare răspuns
1 0, 1 yes
2 3, 0 yes
3 1, 2 no
4 0, 2 yes
... ... ...
5 3, 1 no
6 2, 3 no
36
aur: Rareş Darius Buhai, Liviu Rebreanu (Bistriţa)
. argint: Alexandru Velea, Tiberiu Popoviciu (Cluj)
. argint: Andrei Heidelbacher, C.D. Loga (Timişoara)
. bronz: Mihai-Dan Gheorghe, ICHB (Bucureşti).
672
CAPITOLUL 6. IOI 2014 6.1. GAME 673
În următorul exemplu Mei-Yu poate demonstra după runda a treia, că indiferent cum va
răspunde Jian-Jia la ı̂ntrebările 4, 5, sau 6, nu se poate călători ı̂ntre oraşele 0 şi 1 prin zboruri,
deci Jian-Jia pierde din nou.
În exemplul final Mei-Yu nu poate determina dacă se poate călători ı̂ntre oricare două oraşe
prin zboruri, până când Jian-Jia nu va răspunde la toate cele şase ı̂ntrebări, astfel Jian-Jia câştigă
jocul.
Mai exact, deoarece Jian-Jia a răspuns yes la ultima ı̂ntrebare (din următorul tabel), este
posibilă călătoria ı̂ntre oricare două oraşe. Totuşi, dacă Jian-Jia ar fi răspuns no la ultima ı̂ntrebare
acest lucru nu ar fi fost posibil.
Cerinţă
Scrieţi un program care ı̂l ajută pe Jian-Jia să câştige jocul. Se ştie că nici Mei-Yu nici Jian-Jia
nu cunosc unul strategia celuilalt. Mei-Yu poate ı̂ntreba despre perechile de oraşe ı̂n orice ordine,
iar Jian- Jia trebuie să răspundă la ele imediat, fără a cunoaşte următoarele ı̂ntrebări. Voi trebuie
să implementaţi următoarele două funcţii.
initialize(n) – Noi vă vom apela funcţia initialize o singură dată, la ı̂nceput.
Parametrul n reprezintă numărul de oraşe.
hasEdge(u, v) – Apoi vă vom apela funcţia hasEdge de ori. Aceste apeluri reprezintă
ı̂ntrebările domnişoarei Mei-Yu ı̂n ordinea ı̂n care acestea sunt puse. Voi trebuie să răspundeţi
dacă există sau nu un zbor direct ı̂ntre oraşele şi . Mai exact, valoarea returnată trebuie să
fie 1 dacă există un zbor direct şi 0 ı̂n caz contrar.
Subprobleme
Fiecare subproblemă (subtask) constă din mai multe jocuri. Veţi primi puncte pentru o sub-
problemă dacă programul vostru câştigă toate jocurile pentru Jian-Jia.
subproblemă puncte n
1 15 n 4
2 27 4 & n & 80
3 58 4 & n & 1500
Detalii de implementare
Trebuie să ı̂ncărcaţi exact un fişier, numit game.c, game.cpp sau game.pas. ı̂n acest fişier vor
fi implementate cele două funcţii descrise mai sus, utilizând următoarele antete.
pentru programele C/C++
Let Eyes be the set of edges about which the contestant has answered ”yes” (connected), Eno the
set of edges about which contestant has answered ”no”, and Emaybe the rest of the edges, whose
statuses are not yet determined.
Also, let G V, Eyes and H V, Eyes < Emaybe . G is the graph you get by assuming that
every edge in Emaybe are not connected, while H is the graph you get by assuming that all edges
in Emaybe are connected.
Initially, G is empty and thus not connected, while H is connected. In order not to reveal any
clue to the judge, the contestant should maintain the invariant: G should always be disconnected,
while H should always be connected.
There are several possible ways to maintain the invariant.
4
An O n solution
When asked by the judge whether an edge e u, v is connected, answer ”no” if and only if
e is part of a cycle in H. One can see that this does not change the connectivity of G and H.
To decide whether e forms a circle, one can perform a depth-first search to find out whether
2
there is a path from u to v in V, Eyes Emaybe u, v . This is an O n operation. As there are
2 4
O n edges, the total running time is O n .
In other words, we answer ”yes” if and only if e is a bridge in H.
2
An O n solution
Given a vertex v, let D v be the connected component v belongs to in G. We maintain two
data structures:
2
There can be at most n 1 unions, thus the total time spent on union is O n .
An update of S requires O 1 time for a ”no” response, and O n time for a ”yes” response.
Since the graph G is a tree, we respond ”yes” exactly n 1 times. Thus the time spent on updating
2 2
S is also O n . We thus have an O n algorithm.
An One-Liner O(n2) Algorithm
2
There is a surprising one-line O n algorithm:
#include "game.h"
void initialize(int n)
{
// DO NOTHING!
}
int c[1500];
To understand the algorithm, imagine that we partition the set of all the possible edges into
E1 , E2 , ..., En1 , with Ei i, j ¶i % j. Each Ei has exactly i possible edges. The algorithm above
answers ”yes” to u, v (where u % v) if it is the last edge in Eu that is queried.
To see how it works, consider the last query. Denote the queried edge by e, and the graph
G V, Eyes e. The contestant wins if G is disconnected, while G e is connected.
G e is connected, since it contains n 1 edges, and there is no cycle in G e. One can see
that there is no cycle since, in each Ei , we answer yes to only one edge. Formally, if there
is a cycle C in G e, considering the node u in C with largest id, Eu must has exactly one
edge in G e. But u has two neighbors in C with smaller ids, a contradiction.
#include <bits/stdc++.h>
#include "game.h"
int ctr[2000];
int n;
void initialize(int n)
{
::n=n;
}
return (ctr[v]==v);
}
int read_int()
{
int x;
assert(scanf("%d", &x) == 1);
return x;
}
int main()
{
auto t1 = clock();
int n, u, v;
n = read_int();
auto t2 = clock();
initialize(n);
for (int i = 0; i < n * (n - 1) / 2; i++)
{
u = read_int();
v = read_int();
printf("%d\n", hasEdge(u, v));
}
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
#include "game.h"
#include <bits/stdc++.h>
CAPITOLUL 6. IOI 2014 6.1. GAME 677
int cnt[1500];
int first_time;
void initialize(int n) {}
int c[1500];
int hasEdge(int u, int v) {
return ++c[u > v ? u : v] == (u > v ? u : v);
}
int read_int()
{
int x;
assert(scanf("%d", &x) == 1);
return x;
}
int main()
{
auto t1 = clock();
int n, u, v;
n = read_int();
auto t2 = clock();
initialize(n);
for (int i = 0; i < n * (n - 1) / 2; i++)
{
u = read_int();
v = read_int();
printf("%d\n", hasEdge(u, v));
}
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
*/
#include <cstdio>
#include <cassert>
#include "game.h"
#include<ctime>
#include<iostream>
int d[1500];
void initialize(int){}
int read_int()
{
int x;
assert(scanf("%d", &x) == 1);
return x;
}
int main()
{
auto t1 = clock();
int n, u, v;
n = read_int();
auto t2 = clock();
initialize(n);
for (int i = 0; i < n * (n - 1) / 2; i++)
{
u = read_int();
v = read_int();
printf("%d\n", hasEdge(u, v));
}
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
argc = 4
checker
../tests/03-114.in
game.out
../tests/03-114.out
----------------------
1
Correct
#include <cstdio>
#include <cassert>
#include "game.h"
#include<ctime>
#include<iostream>
int c[1500];
void initialize(int){}
int read_int()
{
int x;
assert(scanf("%d", &x) == 1);
return x;
}
int main()
{
auto t1 = clock();
int n, u, v;
n = read_int();
auto t2 = clock();
initialize(n);
for (int i = 0; i < n * (n - 1) / 2; i++)
{
u = read_int();
v = read_int();
printf("%d\n", hasEdge(u, v));
}
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/03-114.in",
(char*)"game.out",
(char*)"../tests/03-114.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
6.2 Rail
Problema 2 - Rail 100 de puncte
În Taiwan există o cale ferată lungă care leagă ţărmul vestic al insulei de cel estic. Calea ferată
este compusă din m blocuri. Blocurile sunt numerotate consecutiv cu numerele 0, ..., m 1 de la
vest la est. Fiecare bloc este compus dintr-o linie cu sens unic spre vest situată ı̂n nordul blocului,
o linie cu sens unic spre est situată ı̂n sudul blocului, şi opţional o gară ı̂ntre cele două linii.
Există trei tipuri de blocuri. Un bloc de tip C are o gară ı̂n care trenurile intră de pe linia
nordică şi din care ies pe linia sudică, un bloc de tip D are o gară ı̂n care trenurile intră de pe linia
sudică şi din care ies pe linia nordică, iar un bloc de tip gol nu are gară. De exemplu, ı̂n figura
CAPITOLUL 6. IOI 2014 6.2. RAIL 681
de mai jos blocurile 0, 4 şi 6 sunt de tip gol, blocurile 1, 2 şi 3 sunt de tip C, iar blocul 5 este
de tip D. Blocurile sunt conectate ı̂ntre ele pe orizontală. Liniile de cale ferată ale două blocuri
consecutive sunt legate prin ite conectori, ilustraţi prin dreptunghiuri gri ı̂n figura următoare.
Pe calea ferată există gări numerotate de la 0 la n 1. Se cunoaşte că, folosind calea ferată,
putem ajunge din orice gară ı̂n oricare altă gară. De exemplu putem ajunge din gara 0 ı̂n gara
2 plecând din blocul 2, apoi trecând prin blocurile 3 şi 4 pe linia sudică, apoi trecând prin gara
1 din blocul 5, apoi trecând prin blocul 4 pe linia nordică şi ı̂n final ajungând ı̂n gara 2 aflată ı̂n
blocul 3.
Deoarece pot exista mai multe rute posibile, distanţa de la o gară la alta se defineşte ca fiind
numărul minim de conectori prin care trece un traseu valid. De exemplu, distanţa minimă de la
gara 0 la gara 2 este prin blocurile 2-3-4-5-4-3 şi trece prin 5 conectori, deci distanţa este 5.
Un sistem computerizat monitorizează calea ferată. Din nefericire, după o pană de curent
sistemul nu mai cunoaşte unde se află gările şi ı̂n ce tip de bloc se află acestea. Singurul indiciu
rămas ı̂n sistem este numărul blocului ı̂n care se află gara 0, care se află mereu ı̂ntr-un bloc de tip
C. Din fericire, sistemul poate ı̂ntreba care este distanţa de la orice gară la oricare altă gară. De
exemplu, sistemul poate pune următoarea ı̂ntrebare: ’Care este distanţa de la gara 0 la gara 2?’,
primind ca răspuns 5.
Cerinţă
Trebuie să implementaţi funcţia findLocation care determină pentru fiecare gară numărul
şi tipul blocului ı̂n care se află.
findLocation(n, first, location, stype)
n: numărul de staţii.
first: numărul blocului care conţine gara 0.
location: un tablou unidimensional de dimensiune n; la finalul execuţiei acestei funcţii
numărul blocului ı̂n care se află gara i trebuie să se afle ı̂n celula location[i].
stype: un tablou unidimensional de dimensiune n; la finalul execuţiei acestei funcţii tipul
blocului ı̂n care se află gara i trebuie să se afle ı̂n celula stype[i]: 1 pentru tipul C sau 2
pentru tipul D.
Puteţi apela funcţia getDistance pentru a vă ajuta să determinaţi poziţiile şi tipurile
blocurilor ı̂n care se află gările.
getDistance(i, j) returnează distanţa de la gara i la gara j. getDistance(i, i)
va returna 0. getDistance(i, j) va returna -1 dacă i sau j se află ı̂n afara intervalului
0 & i, j & n 1.
Subprobleme
Pentru toate subproblemele (subtask-urile) numărul de blocuri m nu depăşeşte 1,000,000. ı̂n
unele dintre subprobleme numărul de apeluri ale funcţiei getDistance este limitat. Această
limită variază de la subproblemă la subproblemă. Programul vostru va primi ’wrong answer’ dacă
depăşeşte această limită.
subproblemă puncte n apeluri către note
getDistance
1 8 1 & n & 100 nelimitat Toate gările cu excepţia lui 0
sunt ı̂n blocuri de tip D.
2 22 1 & n & 100 nelimitat Toate gările situate ı̂n estul gării
0 se află ı̂n blocuri de tip D, şi
toate gările situate la vestul gării
0 se află ı̂n blocuri de tip C.
3 26 1 & n & 5, 000 n n 1©2 fără restricţii adiţionale
4 44 1 & n & 5, 000 3 n 1 fără restricţii adiţionale
CAPITOLUL 6. IOI 2014 6.2. RAIL 682
Detalii de implementare
Voi trebuie să ı̂ncărcaţi exact un fişier, denumit rail.c, rail.cpp sau rail.pas. Acest fişier imple-
mentează funcţia findLocation aşa cum este descrisă mai sus, utilizând unul din următoarele
antete. Pentru programele C/C++ trebuie să includeţi şi header-ul rail.h.
pentru programele C/C++
Way : Ad Hoc
Query complexity: 3 N 1
Time complexity : O N log N
** This problem can be solved by the following steps :
First, we know that station 0 is C type, and its location. We can query all the other stations’
distances from station 0, we call this: dis0i
Second, we sort all the dis0i, and obviously, the station x with the shortest distance
dis0x must be the first D type location after station 0.
Third, we process each station one by one according to their shortest distance with station 0
(that is, the order obtained in second step). For each station processed, we determine its type
and location immediately as follows:
3.1 First, we maintain the information (location,id) of the leftmost C type and the rightmost
D type as the algorithm proceeds.
3.2 To process the current station k, we use two queries, query(k,leftmost C type) as disk L,
query(k, rightmost D type) as disk R. And we also have dis0k . By some observations, we
CAPITOLUL 6. IOI 2014 6.2. RAIL 683
know that either disk L or disk R is achieved with a ’direct’ route (without moving forth
and back).
For example, we have only 4 cases to consider :
By careful analysis (some if/else conditions), we can get the answer. Sometimes, we may need
extra information to resolve the four cases, where we can check with dis0k .
Take case (a) for example :
the location of k might be L disk L, Then use this location, we need to check if disk R
is reasonable or not.
a.1
( ( ) )
L p k R
There might be some p(type C) between L and k, So the disk R is dispR dispk ,
we need to check whether p exists or not. If p doesn’t exist, then case (a) might be wrong, then
try cases (b),(c), and (d) until we find the answer.
#include "rail.h"
#include <bits/stdc++.h>
void now_I_want_to_getLR()
{
int now = stations[S-1].index,i;
for(i=S-2;i>=0;i--)
{
stations[i].R = now;
if(stations[i].type==2) now = stations[i].index;
}
now = stations[0].index;
for(i=1;i<S;i++)
{
stations[i].L = now;
if(stations[i].type==1) now = stations[i].index;
}
}
int ret = 0;
if(stations[x].type==1 && stations[y].type==1)
{
ret = stations[stations[y].R].location-
stations[x].location+
stations[stations[y].R].location-
stations[y].location;
}
else
if(stations[x].type==1 && stations[y].type==2)
{
ret = stations[y].location-stations[x].location;
}
else
if(stations[x].type==2 && stations[y].type==2)
{
ret = stations[x].location-
stations[stations[x].L].location+
stations[y].location-
stations[stations[x].L].location;
CAPITOLUL 6. IOI 2014 6.2. RAIL 686
}
else
if(stations[x].type==2 && stations[y].type==1)
{
ret = stations[x].location-
stations[stations[x].L].location+
stations[stations[y].R].location-
stations[stations[x].L].location+
stations[stations[y].R].location-
stations[y].location;
}
return ret;
}
void getInput()
{
int g;
g = scanf("%d",&SUBTASK);
g = scanf("%d",&S);
int s;
for (s = 0; s < S; s++)
{
int type, location;
g = scanf(" %d %d",&type,&location);
stations[s].index = s;
stations[s].location = location;
stations[s].type = type;
stations[s].L = -1;
stations[s].R = -1;
}
int serverGetStationNumber()
{
return S;
}
int serverGetSubtaskNumber()
{
return SUBTASK;
}
int serverGetFirstStationLocation()
{
return stations[0].location;
}
int main()
{
auto t1 = clock();
int i;
getInput();
cnt = 0;
int location[10005];
int type[10005];
int ok = 1;
auto t2 = clock();
auto t3 = clock();
if(ok==0) printf("Incorrect\n\n");
else printf("Correct\n\n");
fclose(stdout);
auto t4 = clock();
return 0;
}
// -------------- end grader ----------------------
/*
Correct
t2-t1 = 0.031
t3-t2 = 0.015
t4-t3 = 0.016
#include <bits/stdc++.h>
#define x first
#define y second
#define ll long long
#define pi pair<int,int>
#define pl pair<ll,ll>
#define pd pair<double,double>
#define ld long double
#define pld pair<ld,ld>
#define lg length()
#define sz size()
#define vi vector<int>
#define vl vector<ll>
#define vp vector<pi>
#define vpl vector<pl>
#define pb push_back
#define INF 1000000005
#define LINF 1000000000000000005
#ifdef LOCAL_DEFINE
mt19937 rng(69);
#else
seed_seq seq
{
(uint64_t) chrono::
duration_cast<chrono::
nanoseconds>(chrono::
high_resolution_clock::
now().time_since_epoch()).count(),
//(uint64_t) __builtin_ia32_rdtsc(),
//(uint64_t) (uintptr_t) make_unique<char>().get()
};
mt19937 rng(seq);
#endif
CAPITOLUL 6. IOI 2014 6.2. RAIL 688
#include "rail.h"
sort(l.begin(),l.end());
u.pb(p[z]);
int f=z;
for(pi i : l)
{
int d=getDistance(i.y,f);
p[i.y]=p[f]+d;
if(p[i.y]>=p[z])
{
p[i.y]=p[y]-b[i.y];
t[i.y]=1;
u.pb(p[i.y]);
f=i.y;
}
int c=*(lower_bound(u.begin(),u.end(),p[i.y],greater<int>()));
if(b[i.y]==p[i.y]+p[y]-2*c && p[i.y]!=c)
{
t[i.y]=2;
}
else
{
p[i.y]=p[y]-b[i.y];
t[i.y]=1;
u.pb(p[i.y]);
f=i.y;
}
}
sort(r.begin(),r.end());
CAPITOLUL 6. IOI 2014 6.2. RAIL 689
v.pb(p[y]);
f=y;
for(pi i : r)
{
int d=getDistance(i.y,f);
p[i.y]=p[f]-d;
if(p[i.y]<=p[y])
{
p[i.y]=p[z]+a[i.y];
t[i.y]=2;
v.pb(p[i.y]);
f=i.y;
}
int c=*(lower_bound(v.begin(),v.end(),p[i.y]));
if(a[i.y]==2*c-p[i.y]-p[z] && p[i.y]!=c)
{
t[i.y]=1;
}
else
{
p[i.y]=p[z]+a[i.y];
t[i.y]=2;
v.pb(p[i.y]);
f=i.y;
}
}
}
void now_I_want_to_getLR()
{
int now = stations[S-1].index,i;
for(i=S-2;i>=0;i--)
{
stations[i].R = now;
if(stations[i].type==2) now = stations[i].index;
}
now = stations[0].index;
for(i=1;i<S;i++)
{
stations[i].L = now;
if(stations[i].type==1) now = stations[i].index;
}
}
cnt++;
if(x==y) return 0;
if(x<0 || x>=S || y<0 || y>=S) return -1;
if(stations[x].location > stations[y].location)
{
int tmp = x;
x = y;
y = tmp;
}
int ret = 0;
if(stations[x].type==1 && stations[y].type==1)
{
ret = stations[stations[y].R].location-
stations[x].location+
stations[stations[y].R].location-
stations[y].location;
}
else
if(stations[x].type==1 && stations[y].type==2)
{
ret = stations[y].location-stations[x].location;
}
else
if(stations[x].type==2 && stations[y].type==2)
{
ret = stations[x].location-
stations[stations[x].L].location+
stations[y].location-
stations[stations[x].L].location;
}
else
if(stations[x].type==2 && stations[y].type==1)
{
ret = stations[x].location-
stations[stations[x].L].location+
stations[stations[y].R].location-
stations[stations[x].L].location+
stations[stations[y].R].location-
stations[y].location;
}
return ret;
}
void getInput()
{
int g;
g = scanf("%d",&SUBTASK);
g = scanf("%d",&S);
int s;
for (s = 0; s < S; s++)
{
int type, location;
g = scanf(" %d %d",&type,&location);
stations[s].index = s;
stations[s].location = location;
stations[s].type = type;
stations[s].L = -1;
stations[s].R = -1;
}
int serverGetStationNumber()
{
return S;
}
int serverGetSubtaskNumber()
{
return SUBTASK;
CAPITOLUL 6. IOI 2014 6.2. RAIL 691
int serverGetFirstStationLocation()
{
return stations[0].location;
}
int main()
{
auto t1 = clock();
int i;
getInput();
cnt = 0;
int location[10005];
int type[10005];
int ok = 1;
auto t2 = clock();
auto t3 = clock();
if(ok==0) printf("Incorrect\n\n");
else printf("Correct\n\n");
fclose(stdout);
auto t4 = clock();
return 0;
}
// -------------- end grader ----------------------
/*
Correct
t2-t1 = 0.031
t3-t2 = 0.015
t4-t3 = 0
#include "rail.h"
#include <bits/stdc++.h>
using namespace std;
sort(a, a+n);
if(tˆ2)
{
p[a[i][1]]=p[l]+dl;
s[a[i][1]]=2;
if(p[a[i][1]]>p[r])
r=a[i][1];
}
else
{
p[a[i][1]]=p[r]-dr;
s[a[i][1]]=1;
if(p[a[i][1]]<p[l])
l=a[i][1];
}
mp[p[a[i][1]]]=a[i][1];
}
}
void now_I_want_to_getLR()
{
int now = stations[S-1].index,i;
for(i=S-2;i>=0;i--)
{
stations[i].R = now;
CAPITOLUL 6. IOI 2014 6.2. RAIL 693
int ret = 0;
if(stations[x].type==1 && stations[y].type==1)
{
ret = stations[stations[y].R].location-
stations[x].location+
stations[stations[y].R].location-
stations[y].location;
}
else
if(stations[x].type==1 && stations[y].type==2)
{
ret = stations[y].location-stations[x].location;
}
else
if(stations[x].type==2 && stations[y].type==2)
{
ret = stations[x].location-
stations[stations[x].L].location+
stations[y].location-
stations[stations[x].L].location;
}
else
if(stations[x].type==2 && stations[y].type==1)
{
ret = stations[x].location-
stations[stations[x].L].location+
stations[stations[y].R].location-
stations[stations[x].L].location+
stations[stations[y].R].location-
stations[y].location;
}
return ret;
}
void getInput()
{
int g;
g = scanf("%d",&SUBTASK);
g = scanf("%d",&S);
int s;
for (s = 0; s < S; s++)
{
int type, location;
g = scanf(" %d %d",&type,&location);
stations[s].index = s;
stations[s].location = location;
stations[s].type = type;
stations[s].L = -1;
stations[s].R = -1;
}
now_I_want_to_getLR();
qsort(stations, S, sizeof(STATION), cmp_fun_2);
}
int serverGetStationNumber()
{
return S;
}
int serverGetSubtaskNumber()
{
return SUBTASK;
}
int serverGetFirstStationLocation()
{
return stations[0].location;
}
int main()
{
auto t1 = clock();
int i;
getInput();
cnt = 0;
int location[10005];
int type[10005];
int ok = 1;
auto t2 = clock();
auto t3 = clock();
if(ok==0) printf("Incorrect\n\n");
else printf("Correct\n\n");
fclose(stdout);
auto t4 = clock();
return 0;
}
// -------------- end grader ----------------------
/*
Correct
t2-t1 = 0.031
t3-t2 = 0.031
t4-t3 = 0
// https://oj.uz/submission/139096 87 ms 888 KB
#include "rail.h"
#include <bits/stdc++.h>
sort(v.begin(), v.end());
l[v[0].second] = first + v[0].first;
t[v[0].second] = 2;
set <int> C, D;
C.insert(l[0]); D.insert(l[v[0].second]);
int L = 0, R = v[0].second;
for (int i = 1; i < v.size(); i++)
{
int id = v[i].second;
int x = getDistance(id, L), y = getDistance(id, R);
int lcan = l[L] + x, rcan = l[R] - y, res;
auto it = --C.upper_bound(lcan);
if (y == lcan - *it + l[R] - *it)
{
res = 1;
}
else
{
auto it = D.upper_bound(rcan);
if (it != D.end() && x == *it - rcan + *it - l[L])
{
res = 0;
}
else
{
if (v[i].first == 2 * l[v[0].second] - first - rcan) res = 0;
else res = 1;
}
}
if (res == 1)
{
l[id] = lcan;
t[id] = 2;
D.insert(l[id]);
if (l[R] < l[id]) R = id;
}
else
{
l[id] = rcan;
t[id] = 1;
C.insert(l[id]);
if (l[L] > l[id]) L = id;
}
}
}
void now_I_want_to_getLR()
{
int now = stations[S-1].index,i;
for(i=S-2;i>=0;i--)
{
stations[i].R = now;
if(stations[i].type==2) now = stations[i].index;
}
now = stations[0].index;
for(i=1;i<S;i++)
{
stations[i].L = now;
if(stations[i].type==1) now = stations[i].index;
}
}
int ret = 0;
if(stations[x].type==1 && stations[y].type==1)
{
ret = stations[stations[y].R].location-
stations[x].location+
stations[stations[y].R].location-
stations[y].location;
}
else
if(stations[x].type==1 && stations[y].type==2)
{
ret = stations[y].location-stations[x].location;
}
else
if(stations[x].type==2 && stations[y].type==2)
{
ret = stations[x].location-
stations[stations[x].L].location+
stations[y].location-
stations[stations[x].L].location;
}
else
if(stations[x].type==2 && stations[y].type==1)
{
ret = stations[x].location-
stations[stations[x].L].location+
stations[stations[y].R].location-
CAPITOLUL 6. IOI 2014 6.2. RAIL 697
stations[stations[x].L].location+
stations[stations[y].R].location-
stations[y].location;
}
return ret;
}
void getInput()
{
int g;
g = scanf("%d",&SUBTASK);
g = scanf("%d",&S);
int s;
for (s = 0; s < S; s++)
{
int type, location;
g = scanf(" %d %d",&type,&location);
stations[s].index = s;
stations[s].location = location;
stations[s].type = type;
stations[s].L = -1;
stations[s].R = -1;
}
int serverGetStationNumber()
{
return S;
}
int serverGetSubtaskNumber()
{
return SUBTASK;
}
int serverGetFirstStationLocation()
{
return stations[0].location;
}
int main()
{
auto t1 = clock();
int i;
getInput();
cnt = 0;
int location[10005];
int type[10005];
int ok = 1;
auto t2 = clock();
auto t3 = clock();
if(ok==0) printf("Incorrect\n\n");
else printf("Correct\n\n");
CAPITOLUL 6. IOI 2014 6.2. RAIL 698
fclose(stdout);
auto t4 = clock();
return 0;
}
// -------------- end grader ----------------------
/*
Correct
t2-t1 = 0.031
t3-t2 = 0.015
t4-t3 = 0.016
#include "rail.h"
#include<bits/stdc++.h>
if(isC)
{
l[idx]=rgcan;
t[idx]=1;
C.insert(l[idx]);
if(l[L]>l[idx]) L=idx;
}
else
{
l[idx]=lfcan;
t[idx]=2;
D.insert(l[idx]);
if(l[R]<l[idx]) R=idx;
}
}
}
void now_I_want_to_getLR()
{
int now = stations[S-1].index,i;
for(i=S-2;i>=0;i--)
{
stations[i].R = now;
if(stations[i].type==2) now = stations[i].index;
}
now = stations[0].index;
for(i=1;i<S;i++)
{
stations[i].L = now;
if(stations[i].type==1) now = stations[i].index;
}
}
int ret = 0;
if(stations[x].type==1 && stations[y].type==1)
{
ret = stations[stations[y].R].location-
stations[x].location+
stations[stations[y].R].location-
stations[y].location;
}
else
if(stations[x].type==1 && stations[y].type==2)
{
ret = stations[y].location-stations[x].location;
}
else
if(stations[x].type==2 && stations[y].type==2)
{
ret = stations[x].location-
stations[stations[x].L].location+
stations[y].location-
stations[stations[x].L].location;
}
else
if(stations[x].type==2 && stations[y].type==1)
{
ret = stations[x].location-
stations[stations[x].L].location+
stations[stations[y].R].location-
stations[stations[x].L].location+
stations[stations[y].R].location-
stations[y].location;
}
return ret;
}
void getInput()
{
int g;
g = scanf("%d",&SUBTASK);
g = scanf("%d",&S);
int s;
for (s = 0; s < S; s++)
{
int type, location;
g = scanf(" %d %d",&type,&location);
stations[s].index = s;
stations[s].location = location;
stations[s].type = type;
stations[s].L = -1;
stations[s].R = -1;
}
int serverGetStationNumber()
{
return S;
}
int serverGetSubtaskNumber()
{
return SUBTASK;
}
int serverGetFirstStationLocation()
{
return stations[0].location;
}
int main()
{
auto t1 = clock();
CAPITOLUL 6. IOI 2014 6.3. WALL 701
int i;
getInput();
cnt = 0;
int location[10005];
int type[10005];
int ok = 1;
auto t2 = clock();
auto t3 = clock();
if(ok==0) printf("Incorrect\n\n");
else printf("Correct\n\n");
fclose(stdout);
auto t4 = clock();
return 0;
}
// -------------- end grader ----------------------
/*
Correct
t2-t1 = 0.015
t3-t2 = 0.016
t4-t3 = 0
6.3 Wall
Problema 3 - Wall 100 de puncte
Jian-Jia construieşte un perete din cărămizi de dimensiuni egale. Peretele este format din n
coloane de cărămizi, numerotate de la 0 la n 1 de la stânga la dreapta. Coloanele pot avea
ı̂nălţimi diferite. ı̂nălţimea unei coloane este numărul de cărămizi care o constituie.
Jian-Jia construieşte peretele după cum urmează: iniţial toate coloanele nu conţin nici o
cărămidă.
CAPITOLUL 6. IOI 2014 6.3. WALL 702
Apoi, Jian-Jia parcurge k faze adăugând sau scăzând cărămizi. Procesul de construire a
peretelui se ı̂ncheie atunci când toate cele k faze sunt parcurse. La fiecare fază lui Jian-Jia ı̂i sunt
date un interval de coloane consecutive şi o ı̂nălţime h. El aplică apoi următoarea procedură:
ı̂ntr-o fază de adăugare, Jian-Jia adaugă cărămizi la acele coloane din intervalul dat care au
mai puţin de h cărămizi, astfel ı̂ncât să ajungă la ı̂nălţimea de exact h cărămizi. Coloanele
care au h sau mai multe cărămizi rămân neschimbate.
ı̂ntr-o fază de scădere, Jian-Jia scoate cărămizi din acele coloane din intervalul dat care au
mai mult de h cărămizi, astfel ı̂ncât ele să ajungă la ı̂nălţimea de exact h cărămizi. Coloanele
care au h sau mai puţine cărămizi rămân neschimbate.
Sarcina voastră este să determinaţi forma finală a peretelui.
Exemplu
Să presupunem că avem 10 coloane din cărămizi şi 6 faze de construire a peretelui. ı̂n tabelul
de mai jos sunt incluse toate intervalele. Formele peretelui după fiecare fază sunt arătate mai jos.
faza tipul intervalul ı̂nălţimea
0 adăugare coloanele de la 1 la 8 4
1 scădere coloanele de la 4 la 9 1
2 scădere coloanele de la 3 la 6 5
3 adăugare coloanele de la 0 la 5 3
4 adăugare coloana 2 5
5 scădere coloanele de la 6 la 7 0
După faza 0 fiecare coloană de la 1 la 8 va avea câte 4 cărămizi,
deoarece toate coloanele iniţial sunt goale.
Coloanele 0 şi 9 rămân ı̂n continuare goale.
În faza 1, cărămizile sunt scoase de la coloanele de la 4 la 8
până când fiecare din coloane va avea câte o cărămidă, iar coloana
9 rămâne ı̂n continuare goală.
Coloanele de la 0 la 3, care sunt ı̂n afara intervalului, rămân
neschimbate.
Faza 2 nu produce nici o schimbare, deoarece coloanele de la 3
la 6 nu au mai mult de 5 cărămizi.
După faza 3, numărul de cărămizi ı̂n coloanele 0, 4, şi 5 creşte
la 3.
După faza 4, vom avea 5 cărămizi ı̂n coloana 2.
Faza 5 elimină toate cărămizile din coloanele 6 şi 7.
Cerinţă
Având descrierile celor k faze, vă rugăm să calculaţi numărul
de cărămizi din fiecare coloană după parcurgerea tuturor fazelor.
Trebuie să implementaţi funcţia buildWall.
buildWall(n, k, op, left, right, height, finalHeight)
– n: numărul de coloane care formează peretele.
– k: numărul de faze.
– op: tablou unidimensional de lungime k; opi este tipul fazei i: 1 pentru faza de
adăugare şi 2 pentru faza de scădere, pentru 0 & i & k 1.
– lef t şi right: tablouri unidimensionale de lungime k; intervalul de coloane ı̂n faza
i ı̂ncepe cu coloana lef ti şi se termină cu coloana righti (inclusiv ambele capete
lef ti şi righti), pentru 0 & i & k 1. Se presupune că ı̂ntodeauna lef ti & righti.
– height: tablou unidimensional de lungime k; heighti este parametrul de ı̂nălţime
pentru faza i, pentru 0 & i & k 1.
– f inalHeight: tablou unidimensional de lungime n; veţi returna ı̂n acesta rezultatele
obţinute plasând numărul final de cărămizi din coloana i ı̂n f inalHeighti, pentru
0 & i & n 1.
Subprobleme
Pentru toate subproblemele (subtask-urile) parametrii de ı̂nălţime din toate fazele sunt numere
ı̂ntregi nenegative mai mici sau egale cu 100,000.
CAPITOLUL 6. IOI 2014 6.3. WALL 703
Detalii de implementare
Trebuie să ı̂ncărcaţi exact un fişier, numit wall.c, wall.cpp sau wall.pas. ı̂n acest fişier se va
implementa funcţia descrisă mai sus, utilizând antetul de mai jos. De asemenea veţi include un
fişier header wall.h pentru programele C/C++.
pentru programele C/C++
Overview
We’ll simplify the notion of the problem as follow:
Initially we have an array of length n where the value at each index is 0, and we are to process
k queries in order. We will denote the value at index x as Ax.
There are two kinds of operations:
M inimize l, r, t: For all indices x between l, r, the value become min Ax, t
M aximize l, r, t: For all indices x between l, r, the value become max Ax, t
class Node
{
Node *left, *right; // children nodes
int from, to; // corresponding interval [from, to]
int opmin, opmax; // min/max operation applied on interval
};
A single round of minimize operation runs in O log n, likewise for maximize operations. Note
that in the snippet above, we use the well-known lazy-update technique to maintain the operations
applied at one position. i.e. the message is passed down to children nodes only when necessary,
that is, when new operations are imposed on only part of the segment, so previous operations
should be passed down first.
After all queries are processed, we simply scan each position and check (with log n complexity)
the operations applied on it, obtaining the final value at the position.
The overall running time is therefore O n k log n.
It is possible to optimize further so that the overall running time become O n k log k , it is
however entirely not necessary for this problem.
CAPITOLUL 6. IOI 2014 6.3. WALL 705
#include "wall.h"
#include <bits/stdc++.h>
#define oo 2000000000
const int N = 2000010;
pair<int,int> seg[4 * N];
int n;
int k;
int i, j;
int status = 0;
auto t2 = clock();
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
argc = 4
checker
../tests/04-030.in
wall.out
../tests/04-030.out
----------------------
1
Correct
93939
#include "wall.h"
#include <bits/stdc++.h>
#define left_son (node<<1)
#define right_son ((node<<1)|1)
#define mid ((st+dr)>>1)
class SegTree
{
int a[Nmax<<2], b[Nmax<<2];
public:
void update(int node, int st, int dr, int L, int R, int A, int B)
{
if(L <= st && dr <= R)
{
combine(node, A, B);
return;
}
propag(node);
int main()
{
auto t1 = clock();
int n;
int k;
int i, j;
int status = 0;
auto t2 = clock();
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
argc = 4
checker
../tests/04-030.in
wall.out
../tests/04-030.out
----------------------
1
Correct
#include "wall.h"
#include <bits/stdc++.h>
#define adds 1
#define remov 2
#define left(n) (n<<1)
#define right(n) (n<<1|1)
struct segtree
{
int mx[szt], mn[szt];
segtree()
{
memset(mx, inf, sizeof(mx));
}
void finish()
{
for(int i = 1; i < last; i++)unlazy(i);
}
};
segtree tree;
tree.finish();
int cnt = 0;
for(int i = last; i < last + n; i++)
{
ans[cnt++] = min(tree.mx[i], tree.mn[i]);
}
CAPITOLUL 6. IOI 2014 6.3. WALL 710
return;
}
int n;
int k;
int i, j;
int status = 0;
auto t2 = clock();
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
argc = 4
checker
../tests/04-030.in
wall.out
../tests/04-030.out
----------------------
1
Correct
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "wall.h"
#include<ctime>
#include<iostream>
void push(int v)
{
change(v << 1|0, mn[v], mx[v]);
change(v << 1|1, mn[v], mx[v]);
mx[v] = 0; mn[v] = inf;
}
void buildWall(int n, int q, int op[], int l[], int r[], int h[], int ans[])
{
for (int i = 0; i < N; ++i) mn[i] = inf, mx[i] = 0;
for (int i = 0; i < q; ++i)
{
u = 0; d = inf;
lo = l[i]; hi = r[i] + 1;
op[i] != 1 ? d = h[i]: u = h[i];
update(1, 0, n);
}
final(ans, 1, 0, n);
}
int n;
int k;
int i, j;
int status = 0;
CAPITOLUL 6. IOI 2014 6.3. WALL 712
auto t2 = clock();
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
argc = 4
checker
../tests/04-030.in
wall.out
../tests/04-030.out
----------------------
1
Correct
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
CAPITOLUL 6. IOI 2014 6.4. FRIEND 713
(char*)"../tests/04-030.in",
(char*)"wall.out",
(char*)"../tests/04-030.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
6.4 Friend
Problema 4 - Friend 100 de puncte
După ce construim reţeaua, dorim să selectăm un eşantion pentru un sondaj, ceea ce pre-
supune alegerea unui grup de persoane din reţea. Deoarece prietenii de obicei au interese similare,
eşantionul trebuie să nu includă nicio pereche de prieteni. Fiecare persoană are asociată o ı̂ncredere
de sondaj, exprimată printr-un număr ı̂ntreg pozitiv. Vom ı̂ncerca să determinăm un eşantion de
ı̂ncredere totală maximă (prin ı̂ncredere totală a unui eşantion se ı̂nţelege suma ı̂ncrederilor aso-
ciate presoanelor care ı̂l formează).
Exemplu
Iniţial reţeaua este formată doar din persoana 0. Gazda etapei 1 (persoana 0) invită persoana
1 prin protocolul IAmY ourF riend, astfel ei devin prieteni.
Gazda etapei 2 (din nou persoana 0) invită persoana 2 prin protocolul
M yF riendsAreY ourF riends, ceea ce face ca persoana 1 (unicul prieten al gazdei) să devină
prieten al persoanei 2 (fără ca persoana 0 să devină prieten cu 2).
Gazda etapei 3 (persoana 1) adaugă persoana 3 prin protocolul WeAreYourFriends care face
persoana 3 prieten cu persoana 1 (gazda) dar şi cu persoanele 0 şi 2 (prietenii gazdei).
CAPITOLUL 6. IOI 2014 6.4. FRIEND 714
Etapele 4 şi 5 sunt de asemenea prezentate ı̂n tabelul de mai sus. Reţeaua finală este prezen-
tată ı̂n figura următoare, ı̂n care numerele ı̂nscrise ı̂n cercuri reprezintă indicii membrilor reţelei,
iar numerele alăturate cercurilor reprezintă ı̂ncrederea de sondaj asociată persoanelor respective.
Eşantionul care constă din persoanele 3 şi 5 are ı̂ncrederea totală egală cu 20 + 15 = 35, care este
ı̂ncrederea totală maximă posibilă.
Cerinţă
Fiind dată descrierea fiecărei etape şi valoarea ı̂ncrederii asociate fiecărei persoane, găsiţi un
eşantion cu ı̂ncredere totală maximă. Trebuie să implementaţi funcţia findSample.
findSample(n, confidence, host, protocol)
– n: numărul de persoane.
– conf idence: tablou unidimensional de lungime n; conf idencei reprezintă valoarea
ı̂ncrederii asociate persoanei i.
– host: tablou unidimensional de lungime n; hosti reprezintă gazda etapei i.
– protocol: tablou unidimensional de lungime n; protocoli reprezintă codul pro-
tocolului folosit la etapa i (0 $ i $ n): 0 pentru IAmY ourF riend, 1 pentru
M yF riendsAreY ourF riends, şi 2 pentru W eAreY ourF riends.
– Deoarece nu există gazdă la etapa 0, host[0] şi protocol[0] sunt nedefinite şi nu trebuie
să fie accesate de programul vostru. Funcţia trebuie să returneze ı̂ncrederea totală
maximă a unui eşantion.
Subprobleme
Unele subprobleme (subtask-uri) vor folosi doar o parte din protocoale, aşa cum se vede ı̂n
tabelul ce urmează.
Detalii de implementare
Trebuie să ı̂ncărcaţi exact un fişier, numit friend.c, friend.cpp sau friend.pas. Fişierul trebuie să
conţină implementarea subprogramului descris mai sus, utilizând următorul antet. De asemenea
trebuie să includeţi fişierul header friend.h pentru implementările C/C++.
pentru programele C/C++
6 solutions to 6 subtasks
Solution1 Solution2 Solution3 Solution4 Solution5 Solution6
Subtask1 AC WA WA WA WA AC
Subtask2 TLE AC WA WA WA AC
Subtask3 TLE WA AC WA WA AC
Subtask4 TLE WA WA AC WA AC
Subtask5 TLE WA WA WA AC AC
Subtask6 TLE WA WA WA WA AC
Table 1-1: The result of each solution applying to each subtask.
Note: AC=Accepted, WA=Wrong Answer, TLE=Time Limit Exceeded.
Solution1
In subtask1, N is at most 10. So just apply backtracking for every person - to chose or not to
N
chose. The complexity is O N 2 , Accepted.
The sizes of N in other subtasks are too large to apply this solution, resulting in Time Limit
Exceeded with this complexity.
Solution2
In subtask2, there’re all ’MyFriendsAreYourFriends’ relations, forming a graph with no edge.
That is equivalent to chose all persons, with complexity of O N .
For other subtasks, there’re not only this kind of relations, so this solution does not work and
will result in Wrong Answer.
Solution3
In subtask3, there’re all ’WeAreYourFriends’ relations, forming a complete graph. Since every
pair of two persons is connected by an edge, the answer to this problem is equivalent to choose
the maximum confidence among all people, with complexity of O N .
For other subtasks, there’re not only this kind of relations, so this solution does not work and
will result in Wrong Answer.
Solution4
In subtask4, all relations are ’IamYourFriend’, forming a tree. So we apply the DP-in-tree
method.
Define dpij as the maximum sum for the i-th node with status j, where j 0 stands for
not choosing this node and j 1 stands for choosing this node. Then:
– dpij max dpk 0, dpk 1, for j 0 and for all k, where k is i’s child.
– dpij dpk 0, for j 1 and for all k, where k is i’s child.
The final answer is max dproot0; dproot1, where root stands for the root of this tree.
For other subtasks, there’re not only ’IamYourFriend’ relations, so this solution will not work
and will result in Wrong Answer.
Solution5
Since there’re only ’MyFriendsAreYourFriends’ and ’IamYourFriend’ relations, the resulting
graph contains no odd cycle. That is, we obtain a bipartite graph.
With all confidence equals to 1, the problem becomes finding maximum independent set in a
bipartite graph. As we know, a set is independent if and only if its complement is a vertex cover.
If the complement of independent set is not a vertex cover, then there exists at least one edge
with end points u and v, which is included in the independent set, conflicting with the definition
of independent set. Trivially, a maximum independent set is the complement of minimum vertex
cover.
According to Konig’s theorem[1], in any bipartite graph, the number of edges in a maximum
matching is equal to the number of vertices in a minimum vertex cover. Thus, we can apply
the augmenting path algorithm toÓ find out maximum cardinality matching in a bipartite graph,
with complexity of O N E or O N E , depending on different implementations, where E is the
number of edges.
Let k be the result of maximum cardinality bipartite matching, the answer to this problem
equals to N k, since maximum independent set is the complement of minimum vertex cover.
As for partitioning the graph into bipartite, we apply dfs to mark out the odd points and the
even points, and then put all odd points one side, even points the other side.
In subtask 2 and 4, the relations are ’MyFriendsAreYourFriends’ and ’IamYourFriend’. How-
ever, the confidence value in those two subtasks are not all equals to 1. As a result, this solution
can only solve subtask5 correctly, and Wrong Answer for other subtasks.
Solution6
By using Greedy method to eliminate each person in the reverse order of building process, we
will finally get the p; q pair for the last person. The answer will be max p; q of the last person.
Here we briefly introduce this method. Initially, we maintain two values p x and q x for
each person x, where p x conf idencex and q x 0. Physically, p stands for ’choose’ and q
stands for ’not choose’.
¬ ¬
To simplify the notation, we call p for p x, q for q x, p for p y , q for q y .
(1) WeAreYourFriends
¬
(a) Choose x p p q .
¬
(b) Choose y p p q.
¬
(c) Choose both: p p p .
¬ ¬ ¬ ¬ ¬
(d) Neither: q q q . So p max p q ; p q; p p , q qq.
(3) IamYourFriend
#include<ctime>
#include<iostream>
#include "friend.h"
#include <algorithm>
int a[100010],b[100010];
int findSample(int n,int *c,int *h,int *p)
{
int i;
for(i=0;i<n;++i)a[i]=c[i];
for(;--i;)
{
if(!p[i])
{
a[h[i]]+=b[i];
b[h[i]]+=max(a[i],b[i]);
}
else
if(p[i]==1)
{
a[h[i]]=max(a[h[i]]+max(a[i],b[i]),b[h[i]]+a[i]);
b[h[i]]+=b[i];
}
else
{
a[h[i]]=max(a[h[i]]+b[i],b[h[i]]+a[i]);
b[h[i]]+=b[i];
}
}
CAPITOLUL 6. IOI 2014 6.4. FRIEND 718
return max(a[0],b[0]);
}
// Confidence
int confidence[__MAXSIZE__];
// Host
int host[__MAXSIZE__];
// Protocol
int protocol[__MAXSIZE__];
// Main
int main(void)
{
auto t1 = clock();
int n,i;
// Number of people
assert(scanf("%d",&n)==1);
// Confidence
for(i=0;i<n;i++)
assert(scanf("%d",&confidence[i])==1);
auto t2 = clock();
// Answer
printf("%d\n",findSample(n,confidence,host,protocol));
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
rgc = 4
checker
../tests/06-015.in
friend.out
../tests/06-015.out
----------------------
1
Correct
#include <cstdio>
#include <cassert>
#include<ctime>
#include<iostream>
#include "friend.h"
#define max(a, b) ((a) > (b) ? (a) : (b))
// Confidence
int confidence[__MAXSIZE__];
// Host
int host[__MAXSIZE__];
// Protocol
int protocol[__MAXSIZE__];
// Main
int main(void)
{
auto t1 = clock();
int n,i;
// Number of people
assert(scanf("%d",&n)==1);
// Confidence
for(i=0;i<n;i++)
assert(scanf("%d",&confidence[i])==1);
auto t2 = clock();
// Answer
printf("%d\n",findSample(n,confidence,host,protocol));
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
argc = 4
checker
../tests/06-015.in
friend.out
../tests/06-015.out
----------------------
1
Correct
//#include <cstdio>
//#include <cassert>
#include <bits/stdc++.h>
using namespace std;
int findSample(int n,int c[],int h[],int p[])
{
int ans=0;
for(int i=n-1;i>0;i--)
{
if(p[i]==0)ans+=c[i],c[h[i]]=max(0,c[h[i]]-c[i]);
if(p[i]==1)c[h[i]]+=c[i];
if(p[i]==2)c[h[i]]=max(c[h[i]],c[i]);
}
return ans+c[0];
}
// Confidence
int confidence[__MAXSIZE__];
// Host
int host[__MAXSIZE__];
// Protocol
int protocol[__MAXSIZE__];
// Main
int main(void)
{
auto t1 = clock();
int n,i;
// Number of people
assert(scanf("%d",&n)==1);
CAPITOLUL 6. IOI 2014 6.4. FRIEND 721
// Confidence
for(i=0;i<n;i++)
assert(scanf("%d",&confidence[i])==1);
auto t2 = clock();
// Answer
printf("%d\n",findSample(n,confidence,host,protocol));
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
argc = 4
checker
../tests/06-015.in
friend.out
../tests/06-015.out
----------------------
1
Correct
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/06-015.in",
(char*)"friend.out",
(char*)"../tests/06-015.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
CAPITOLUL 6. IOI 2014 6.5. GONDOLA 722
6.5 Gondola
Problema 5 - Gondola 100 de puncte
Telegondola Mao-Kong este o atracţie turistică faimoasă ı̂n Taiwan. Sistemul telegondolei
constă dintr-o şină circulară, o singură staţie, şi n gondole numerotate consecutiv de la 1 la n
care merg circular pe linie ı̂ntr-o direcţie fixată. După ce gondola cu numărul i trece prin staţie,
următoarea gondolă care trece prin staţie va fi gondola cu numărul i 1 dacă i $ n, sau gondola
cu numărul 1 dacă i n.
Gondolele pot să se defecteze. Din fericire avem la dispoziţie oricâte gondole de rezervă, care
sunt numerotate n 1, n 2, şi aşa mai departe. Când o gondolă se defectează, o ı̂nlocuim (ı̂n
aceeaşi poziţie pe şină) cu prima gondolă de rezervă disponibilă, adică cu cea care are cel mai mic
număr. De exemplu, dacă pe şină există 5 gondole şi gondola cu numărul 1 se defectează prima,
o ı̂nlocuim cu gondola cu numărul 6.
Ţie ı̂ţi place să stai ı̂n staţie şi să te uiţi cum trec gondolele. O secvenţă de gondole este o
secvenţă de n numere ale gondolelor ı̂n ordinea ı̂n care trec ele prin staţie. Este posibil ca una sau
mai multe din gondole să se fi defectat (şi să fi fost ı̂nlocuite) ı̂nainte să fi ajuns tu ı̂n staţie, dar
niciuna din gondole nu se defectează ı̂n timpul ı̂n care tu te uiţi la gondole.
Observaţi că aceeaşi configuraţie a gondolelor pe şină poate produce mai multe secvenţe de
gondole, ı̂n funcţie de care gondolă trece prima oară prin staţie când ajungi tu acolo. De exemplu,
dacă nicuna din gondole nu s-a defectat, atunci (2, 3, 4, 5, 1) şi (4, 5, 1, 2, 3) sunt secvenţe posibile
de gondole, ı̂n timp ce (4, 3, 2, 5, 1) nu este (deoarece gondolele apar ı̂n ordinea greşită).
Dacă se defectează gondola cu numărul 1, atunci am putea observa secvenţa de gondole (4, 5,
6, 2, 3).
Dacă următoarea care se defectează este gondola cu numărul 4, o ı̂nlocuim cu gondola numărul
7 şi am putea observa secvenţa de gondole (6, 2, 3, 7, 5). Dacă apoi se defectează gondola cu
numărul 7, o ı̂nlocuim cu gondola numărul 8 şi am putea observa secvenţa de gondole (3, 8, 5, 6,
2).
O secvenţă de ı̂nlocuiri este o secvenţă care conţine numerele gondolelor care s-au stricat, ı̂n
ordinea ı̂n care s-au stricat. Pentru exemplul precedent, secvenţa de ı̂nlocuiri este (1, 4, 7). O
secvenţă de ı̂nlocuiri r produce o secvenţă de gondole g dacă, după ce gondolele se strică conform
cu secvenţa de ı̂nlocuiri r, secvenţa de gondole g ar putea fi observată.
Verificarea unei secvenţe de gondole
Pentru primele trei subprobleme (subtask-uri) trebuie să verificaţi dacă o secvenţă dată este
o secvenţă de gondole. ı̂n tabelul de mai jos puteţi vedea exemple de secvenţe care sunt sau nu
secvenţe de gondole. Trebuie să impementaţi funcţia valid.
valid n, inputSeq
– n: lungimea secvenţei date.
– inputSeq: tablou unidimensional de lungime n; inputSeq i este elementul i al secvenţei
date, pentru 0 & i & n 1.
– Funcţia trebuie să retuneze 1 dacă secvenţa dată este o secvenţă de gondole, sau 0 ı̂n
caz contrar.
CAPITOLUL 6. IOI 2014 6.5. GONDOLA 723
Subproblemele 1, 2, 3
Exemple
Secvenţa de ı̂nlocuiri
Pentru următoarele trei subprobleme trebuie să contruiţi o secvenţă de ı̂nlocuiri care produce
o secvenţă de gondole dată. Orice secvenţă corectă de ı̂nlocuiri va fi acceptată. Trebuie să
implementaţi funcţia replacement.
replacement(n, gondolaSeq, replacementSeq)
– n este lungimea secvenţei de gondole.
– gondolaSeq: tablou unidimensional de lungime n; se garantează că gondolaSeq este o
secvenţă de gondole, şi gondolaSeq i este elementul cu numărul i din secvenţă, pentru
0 & i & n 1.
– Funcţia trebuie să returneze numărul l, lungimea secvenţei de ı̂nlocuiri.
– replacementSeq: un tablou unidimensional care este suficient de mare pentru a stoca
elementele secvenţei de ı̂nlocuiri; trebuie să transmiteţi secvenţa prin plasarea elemen-
tului i al secvenţei de ı̂nloucuiri găsite de voi ı̂n replacementSeq i, pentru 0 & i & l 1.
Subproblemele 4, 5, 6
Exemple
– Dacă secvenţa dată este o secvenţă de gondole, atunci trebuie să determinaţi numărul
(care poate fi foarte mare) de secvenţe de ı̂nlocuiri posibile care produc această secvenţă,
şi să returnaţi acest număr modulo 1,000,000,009. Dacă secvenţa dată nu este o secvenţă
de gondole, funcţia trebuie să returneze 0. Dacă secvenţa dată este o secvenţă de
gondole dar nicio gondolă nu s-a stricat, funcţia trebuie să retuneze 1.
Subproblemele 7, 8, 9, 10
Exemple
Detalii de implementare
Trebuie să ı̂ncărcaţi exact un fişier, numit gondola.c, gondola.cpp sau gondola.pas. Acest
fişier trebuie să implementeze toate cele trei subprograme descrise mai sus (chiar dacă plănuiţi
să rezolvaţi doar unele din subprobleme), folosing următoarele antete. De asemenea trebuie să
includeţi fişierul header gondola.h pentru implementări C/C++.
pentru programe C/C++
Overview
This is an easy problem. Even though it might seem that there are three separate tasks (as
indicated by the grouping of subtasks), the task is actually incremental. The three parts (check
whether there is a solution - find one solution - count all solutions) are closely related.
Subtasks 1-3
In subtask 1, once we see the first gondola (i.e., inputSeq 0), the rest is uniquely determined.
We just need to iterate through the sequence and check whether everything matches.
N = len(sequence)
for n:=1..N: if sequence[n] % N != (sequence[0]+n) % N: return False
return True
If there exist one of the original gondolas: check whether the other original gondolas are in
the expected places, if not, return false.
Return true if all the values are distinct, false otherwise.
Subtasks 4-6
A simple solution for subtask 4: if the largest number in the sequence is n, terminate, otherwise
output the only missing number and terminate.
Solutions for subtasks 5 and 6 share the same idea, the difference is that subtask 4 allows its
inefficient implementations. There are many possible solutions. Here is one of them.
Collect all non-original gondolas. For each of them determine the original gondola it replaced.
Sort these records according to the new gondola number.
In sorted order, replace the original gondolas by new ones until the expected numbers are
reached.
Note that the case where no original gondolas are present may require special attention - not
just for the contestants, but also in the grader for these subtasks.
Subtasks 7-10
Counting the repair sequences directly is hard. One way of doing it is by asking the question:
How many repair sequences start with gondola x being replaced? for each x. Each choice of x
leads us to a new state with one fewer gondolas to replace.
Using this idea we can now solve subtask 8 by dynamic programming: for each admissible state
of the lift we compute the number of ways in which it can be solved.
Subtasks 9 and 10 require one additional insight. (This is, probably, the only tricky part of
this problem, and the insight needed is not too hard.)
Instead of looking at the old gondola that is being removed, we will simply look at the new
gondola that is being added. How many different options do we have for its place? If the new
gondola is present in the final sequence, its place is uniquely determined. Otherwise, the number
of places where this new gondola can be added is simply the number of places that end up having
a gondola with a larger number.
Additionally, we need to multiply the result by n if none of the original gondolas is present.
(All n cyclic rotations of the original sequence are now possible, and the repair sequences for
different rotations are necessarily distinct.) We outline the algorithm as follows:
Run the algorithm for subtasks 1-3 to check whether the input sequence is valid or not.
If valid, for each replaced gondola we find the original gondola it ultimately replaced, and
we sort these records according to the new gondola number.
CAPITOLUL 6. IOI 2014 6.5. GONDOLA 726
The total number of possibilities can now be computed by multiplying the number of possible
locations for each gondola between n+1 and the largest replaced gondola number present.
Note the multiplicative operation is modular here.
Finally, multiply by n if all original gondolas are replaced.
#include<ctime>
#include<iostream>
#include "gondola.h"
int gondolaSequence[100001];
int replacementSequence[250001];
#include <algorithm>
int arr[250001];
int now[250001];
std::sort(inputSeq,inputSeq+n);
for(i=1;i<n;i++)
if(inputSeq[i-1]==inputSeq[i])
return 0;
return 1;
}
j=0;
for(i=0;i<n;i++)if(gondolaSeq[i]>j)j=gondolaSeq[i];
for(i=n+1;i<=j;i++)
{
replacementSeq[i-n-1]=arr[i]>0?now[arr[i]-1]:now[arr[j]-1];
now[arr[i]>0?arr[i]-1:arr[j]-1]=i;
}
return j-n;
}
return 1LL*x*x%MOD;
}
std::sort(inputSeq,inputSeq+n);
for(i=0;i<n;i++)
{
if(inputSeq[i]<=n)continue;
r=1LL*r*f(n-i,inputSeq[i]-(i>0?std::max(inputSeq[i-1],n):n)-1)%MOD;
}
return 1LL*r*(inputSeq[0]>n?n:1)%MOD;
}
int main()
{
auto t1 = clock();
int i, n, tag;
int nr;
assert(scanf("%d", &tag)==1);
assert(scanf("%d", &n)==1);
for(i=0;i< n;i++)
assert( scanf("%d", &gondolaSequence[i]) ==1);
auto t2 = clock();
switch (tag)
{
case 1: case 2: case 3:
printf("%d\n", valid(n, gondolaSequence));
break;
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
CAPITOLUL 6. IOI 2014 6.5. GONDOLA 728
}
// -------------- end grader --------------------
/*
t2-t1 = 0.016
t3-t2 = 0.031
t4-t3 = 0
#include "gondola.h"
#include <iostream>
#include <map>
#include <algorithm>
#include <stdio.h>
#include <assert.h>
#include<ctime>
int gondolaSequence[100001];
int replacementSequence[250001];
map<int,int> ap;
int v[nmax];
int i,act;
return 1;
}
//----------------------
for(i=n+1;i<=mx;i++)
if(ap[i])
{
replacementSeq[l++]=ap[i];
act++;
while(act<i)
{
replacementSeq[l++]=act;
act++;
}
}
return l;
}
//----------------------
sort(inputSeq,inputSeq+n);
for(i=n-2;i>=0;i--)
if(inputSeq[i]>n||inputSeq[i+1]>n)
{
f=n-1-i;if(inputSeq[i]<n) inputSeq[i]=n;
ans=(1LL*ans*expo(f,inputSeq[i+1]-inputSeq[i]-1))%mod;
}
if(ordered)
{
f=n;
ans=(1LL*ans*expo(f,inputSeq[0]-n-1))%mod;
f=n;
ans=(1LL*ans*f)%mod;
}
return ans;
}
int main()
{
auto t1 = clock();
int i, n, tag;
int nr;
assert(scanf("%d", &tag)==1);
assert(scanf("%d", &n)==1);
for(i=0;i< n;i++)
assert( scanf("%d", &gondolaSequence[i]) ==1);
auto t2 = clock();
CAPITOLUL 6. IOI 2014 6.5. GONDOLA 730
switch (tag)
{
case 1: case 2: case 3:
printf("%d\n", valid(n, gondolaSequence));
break;
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
// -------------- end grader --------------------
/*
t2-t1 = 0.124
t3-t2 = 0.188
t4-t3 = 0.016
int gondolaSequence[100001];
int replacementSequence[250001];
#include <bits/stdc++.h>
#include "gondola.h"
}
x = mul(x, x);
y >>= 1;
}
return res;
}
return 1;
}
return m - n;
}
int ans = 1;
if (inputSeq[0] > n)
{
ans = n;
}
CAPITOLUL 6. IOI 2014 6.5. GONDOLA 732
return ans;
}
int main()
{
auto t1 = clock();
int i, n, tag;
int nr;
assert(scanf("%d", &tag)==1);
assert(scanf("%d", &n)==1);
for(i=0;i< n;i++)
assert( scanf("%d", &gondolaSequence[i]) ==1);
auto t2 = clock();
switch (tag)
{
case 1: case 2: case 3:
printf("%d\n", valid(n, gondolaSequence));
break;
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
// -------------- end grader --------------------
/*
t2-t1 = 0.063
t3-t2 = 0.046
CAPITOLUL 6. IOI 2014 6.5. GONDOLA 733
t4-t3 = 0
int gondolaSequence[100001];
int replacementSequence[250001];
#include "gondola.h"
#include <bits/stdc++.h>
sort(S.begin(), S.end());
if(S.size()!=N) return 0;
int flag=-1;
for(i=0; i<N; i++)
{
if(A[i]>N) continue;
int t=(A[i]-1-i+N)%N;
if(flag==-1) flag=t;
else
if(flag!=t) return 0;
}
return 1;
}
int flag=0;
vector<pii> V;
for(i=0; i<N; i++)
{
if(A[i]<=N)
{
flag=(A[i]-1-i+N)%N;
continue;
}
V.push_back({A[i], i});
}
sort(V.begin(), V.end());
int now=N+1;
for(i=0; i<V.size(); i++)
{
int p=V[i].first, q=V[i].second;
CAPITOLUL 6. IOI 2014 6.5. GONDOLA 734
while(A[q]!=p)
{
B[ret++]=A[q];
A[q]=now++;
}
}
return ret;
}
ll mypow(ll x, ll y)
{
if(y==0) return 1;
ll ret=mypow(x, y/2);
return ret*ret%MOD;
}
int flag=-1;
vector<int> V; V.push_back(N);
for(i=0; i<N; i++)
{
if(A[i]<=N) flag=0;
else V.push_back(A[i]);
}
sort(V.begin(), V.end());
for(i=1; i<V.size(); i++)
ans=ans*mypow(V.size()-i, V[i]-V[i-1]-1)%MOD;
if(flag==-1) ans=ans*N%MOD;
return ans;
}
int main()
{
auto t1 = clock();
int i, n, tag;
int nr;
assert(scanf("%d", &tag)==1);
assert(scanf("%d", &n)==1);
for(i=0;i< n;i++)
assert( scanf("%d", &gondolaSequence[i]) ==1);
auto t2 = clock();
switch (tag)
{
case 1: case 2: case 3:
printf("%d\n", valid(n, gondolaSequence));
break;
break;
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
// -------------- end grader --------------------
/*
t2-t1 = 0.078
t3-t2 = 0.062
t4-t3 = 0
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/10-018.in",
(char*)"gondola.out",
(char*)"../tests/10-018.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
6.6 Holiday
Problema 6 - Holiday 100 de puncte
Jian-Jia planifică să-şi petreacă următoarea vacanţă ı̂n Taiwan. Pe durata vacanţei, Jian-Jia
va călători dintr-un oraş ı̂n altul şi va vizita atracţiile oraşelor.
Există n oraşe ı̂n Taiwan, toate situate de-a lungul unei singure autostrăzi. Oraşele sunt
numerotate consecutiv de la 0 la n. Pentru oricare oraş i, unde 0 $ i $ n 1, oraşele adiacente
sunt i 1 şi i 1. Oraşul 0 este adiacent doar cu oraşul 1, iar oraşul n 1 este adiacent doar cu
oraşul n 2.
Fiecare oraş conţine un anumit număr de atracţii. Jian-Jia are d zile de vacanţă şi intenţionează
să viziteze cat mai multe atracţii posibile. Jian-Jia a ales deja oraşul din care ı̂şi va ı̂ncepe
vacanţa. ı̂n fiecare zi de vacanţă, Jian-Jia poate călători ı̂n unul din oraşele adiacente ori vizita
toate atracţiile din oraşul ı̂n care se află, dar nu poate face ambele. Jian-Jia nu va vizita niciodată
de mai multe ori atracţiile dintr-un oraş chiar dacă vizitează acelaşi oraş de mai multe ori. Vă
rugăm să-l ajutaţi pe Jian-Jia să-şi planifice vacanţa astfel ı̂ncât să viziteze cât mai multe atracţii
posibile.
Exemplu
Să presupunem că avem 5 oraşe (listate ı̂n tabelul de mai jos), iar Jian-Jia are o vacanţă de
7 zile pe care o ı̂ncepe din oraşul 2. ı̂n prima zi, Jian-Jia va vizita cele 20 de atracţii din oraşul
2. ı̂n a doua zi Jian-Jia călătoreşte din oraşul 2 ı̂n oraşul 3, iar ı̂n a treia zi vizitează cele 30 de
atracţii din oraşul 3. Apoi, Jian-Jia călătoreşte următoarele trei zile de la oraşul 3 la oraşul 0, şi
vizitează cele 10 atracţii din oraşul 0 ı̂n cea de-a şaptea zi. Numărul total de atracţii pe care le
va vizita Jian-Jia este 20 + 30 + 10 = 60, care reprezintă numărul maxim de atracţiii pe care le
poate vizita Jian-Jia ı̂n cele 7 zile de vacanţă, ı̂n cazul ı̂n care primul oraş vizitat este 2.
zi acţiune
1 vizitează atracţiile din oraşul 2
2 călătoreşte de la oraşul 2 la oraşul 3
3 vizitează atracţiile din oraşul 3
4 călătoreşte de la oraşul 3 la oraşul 2
5 călătoreşte de la oraşul 2 la oraşul 1
6 călătoreşte de la oraşul 1 la oraşul 0
7 vizitează atracţiile din oraşul 0
Cerinţă
Trebuie să implementaţi funcţia f indM axAttraction care calculează numărul maxim de
atracţii pe care Jian-Jia le poate vizita.
f indM axAttraction n, start, d, attraction
– n: numărul de oraşe.
– start: indicele primului oraş vizitat.
– d: numărul de zile.
– attraction: un tablou unidimensional de lungime n; attractioni este numărul de
atracţii din oraşul i, pentru 0 & i & n 1.
– Funcţia trebuie să returneze numărul maxim de atracţii pe care Jian-Jia le poate vizita.
Subprobleme
În toate subproblemele 0 & d & 2n n©2$ şi numărul de atracţii din fiecare oraş este nenegativ.
Constrângeri adiţionale:
CAPITOLUL 6. IOI 2014 6.6. HOLIDAY 737
Detalii de implementare
Trebuie să ı̂ncărcaţi un singur fişier, cu numele holiday.c, holiday.cpp sau holiday.pas.
Acest fişier va conţine un subprogram care implementează subproblemele descrise mai sus
folosind următorul antet. De asemenea trebuie să includeţi headerul holiday.h pentru imple-
mentările C/C++.
Atenţie: rezultatul poate fi un număr mare şi tipul valorii returnate de funcţia
f indM axAttraction este un ı̂ntreg pe 64-biţi.
pentru programele C/C++
For ease of description, we will first describe a simple O n log n-time solution for the special case
of the starting city start being the one with the index 0 for any fixed d. That is, start 0 and d
2
is a given number. Then we extend this solution to build a table of solutions in O n log n time
for all possible values of d. Finally we describe how to extend this solution to solve the general
case of an arbitrary start with the same asymptotic time complexity.
Simple solution for start 0 and a given fixed d
Without lost of generality, assume we start at the leftmost city and move right. It is easy to
see that we only need to move right and there is no need to move left at any time.
Assume in an optimal solution, city right is the rightmost city we will travel to. Then we can
visit up to d right cities among the cities with labels 0, 1, ..., right. In order for the solution to
be optimal, we want to visit the d right cities with the largest number of attractions. That is,
if we sort the cities with labels 0, 1, ..., right using the number of attractions as their keys, then
we want to know the sum of the d right largest number of attractions.
Segment tree We use a data structure called segment tree for this part though it may appear
this data structure is not needed to solve this very special case. However, it will be clear why this
data structure is used in the solution to the intermediate case. The segment tree data structure
has been used in previous IOI contests including 2001 Baltic OI.
The segment tree has many variations. We will use the following one. A segment tree is a
rooted complete binary tree with leaves carrying a flag indicating whether this leaf is active or not,
CAPITOLUL 6. IOI 2014 6.6. HOLIDAY 738
and a value. For each internal node v, it keeps the sum of the values of all of the active leaves in
the subtree rooted at v. Each internal node also maintains the number of currently active leaves
in the subtree rooted at v.
Assume the segment tree has n leaves. Note that we need to add dummy leaves of n is not
a power of 2. Further assume the values of the leaves, active or in-active, are in non-increasing
order from left to right. To maintain this data structure, it takes O log n time to turn on or off
any leaf. It also takes O log n time to find out the sum of the values in the largest x active leaves
for any given x. A side note is when x is more than the number of active leaves, then we simply
output the sum of the values of all active leaves.
Algorithm Initially, we sort the cities using their number of attractions as keys in non-
increasing order. Then in this order, we place them as leaves in the segment tree from left to
right with all leaves in-active. The number of attractions are now the values of the leaves. The
initialization phase takes O n log n time. We turn on a leaf when it is being move to during the
search of our solution. We iterate on all possible values of the rightmost city we can move to.
Hence it takes a total of O n log n time to find a solution for this easy special case.
Intermediate solution for start 0 and all possible values of d
Now we describe how to solve this intermediate case. In our previous solution, we can find the
maximum number of attractions we can visit given any d.
Let f d be the label of the city we move to in d days so that the maximum number of
attractions can be found.
Note that f d may not be unique. In the case of multiple ones, we pick the one with the
smallest label. We now want to build a table for all possible values of d.
The idea is to use recursive divide-and-conquer approach.
Let M be the maximum number of d. For ease of description, let M be a power of 2.
To compute the solutions for f 1, f 2, ..., f M we first find f M ©2 using our pre-
vious algorithm by iterating through all cities from 0 to n and then recursively compute
f 1, f 2, ..., f M ©2 1 in one branch by considering only cities from 0 to f M ©2, and
f M ©2 1, f M ©2 2, ..., f M in the other branch by considering only cities from f M ©2 to
n.
In the branch of computing f 1, f 2, ..., f M ©2 1, we first compute f M ©4 among cities
0 to f M ©2. In general, the total amount of time spent in each level of recursive calls takes a
total of O n log n. There are a total of O log n levels. Hence the overall time complexity is
2
O n log n.
In solving this intermediate case, it is now clear how the segment tree is useful. First we only
need to do the initialization once. Secondly, we can easily turn on or off a leaf to accommodate
the fact that the cities that we pay attention to in each level of recursion. For example, only half
of the leaves are active during the second level of recursion.
General solution for an arbitrary value of start
Now we are ready to show the general solution. Observe the fact that when the value of start
is arbitrary, then the solution can be found in either one of the following 2 cases.
We first move right to a city, then move left from this point, and then finally stop at a city
left of start. Or we first move left to a city, then move right from this point, and then finally stop
at a city right of start. That is, we only change the direction once.
Without lost of generality, we assume the first scenario. We first use the immediately solution
to find f t for all possible of values t. Then we also use the immediately solution to find g t for
all possible values of t where g t is the city we will stop in an optimal solution if we only move
left and the starting city is start 1.
We first iterate on d0 the days we want to spend on moving and visiting cities to the right of,
and including, start.
Using the solution to the intermediate case, we know f d0 .
Then we know we can spend d d0 f d0 start 1 days on the cities to the left of start.
2
Hence the overall time complexity is O n log n.
#include "holiday.h"
#include <bits/stdc++.h>
struct NOD
{
NOD() : sum(0), cnt(0), l(0), r(0) {}
ll sum;
int cnt, l, r;
} arr[MAXN*18]; int arrn;
int newNOD()
{
return ++arrn;
}
int pst[MAXN];
ll Ans;
int N, X, L;
if(s == e) return;
upmax(Ans, hc);
f(s, m-1, p, hi);
f(m+1, e, hi, q);
}
ll getAns()
{
iota(AO, AO+N+1, 0);
sort(AO+1, AO+N+1, [&](int a, int b)
{
return A[a] > A[b];
});
arrn = 0;
X = N+1-X;
reverse(A+1, A+N+1);
iota(AO, AO+N+1, 0);
sort(AO+1, AO+N+1, [&](int a, int b) {return A[a] > A[b];});
return Ans;
}
return getAns();
}
int main()
{
auto t1 = clock();
int n, start, d;
int attraction[100000];
int i, n_s;
auto t2 = clock();
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
#include "holiday.h"
#include <bits/stdc++.h>
struct st
{
int l, r, cnt;
long long sum;
st()
{
l = r = cnt = sum = 0;
}
} t[N * 20];
else
{
int tm = (tl + tr) >> 1;
if(pos <= tm)
{
if(!t[v].l) t[v].l = ++ cn;
t[v].r = t[ov].r;
upd(t[ov].l, t[v].l, pos, tl, tm);
}
else
{
if(!t[v].r) t[v].r = ++ cn;
t[v].l = t[ov].l;
upd(t[ov].r, t[v].r, pos, tm + 1, tr);
}
long long get(int ov, int v, int cnt, int tl = 0, int tr = sz)
{
if(cnt <= 0) return 0ll;
if(tl == tr)
{
long long k = min(t[v].cnt - t[ov].cnt, cnt);
return k * 1ll * vec[tl];
}
sort(vec.begin(),vec.end());
sz = (int)vec.size() - 1;
for(int i = 0; i < n; i ++)
{
ar[i] = lower_bound(vec.begin(),vec.end(), ar[i])-vec.begin();
}
return ans;
}
int main()
{
auto t1 = clock();
int n, start, d;
int attraction[100000];
int i, n_s;
auto t2 = clock();
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
#include <bits/stdc++.h>
#include "holiday.h"
struct pst
{
struct T
{
ll x=0;
int cnt=0, l=0, r=0;
};
int m=s+e>>1;
if(x<=m) add(x, s, m, A[i].l);
else add(x, m+1, e, A[i].r);
}
void add(int x)
{
td++;
add(x, 0, N-1, D[td]=D[td-1]);
}
sort(begin(X), end(X));
pst t(move(X));
for(int i=0; i<N; i++) t.add(A[i]);
int m=s+e>>1;
pair<ll, int> n={-1, -1};
return max({n.first,
CAPITOLUL 6. IOI 2014 6.6. HOLIDAY 745
int main()
{
auto t1 = clock();
int n, start, d;
int attraction[100000];
int i, n_s;
auto t2 = clock();
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
#include<bits/stdc++.h>
#include"holiday.h"
struct Node
{
int cnt;
ll sum;
int l, r;
};
int ptr = 0;
const int V = N * 20;
Node d[V];
int t[N];
int newNode()
{
++ptr;
return ptr - 1;
}
int m = (l + r) >> 1;
if (i <= m)
{
d[ans].l = add(d[t].l, l, m, i);
d[ans].r = d[t].r;
}
else
{
d[ans].l = d[t].l;
d[ans].r = add(d[t].r, m + 1, r, i);
}
return ans;
}
int m = (l + r) >> 1;
int r_cnt = d[d[tr].r].cnt - d[d[tl].r].cnt;
if (k <= r_cnt)
return sum(d[tl].r, d[tr].r, m + 1, r, k);
else
return (d[d[tr].r].sum - d[d[tl].r].sum) +
sum(d[tl].l, d[tr].l, l, m, k - r_cnt);
}
ll ans = 0;
CAPITOLUL 6. IOI 2014 6.6. HOLIDAY 747
ll get(int l, int r)
{
int go = (start - l) + (r - start) + min(start - l, r - start);
if (hol <= go)
return 0;
int k = hol - go;
long long int findMaxAttraction(int n, int start_, int hol_, int a_[])
{
for (int i = 0; i < V; ++i)
{
d[i].cnt = d[i].sum = 0;
d[i].l = d[i].r = -1;
}
start = start_;
hol = hol_;
for (int i = 0; i < n; ++i)
a[i] = a_[i];
sort(all(c));
c.resize(unique(all(c)) - c.begin());
solve(start, n - 1, 0, start);
return ans;
}
int main()
{
auto t1 = clock();
int n, start, d;
int attraction[100000];
int i, n_s;
auto t2 = clock();
auto t3 = clock();
fclose(stdout);
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/04-009.in",
(char*)"holiday.out",
(char*)"../tests/04-009.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
Urmează să dai un examen la Istoria Artei, dar ai dat mai multă importanţă informaticii decât
cursului de artă. Va trebui să scrieţi un program care va da examenul ı̂n locul vostru.
Examenul va consta din mai multe picturi. Fiecare pictură va fi un exemplu din una dintre 4
stiluri distincte, numerotate 1, 2, 3 şi 4.
Primul stil conţine artă modernă neoplazică. De exemplu:
750
CAPITOLUL 7. IOI 2013 7.1. ART CLASS 751
Dată fiind o imagine digitală a unei picturi, se pune problema determinării stilului de care
aparţine.
Comisia IOI a colecţionat mai multe imagini din fiecare stil. Nouă imagini din fiecare stil au
fost selectate aleator şi incluse in materialul problemei pe computer-ul vostru, astfel să le puteţi
examina manual şi folosi pentru testare. Imaginile rămase vor fi date programului tău ı̂n timpul
gradării.
Imaginea va fi oferită ca un grid de H W pixeli. Rândurile imaginii sunt numerotate 0, ...,
H 1 de sus ı̂n jos, iar coloanele sunt numerotate 0, ..., W 1 de la stânga la dreapta.
Pixelii sunt descrişi folosind matricele R, G şi B, care vă spun cantitatea de roşu, verde
şi albastru al fiecărui pixel din imagine. Aceste cantităţi variază de la 0 (fără roşu, verde sau
albastru) la 255 (cantitatea maxima de roşu, verde sau albastru).
Implementare
Va trebui să submitaţi un fişier ce implementează functia travelTime(), după cum
urmează:
Funcţia voastră: travelTime()
C/C++
Pascal
Descriere
Această funcţie ar trebui să determine stilul de care aparţine imaginea.
Parametrii
H : Numărul de rânduri de pixeli din imagine.
W : Numărului de coloane de pixeli din imagine.
R : O matrice de mărime H W ce conţine cantitatea de roşu din fiecare pixel al imaginii.
G : O matrice de mărime H W ce conţine cantitatea de verde din fiecare pixel al imaginii.
B : O matrice de mărime H W ce conţine cantitatea de albastru din fiecare pixel al
imaginii.
Returnează: Stilului imaginii, care poate fi 1 , 2 , 3 sau 4 , cum e descris mai sus.
Fiecare element al matricei Rij , Gij şi B ij reprezintă pixelul de pe linia i şi coloana
j, şi va fi un număr ı̂ntreg ı̂ntre 0 şi 255 inclusiv.
Constrângeri
Limită de timp: 5 secunde
Limită de memorie: 64 MiB
100 & H & 500
100 & W & 500
Punctaje
Nu există subtaskuri. ı̂n schimb, scorul vostru pentru acest task va fi calculat pe baza
numărului de imagini pe care programul vostru le clasifică corect.
Presupunând că veţi clasifica corect un procent de P imagini (deci 0 & P & 100):
CAPITOLUL 7. IOI 2013 7.2. CAVE 752
Testare
Grader-ul de pe computerul vostru va citi input-ul din fişierul artclass.jpg. Acest fişier
trebuie sa conţină o imagine ı̂n format JPEG.
Vă este permis să folosiţi orice aplicaţie de procesare grafică pentru a studia imaginile, dar
acest lucru nu este necesar pentru a rezolva problema. (Vedeţi meniul ”Applications ¿ Graphics”.)
Note de limbaj
C/C++: Trebuie să faceţi #include "artclass.h".
Pascal: Trebuie să definiţi unit ArtClass. Toţi vectorii sunt indexaţi de la 0 (nu de la 1).
Vedeţi template-urile de soluţii de pe calculatorul vostru pentru exemple.
Timp maxim de executare/test: 5.0 secunde
Memorie: total 64 MB
http://blog.brucemerry.org.za/2013/07/ioi-2013-day-1-analysis.html
This is a heuristic problem that can probably be solved in many ways.
Since it was a hammer I have, I decided to hit it with a very simple wavelet-based spectral
analysis.
To find the highest-frequency components, downsample the image, upsample it again, and
subtract it from the original.
Then take the sum of squared values in the residual.
Now start with the downsampled image and repeat recursively to get progressively lower fre-
quencies.
For the downsample and upsample I took a simple box filter. I kept 6 frequencies, since 26 is
less than the minimum image size.
For each style, I computed the mean and standard deviation of each of the 6 power values from
the examples.
To classify a picture, I sum up the squared differences from the means, with the differences
scaled using the standard deviations. It’s not 100% accurate, but good enough to get a perfect
score.
7.2 Cave
Problema 2 - Cave 100 de puncte
Pierdându-vă pe drumul lung de la colegiu la UQ Centre, aţi dat peste intrarea ı̂ntr-un sistem
secret de peşteri ce se ı̂ntinde adânc sub universitate. Intrarea este blocată de un sistem de
securitate consistând din N uşi consecutive, aflate una ı̂n spatele alteia şi N ı̂ntrerupătoare,
fiecare ı̂ntrerupător conectat la o uşă diferită.
Uşile sunt numerotate 0, 1, ..., N 1 ı̂n ordine, uşa 0 fiind cea mai apropiată de voi.
Întrerupătoarele sunt de asemenea numerotate 0, 1, ..., N 1, dar nu cunoaşteţi care
ı̂ntrerupător este conectat la care uşă.
Întrerupătoarele se află la intrarea ı̂n peşteră. Fiecare ı̂ntrerupător poate fi ı̂n poziţia up sau
ı̂n poziţia down. Numai una din aceste poziţii este corectă pentru fiecare ı̂ntrerupător. Dacă
un ı̂ntrerupător este ı̂n poziţia corectă atunci uşa la care este conectat se va deschide, iar dacă
ı̂ntrerupătorul se află ı̂n poziţia greşita atunci uşa la care este conectat nu se va deschide. Poziţia
corectă poate fi diferită pentru diferite ı̂ntrerupătoare, şi voi nu ştiţi care poziţii sunt cele corecte.
Aţi vrea să ı̂nţelegeţi sistemul de securitate. Pentru a face asta, puteţi seta ı̂ntrerupătoarele
ı̂n orice combinaţie, şi apoi puteţi merge ı̂n peşteră pentru a vedea care este prima uşă ı̂nchisă.
Uşile nu sunt transparente: o dată ce aţi ı̂ntâlnit prima uşă ı̂nchisă, nu puteţi vedea nicio uşă ce
se află după aceasta.
Aveţi timp să ı̂ncercaţi 70,000 de combinaţii de ı̂ntrerupătoare, dar nu mai mult de atât. Taskul
vostru este să determinaţi poziţia corectă pentru fiecare ı̂ntrerupător şi cu care uşă este conectat
fiecare ı̂ntrerupător.
Implementare
Va trebui să submitaţi un fişier ce implementează procedura exploreCave(). Acesta poate
apela funcţia tryCombination() a grader-ului de maxim 70,000 de ori, şi trebuie să termine
apelând procedura answer() a grader-ului. Aceste funcţii şi proceduri sunt descrise mai jos.
Funcţia grader-ului: tryCombination()
C/C++
Pascal
Descriere
Grader-ul va avea acestă funcţie. Aceasta vă permite să ı̂ncercaţi o combinaţie de
ı̂ntrerupătoare, şi apoi să intraţi ı̂n peşteră pentru a determina care este prima uşă ı̂nchisă. Dacă
toate uşile sunt deschise, atunci va returna -1. Acestă funcţie se execută ı̂ntr-o complexitate
temporală de O N ; adică ı̂n cel mai rău caz se execută ı̂ntr-un timp propoţional cu N .
Acestă funcţie poate fi apelată de maxim 70,000 de ori.
Parametrii
Pascal
Descriere
Apelaţi acestă procedură atunci când aţi identificat o combinaţie de ı̂ntrerupătoare care să
deschidă toate uşile, şi uşa la care este conectat fiecare ı̂ntrerupător.
Parametrii
S: Un array de lungime N , indicând poziţia corectă a fiecărui ı̂ntrerupător. Formatul
acestuia este la fel cu formatul din funcţia tryCombination() de mai sus.
D: Un array de lungime N , indicând uşa la care este conectat fiecare ı̂ntrerupător. Mai
precis, elementul Di ar trebui să conţină numărul uşii la care ı̂ntrerupatorul i este conectat.
Returns: Această procedură nu returneaza, ci va cauza programul sa facă exit.
Pascal
Descriere
Submisia voatră trebuie să implementeze această procedură.
Această procedură ar trebui să folosească funcţia tryCombination() a grader-ului pentru a
determina poziţia corectă a fiecărui ı̂ntrerupător, şi uşa la care este conectat fiecare ı̂ntrerupător,
iar apoi, când are aceste informaţii, să apeleze answer().
Parametrii
Exemplu
Presupuneţi că uşile si ı̂ntrerupătoarele sunt aranjate ca ı̂n imaginea de mai sus:
Apel de funcţie Returnează Explicaţie
tryCombination([1,0,1,1]) 1 Aceasta corespunde imaginii.
ı̂ntrerupătoarele 0, 2 şi 3 sunt down,
iar ı̂ntrerupătorul 1 este up. Funcţia
returnează 1, indicând că uşa 1 este
prima uşă de la stânga care este ı̂nchisă.
tryCombination([0,1,1,0]) 3 Uşile 0, 1 şi 2 sunt deschise, iar uşa 3 este
ı̂nchisă.
tryCombination([1,1,1,0]) -1 Mutând ı̂nterupătorul 0 ı̂n poziţia down
cauzează toate uşile să se deschidă, lucru
indicat de valoarea de retur -1
answer([1,1,1,0],[3,1 0,2]) (Programul Ne putem da seama că răspunsul este [1,
ı̂şi ı̂ncheie 1, 1,0], iar ı̂ntrerupătoarele 0, 1, 2 şi 3
execuţia) sunt conectate la uşile 3, 1, 0 şi 2.
Constrângeri
Limită de timp: 2 secunde
Limită de memorie: 32 MiB
1 & N & 5, 000
CAPITOLUL 7. IOI 2013 7.2. CAVE 755
Subtask-uri
Subtask Punctaj Constrângeri adiţionale
1 12 Pentru fiecare i, ı̂nterupătorul i este conectat la uşa i. Task-ul vostru
este să determinaţi poziţia corectă a ı̂ntrerupătoarelor.
2 13 Poziţia corectă va fi tot timpul [0, 0, 0, ..., 0].
Task-ul vostru este să determinaţi cu ce uşă este conectat fiecare
ı̂ntrerupător.
3 21 N & 100
4 30 N & 2, 000
5 24 (Nimic)
Testare
Grader-ul de pe computerul vostru va citi datele de intrare din fişierul cave.in, care trebuie
să fie ı̂n următorul format:
linia 1: N
linia 2: S 0 S 1 ... S N 1
linia 3: D0 D1 ... DN 1
Aici N este numărul de uşi şi ı̂ntrerupătoare, S i este poziţia corectă pentru ı̂ntrerupătorul
i, şi Di este uşa la care este conectat ı̂ntrerupătorul i.
Astfel, exemplul de mai sus ar fi dat ı̂n următorul format:
41
1 1 0
3 1 0 2
Note de limbaj
C/C++: Trebuie să faceţi #include "cave.h".
Pascal: Trebuie să definiţi unit Cave, şi trebuie să importaţi rutinele grader-ului facând
uses GraderHelpLib. Toate array-urile sunt indexate de la 0 (nu de la 1).
Vedeţi template-urile de soluţii de pe computer-ul vostru pentru exemple.
Timp maxim de executare/test: 2.0 secunde
Memorie: total 32 MB
http://blog.brucemerry.org.za/2013/07/ioi-2013-day-2-analysis.html
This is a nice problem following a recent IOI trend of having problems where the limiting
factor is not execution time, but some abstract measure of efficiency. This is slightly easier than
some of the previous problems in each vein.
To achieve 100%, we can use up to 14 queries per door. Since 214 is slightly more than the
number of doors, this strongly suggests some form of binary search on each door. It will be easiest
if we attack the doors in order. Once we know which switch and position opens a door, we can lock
that switch in place so that we will always be able to see the next door, and thereafter pretend
the switch does not even exist.
To solve for a door, we can start with all switches down, which will immediately tell us which
switch position opens the door. At this point every switch is a candidate. We can then test with
half the candidates down and half up, which will eliminate half the candidates. This process is
then repeated until only one candidate remains.
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
#include<ctime>
//#include "cave.h"
int w[14][5000],F[5000];
void exploreCave(int N)
{
int i,j,t,c,ck;
for(i=0;i<14;i++)
{
for(j=0;j<N;j++)
{
if((1<<i)&j)w[i][j]=1;
}
}
for(i=0;i<N;i++)
{
c=0;
t=tryCombination(w[13]);
ck=(t==i);
for(j=0;j<13;j++)
{
t=tryCombination(w[j]);
if(t==i && !ck)c+=1<<j;
if(t!=i && ck)c+=1<<j;
}
for(j=0;j<14;j++)
w[j][c]=ck;
F[c]=i;
}
answer(w[0],F);
}
/* Symbol obfuscation */
#define N koala
#define realS kangaroo
#define realD possum
#define inv platypus
#define num_calls echidna
static int N;
static int realS[MAX_N];
static int realD[MAX_N];
static int inv[MAX_N];
static int num_calls;
int correct = 1;
for (i = 0; i < N; ++i)
if (S[i] != realS[i] || D[i] != realD[i])
{
correct = 0;
break;
}
//exit(0);
}
int init()
{
int i, res;
num_calls = 0;
return N;
}
int main()
{
auto t1 = clock();
int N;
N = init();
auto t2 = clock();
CAPITOLUL 7. IOI 2013 7.2. CAVE 758
exploreCave(N);
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.053
t3-t2 = 1.487
t4-t3 = 0
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
#include<ctime>
int a[5010],b[5010],chk[5010];
void exploreCave(int N)
{
int i,j,s,e,m,t,p;
for(i=0;i<N;++i)
{
t=tryCombination(a);
s=0,e=N-1;
while(s<e)
{
m=(s+e)/2;
for(j=s;j<=m;++j)
if(!chk[j])
a[j]=!a[j];
p=t,t=tryCombination(a);
if(t==i)
a[s]=!a[s];
b[s]=i,chk[s]=1;
}
answer(a,b);
}
/* Symbol obfuscation */
#define N koala
#define realS kangaroo
#define realD possum
#define inv platypus
#define num_calls echidna
static int N;
static int realS[MAX_N];
static int realD[MAX_N];
static int inv[MAX_N];
static int num_calls;
//exit(0);
}
int init()
{
int i, res;
{
res = scanf("%d", &realD[i]);
inv[realD[i]] = i;
}
num_calls = 0;
return N;
}
int main()
{
auto t1 = clock();
int N;
N = init();
auto t2 = clock();
exploreCave(N);
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0
t3-t2 = 1.791
t4-t3 = 0
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
#include<ctime>
#include <bits/stdc++.h>
void exploreCave(int N)
{
memset(d, -1, sizeof(d));
res = tryCombination(s);
for(int i = 0; i < N; i++)
{
if(res == -1 or res > i) pr = true;
CAPITOLUL 7. IOI 2013 7.2. CAVE 761
else pr = false;
int maxi = N, mini = -1;
while(maxi - mini > 1)
{
int medi = (maxi + mini) / 2;
for (int j = mini + 1; j <= medi; j++)
{
if (c[j]) continue;
s[j] = !s[j];
}
res = tryCombination(s);
if (res == -1 or res > i) dw = true;
else dw = false;
if (dw == pr) mini = medi;
else maxi = medi;
pr = dw;
}
d[maxi] = i;
c[maxi] = true;
if(!dw)
{
s[maxi] = !s[maxi];
res = tryCombination(s);
}
}
answer(s, d);
}
/* Symbol obfuscation */
#define N koala
#define realS kangaroo
#define realD possum
#define inv platypus
#define num_calls echidna
static int N;
static int realS[MAX_N];
static int realD[MAX_N];
static int inv[MAX_N];
static int num_calls;
}
printf("\n");
//exit(0);
}
int init()
{
int i, res;
num_calls = 0;
return N;
}
int main()
{
auto t1 = clock();
int N;
N = init();
auto t2 = clock();
exploreCave(N);
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0
t3-t2 = 1.671
t4-t3 = 0
CAPITOLUL 7. IOI 2013 7.2. CAVE 763
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
#include<ctime>
#include <bits/stdc++.h>
void exploreCave(int N)
{
int n=N;
int R[n+10];
int P[n+10];
int aux2[n+10];
int x,y;
int z=1;
for(int i=0;i<n;i++)
{
R[i]=1;
P[i]=-1;
}
for(int i=0;i<n;i++)
{
for(int l=0;l<n;l++){aux2[l]=R[l];}
int p1=0,p2=n-1;
x=tryCombination(aux2);
z=0;
while(p1!=p2)
{
int p3=(p1+p2)/2;
if(z==1)
{
for(int l=p3+1;l<=p2;l++)
{
if(P[l]==-1)
{
aux2[l]=1;
}
}
}
else
{
for(int l=p1;l<=p3;l++)
{
if(P[l]==-1)
{
aux2[l]=0;
}
}
}
y=tryCombination(aux2);
if(z==1)
{
if((x>=i+1 || x==-1) && (y>=i+1 || y==-1)){p2=p3;z=1;}
else
CAPITOLUL 7. IOI 2013 7.2. CAVE 764
x=y;
}
R[p1]=aux2[p1];P[p1]=i;
}
}
answer(R,P);
}
/* Symbol obfuscation */
#define N koala
#define realS kangaroo
#define realD possum
#define inv platypus
#define num_calls echidna
static int N;
static int realS[MAX_N];
static int realD[MAX_N];
static int inv[MAX_N];
static int num_calls;
//exit(0);
}
int init()
{
int i, res;
num_calls = 0;
return N;
}
int main()
{
auto t1 = clock();
int N;
N = init();
auto t2 = clock();
exploreCave(N);
auto t3 = clock();
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0
t3-t2 = 1.968
t4-t3 = 0
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/random-perm-5000-many-closed.in",
(char*)"cave.out",
(char*)"../tests/random-perm-5000-many-closed.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
7.3 Dreaming
Problema 3 - Dreaming 100 de puncte
Această poveste se petrece cu mult timp ı̂n urmă, atunci când lumea era nouă şi IOI nu fusese
ı̂ncă visat.
Serpent trăieşte ı̂ntr-o lume ı̂n care există N băltoace, numerotate 0, ..., N 1. Există M poteci
bidirecţionale, care unesc perechi de băltoace, pe care Serpent poate călători. Fiecare pereche de
băltoace este conectată (direct sau indirect) de cel mult o secvenţă de poteci, deşi unele perechi
de băltoace pot să nu fie conectate deloc (deci, M & N 1). Fiecare potecă necesită un număr de
zile pentru ca Serpent să o parcurgă: acest număr poate fi diferit pentru fiecare potecă ı̂n parte.
Prietenul lui Serpent, Kangaroo, doreşte să construiască N M 1 noi poteci, astfel ı̂ncât să
fie posibil ca Serpent să călătorească ı̂ntre oricare pereche de băltoace. Kangaroo poate crea poteci
ı̂ntre oricare pereche de băltoace, iar fiecare potecă creată de Kangaroo va dura L zile pentru ca
Serpent să o călătorească.
În plus, Kangaroo doreşte să facă călătoriile lui Serpent pe cât de scurte posibil. Kangaroo va
construi noi poteci astfel ı̂ncât timpul de parcurgere al celui mai lung drum ı̂ntre oricare pereche
de băltoace să fie cât mai mic posibil. Ajutaţi-l pe Kangaroo şi Serpent să determine cel mai lung
timp de călătorie ı̂ntre oricare pereche de băltoace, dupa ce Kangaroo a construit potecile noi ı̂n
stiul descris.
Exemple
CAPITOLUL 7. IOI 2013 7.3. DREAMING 767
În imaginea de mai sus, sunt N 12 băltoace şi M 8 poteci. Presupunând că L 2 atunci
fiecare potecă nouă va fi călătorită de Serpent ı̂n 2 zile. Atunci Kangaroo poate construi trei noi
poteci:
ı̂ntre băltoacele 1 şi 2;
ı̂ntre băltoacele 1 şi 6;
ı̂ntre băltoacele 4 şi 10.
Imaginea de mai sus arată setul final de poteci. Cel mai lung timp de călătorie este de 18 zile,
ı̂ntre băltoacele 0 şi 11. Acesta este cel mai mic rezultat posibil - oricum Kangaroo ar construi
potecile, va exista o pereche de băltoace care să necesite ca Serpent să călătorească 18 zile sau
mai mult.
Implementare
Va trebui să submitaţi un fişier ce implementează functia travelTime(), după cum urmează:
Funcţia voastră: travelTime()
C/C++
Pascal
Descriere
CAPITOLUL 7. IOI 2013 7.3. DREAMING 768
Această funcţie trebuie să calculeze cel mai mare timp de călătorie (măsurat ı̂n zile) ı̂ntre orice
pereche de băltoace, presupunând că Kangaroo a adăugat N M 1 poteci astfel ı̂ncât toate
băltoacele sunt conectate şi timpul maxim de călătorie este cel mai mic posibil.
Parametrii
N : Numărul de băltoace.
M : Numărul de poteci ce există deja.
L: Timpul ı̂n zile care care ı̂i trebuie lui Serpent să călătoarească pe o potecă nouă.
A, B and T : Vectori de lungime M ce specifică capetele şi timpul de parcurgere pentru
fiecare potecă existentă, astfel ı̂ncât a i-a potecă uneşte băltoacele Ai 1 şi B i 1, şi
necesită T i 1 zile pentru a fi călătorită ı̂n orice direcţie.
Returnează: Cel mai mare timp de călătorie ı̂ntre orice pereche de băltoace, aşa cum este
descris mai sus.
Exemplu de scenariu
Următorul scenariu descrie exemplul de mai sus:
Parametru Valoare
N 12
M 8
L 2
A [0, 8, 2, 5, 5, 1, 1, 10]
B [8, 2, 7, 11, 1, 3, 9, 6]
T [4, 2, 4, 3, 7, 1, 5, 3]
Returns 18
Constrângeri
Limită de timp: 1 secundă
Limită de memorie: 64 MiB
1 & N & 100, 000
0&M &N 1
0 & Ai, B i & N 1
1 & T i & 10, 000
1 & L & 10, 000
Subtask-uri
Subtask Puncte Constrângeri suplimentare
1 14 M = N - 2 , şi există exact una sau două poteci pre-existente ce pleacă din
fiecare băltoacă. Cu alte cuvinte, există două seturi de băltoace conectate,
şi in fiecare set potecile formeaza un drum ce nu se desprinde.
2 10 M N 2 şi N 100
3 23 M N 2
4 18 Există cel mult o singură potecă pre-existentă ce pleacă din fiecare băltoacă.
5 12 N & 3, 000
6 23 (Nimic)
Testare
Grader-ul de pe computerul vostru va citi input-ul din fişierul dreaming.in, care trebuie să
fie ı̂n următorul format:
linia 1: N M 4L4
În acest fel, exemplul de mai sus trebuie să fie dat ı̂n următorul format:
12 8 2
0 8 4
8 2 2
2 7 4
5 11 3
5 1 7
CAPITOLUL 7. IOI 2013 7.3. DREAMING 769
1 3 1
1 9 5
10 6 3
Note de limbaj
C/C++: Trebuie să faceţi #include "dreaming.h".
Pascal: Trebuie să definiţi unit Dreaming. Toţi vectorii sunt indexaţi de la 0 (nu de la 1
).
Timp maxim de executare/test: 1.0 secunde
Memorie: total 64 MB
http://blog.brucemerry.org.za/2013/07/ioi-2013-day-1-analysis.html
This is a combination of a few common tree processing tasks. Firstly, the longest path might
just be within one of the original trees, i.e., a tree diameter. This can be computed recursively on
a tree by determining, for each node, the two longest paths downwards via different children (one
or both can be zero if there are fewer than 2 children). The diameter path will have a highest
node, and so the diameter will be the sum of these two lengths.
When add an edge to a tree, we must decide where to make the connection. The longest path
from the connection point to anywhere in the tree ought to be as short as possible, and so for each
point in the tree we need to know the distance to the furthest point. This is slightly more complex
than before, since we also have to consider paths that start upwards. However, a second recursive
walk (this time computing top-down instead of bottom-up) allows the shortest such paths to be
found. For a given tree, let the radius be the distance from the optimal connection point to the
furthest point in the tree.
Finally, we must decide how to connect the trees together. Sort the trees by decreasing radius
r1 ¿ r2 ¿ .... Clearly, there will be a path of at least length r1 + r2 + L. If there at least three
trees, they can’t all be connected to each other, so there must also be a path of at least length r2
+ r3 + 2L. Conversely, by connecting the first tree to every other tree (always using the optimal
connection points), it is not hard to see that there are no other paths that can be longer than the
worst of these.
#include<ctime>
#include<iostream>
#include "dreaming.h"
#include<algorithm>
#include<vector>
int N,M,L;
int Y[100010],tl,inl;
int tmp[100010],Q[100010][3];
int check[100010];
struct line
CAPITOLUL 7. IOI 2013 7.3. DREAMING 770
{
line(){}
line(int en,int len):en(en),len(len){}
int en,len;
};
int far(int x)
{
int fr=1,re=0,ret=x,mx=0;
Q[0][0]=x;
Q[0][1]=0;
check[x]=1;
while(fr!=re)
{
int i;
for(i=0;i<edge[Q[re][0]].size();i++)
{
int tx=edge[Q[re][0]][i].en;
if(check[tx])continue;
check[tx]=1;
Q[fr][0]=tx;
Q[fr][1]=Q[re][1]+edge[Q[re][0]][i].len;
if(mx<Q[fr][1])
{
mx=Q[fr][1];
ret=Q[fr][0];
}
fr++;
}
re++;
}
return ret;
}
void solve(int x)
{
int t=far(x),fr=1,re=0,tp=0;
Q[0][0]=t;
Q[0][1]=0;
Q[0][2]=-1;
check[t]=2;
while(fr!=re)
{
int i;
for(i=0;i<edge[Q[re][0]].size();i++)
{
int tx=edge[Q[re][0]][i].en;
if(check[tx]==2) continue;
check[tx]=2;
Q[fr][0]=tx;
Q[fr][1]=Q[re][1]+edge[Q[re][0]][i].len;
Q[fr][2]=re;
if(Q[fr][1]>Q[tp][1])tp=fr;
fr++;
}
re++;
}
int len=Q[tp][1],tx=0;
while(Q[tp][2]!=-1)
{
if(Q[tp][1]*2>len) tx=Q[tp][1];
else
{
tx=min(tx,len-Q[tp][1]);
break;
}
tp=Q[tp][2];
}
Y[tl]=tx;tl++;
inl=max(inl,len);
}
CAPITOLUL 7. IOI 2013 7.3. DREAMING 771
int travelTime(int Nn, int Mm, int Ll, int A[], int B[], int T[])
{
N=Nn,M=Mm,L=Ll;
int i;
for(i=0;i<M;i++)
{
edge[A[i]+1].push_back(line(B[i]+1,T[i]));
edge[B[i]+1].push_back(line(A[i]+1,T[i]));
}
for(i=1;i<=N;i++)
{
if(check[i])continue;
solve(i);
}
sort(Y,Y+tl);
if(tl==1)return inl;
if(tl==2)
return max(inl,L+Y[tl-1]+Y[tl-2]);
else
return max(inl,max(L+Y[tl-1]+Y[tl-2],2*L+Y[tl-2]+Y[tl-3]));
}
int main()
{
auto t1 = clock();
int N, M, L, i;
int res;
auto t2 = clock();
auto t3 = clock();
printf("%d\n", answer);
auto t4 = clock();
return 0;
}
t4-t3 = 0
#include<ctime>
#include<iostream>
#include "dreaming.h"
#include <stdio.h>
#include <algorithm>
#include <vector>
#define MM 100000
int sta[MM+1],chi[MM*2+1],wei[MM*2+1],nxt[MM*2+1];
int n,m,l,d[2][MM+1],v[2][MM+1],itr;
vector<int> vec;
bool ch[MM+1];
for(i=sta[x];i;i=nxt[i])
{
if(chi[i]!=p)
{
int k=DFS1(chi[i],x)+wei[i];
if(d[0][x]<k)
{
d[1][x]=d[0][x];
v[1][x]=v[0][x];
d[0][x]=k;
v[0][x]=i;
}
else
if(d[1][x]<k)
{
d[1][x]=k;
v[1][x]=i;
}
}
}
return d[0][x];
}
if(d[0][x]<s)
{
d[1][x]=d[0][x];
v[1][x]=v[0][x];
d[0][x]=s;
v[0][x]=-1;
}
else
CAPITOLUL 7. IOI 2013 7.3. DREAMING 773
if(d[1][x]<s)
{
d[1][x]=s;
v[1][x]=-1;
}
ret=d[0][x];
ch[x]=true;
for(i=sta[x];i;i=nxt[i])
{
if(chi[i]!=p)
{
int k;
if(v[0][x]!=i)
{
k=DFS2(chi[i],d[0][x]+wei[i],x);
}
else
{
k=DFS2(chi[i],d[1][x]+wei[i],x);
}
ret=min(ret,k);
}
}
itr=max(itr,d[0][x]+d[1][x]);
return ret;
}
int travelTime(int _n, int _m, int _l, int A[], int B[], int T[])
{
int i;
n=_n;
l=_l;
m=0;
for(i=0;i<_m;i++)
{
addEdge(A[i],B[i],T[i]);
addEdge(B[i],A[i],T[i]);
}
for(i=0;i<n;i++)
{
if(!ch[i])
{
DFS1(i,-1);
vec.push_back(DFS2(i,0,-1));
}
}
int mx1=-1,mx2=-1,mx3=-1;
for(i=0;i<vec.size();i++)
{
if(mx3<vec[i]){mx3=vec[i];}
if(mx2<vec[i]){mx3=mx2;mx2=vec[i];}
if(mx1<vec[i]){mx2=mx1;mx1=vec[i];}
}
if(mx2==-1) return itr;
if(mx3==-1) return max(itr,mx1+mx2+l);
return max(itr,max(mx1+mx2+l,mx2+mx3+l*2));
}
int main()
{
auto t1 = clock();
int N, M, L, i;
int res;
auto t2 = clock();
auto t3 = clock();
printf("%d\n", answer);
auto t4 = clock();
return 0;
}
#include "dreaming.h"
#include <bits/stdc++.h>
#define fi first
#define se second
#define lo long long
#define inf 1000000009
#define md 1000000007
#define li 100005
#define mp make_pair
#define pb push_back
int vis[li],mn,M[li],M2[li],node[li],ss;
vector< pair<int,int> > v[li];
void f(int x)
{
vis[x]=1;
int t;
for(int i=0;i<(int)v[x].size();i++)
{
int go=v[x][i].fi;
CAPITOLUL 7. IOI 2013 7.3. DREAMING 775
int knr=v[x][i].se;
if(vis[go]==1) continue;
f(go);
t=M[go]+knr;
if(M[x]<t)
{
M2[x]=M[x];
M[x]=t;
node[x]=go;
}
else
if(M2[x]<t)
{
M2[x]=t;
}
}
ss=max(ss,M[x]+M2[x]);
}
x=-inf,xx=-inf,xxx=-inf;
for(int i=0;i<n;i++)
{
if(vis[i]==1) continue;
mn=1e9;
f(i);
g(i,-1,0);
if(x<mn)
{
xxx=xx;
xx=x;
x=mn;
}
else
if(xx<mn)
{
xxx=xx;
xx=mn;
}
else
if(xxx<mn)
{
xxx=mn;
}
}
return max(ss,max(x+xx+l,xx+xxx+l+l));
}
} while(0)
int main()
{
auto t1 = clock();
int N, M, L, i;
int res;
auto t2 = clock();
auto t3 = clock();
printf("%d\n", answer);
auto t4 = clock();
return 0;
}
#include "dreaming.h"
#include <bits/stdc++.h>
#define ff first
#define ss second
vector<pii> edge[100005];
int par[100005], X[100005];
bool vis[100005];
{
if (i.ss == p) continue;
auto t = dfs(i.ss, x);
ret = max(ret, pii(t.ff + i.ff, t.ss));
}
X[x] = ret.ff;
par[x] = p;
vis[x] = 1;
return ret;
}
int travelTime(int N, int M, int L, int A[], int B[], int T[])
{
for (int i = 0; i < M; ++i)
{
edge[A[i]].emplace_back(T[i], B[i]);
edge[B[i]].emplace_back(T[i], A[i]);
}
vector<int> vec;
int ans, dia = 0;
for (int i = 0; i < N; ++i)
{
if (vis[i]) continue;
auto t = dfs(dfs(i, i).ss, -1);
int x = t.ss, mn = t.ff;
for (; x >= 0; x = par[x]) mn = min(mn, max(X[x], t.ff - X[x]));
vec.push_back(mn);
dia = max(dia, t.ff);
}
sort(vec.rbegin(), vec.rend());
if (vec.size() > 2)
{
ans = L + vec[0] + vec[1];
for (int i = 2; i < vec.size(); ++i)
ans = max(ans, L + L + vec[1] + vec[i]);
}
else
if (vec.size() == 2) ans = L + vec[0] + vec[1];
else ans = 0;
int main()
{
auto t1 = clock();
int N, M, L, i;
int res;
auto t2 = clock();
CAPITOLUL 7. IOI 2013 7.3. DREAMING 778
auto t3 = clock();
printf("%d\n", answer);
auto t4 = clock();
return 0;
}
#include"dreaming.h"
#include<bits/stdc++.h>
int travelTime(int n, int m, int L, int A[], int B[], int T[])
{
for(int i=0; i<m; i++)
{
adj[A[i]].push_back({T[i], B[i]});
adj[B[i]].push_back({T[i], A[i]});
}
v.push_back(mn);
CAPITOLUL 7. IOI 2013 7.3. DREAMING 779
diameter=max(diameter, rs.first);
}
sort(v.begin(), v.end());
reverse(v.begin(), v.end());
if(v.size()>2)
{
ans=L+v[0]+v[1];
for(int i=2; i<v.size(); i++)
ans=max(ans, 2*L+v[1]+v[i]);
}
else
if(v.size()==2) ans=L+v[0]+v[1];
else ans=0;
ans=max(ans, diameter);
return ans;
}
int main()
{
auto t1 = clock();
int N, M, L, i;
int res;
auto t2 = clock();
auto t3 = clock();
printf("%d\n", answer);
auto t4 = clock();
return 0;
}
*/
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/two-sticks-9.in",
(char*)"dreaming.out",
(char*)"../tests/two-sticks-9.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
7.4 Game
Problema 4 - Game 100 de puncte
Bazza şi Shazza vor să joace un joc. Tabla este un grid de celule, cu R rânduri numerotate 0,
..., R 1 şi C coloane numerotate 0, ..., C 1. Fie p, q celula din rândul p şi coloana q. Fiecare
celulă conţine un ı̂ntreg pozitiv, la ı̂nceputul jocului toate acestea conţinând zero.
Jocul se desfăşoară ı̂n felul următor. ı̂n orice moment, Bazza poate:
să facă un update la celula p, q , schimbând ı̂ntregul pe care ı̂l conţine;
să ı̂i ceară lui Shazza să calculeze cel mai mare divizor comun (CMMDC) al tuturor ı̂ntregilor
dintr-o regiune dreptunghiulară de celule, având colţurile opuse p, q şi u, v (inclusiv aceste
celule).
Bazza va face cel mult NU NQ acţiuni (updatare celule de NU ori şi punere de ı̂ntrebări de
NQ ori) până se plictiseşte şi iese afară ca să se joace cricket.
Voi trebuie să calculaţi răspunsurile corecte.
Exemple
Presupunând că R 2 and C 3, şi Bazza ı̂ncepe cu următoarele update-uri:
Update la celula (0, 0) la valoarea 20;
Update la celula (0, 2) la valoarea 15;
Update la celula (1, 1) la valoarea 12.
CAPITOLUL 7. IOI 2013 7.4. GAME 781
Grid-ul rezultat este afişat ı̂n imaginea de mai sus. Bazza poate să ı̂ntrebe care este CMMDC-ul
următoarelor zone dreptunghiulare:
Colţuri opuse (0, 0) and (0, 2) : cei trei ı̂ntregi din acest dreptunghi sunt 20, 0 şi 15, având
CMMDC-ul 5.
Colţuri opuse (0, 0) and (1, 1) : cei patru ı̂ntregi din acest dreptunghi sunt 20, 0, 0 şi 12,
având CMMDC-ul 4.
Noul grid este afişat ı̂n imaginea de mai sus. Bazza poate ı̂ntreba pentru CMMDC-urile
următoarelor zone dreptunghiulare (din nou):
Colţuri opuse (0, 0) şi (0, 2) : acum cei trei ı̂ntregi ı̂n acest dreptunghi sunt 20, 6 şi 15,
având CMMDC-ul 1.
Colţuri opuse (0, 0) şi (1, 1) : acum cei patru ı̂ntregi din acest dreptunghi sunt 20, 6, 0 şi
14, având CMMDC-ul 2.
K: Valoarea nouă care va fi conţinută de celula din grid ( 0 & K & 1018 ). Poate fi la fel ca
valoarea curentă.
Exemplu
Aici aveţi descris exemplul de mai sus:
Apelul Funcţiei Returnează
init(2, 3)
update(0, 0, 20)
update(0, 2, 15)
update(1, 1, 12)
calculate(0, 0, 0, 2) 5
calculate(0, 0, 1, 1) 4
update(0, 1, 6)
update(1, 1, 14)
calculate(0, 0, 0, 2) 1
calculate(0, 0, 1, 1) 2
Constrângeri
Limită de timp: vezi subtask-uri
Limită de memorie: vezi subtask-uri
1 & R, C & 10
9
0 & K & 10 , unde K este un ı̂ntreg pe care Bazza ı̂l plasează ı̂n grid.
18
Subtask-uri
Vezi versiunea in engleză pentru parametrii subtask-urilor.
Testare
Graderul de pe computerul vostru va citi input din fişierul game.in. Acest fişier trebuie să
aibă următorul format:
CAPITOLUL 7. IOI 2013 7.4. GAME 783
linia 1: R C N
următoarele N linii: o acţiune pe linie, ı̂n ordinea ı̂n care apar
Linia pentru fiecare acţiune trebuie să fie una dintre următoarele formate:
indică update(P, Q, K): 1 P Q K
indică calculate(P, Q, U, V): 2 P Q U V
Note de limbaj
C/C++ Trebuie să faceţi #include "game.h".
Pascal Trebuie sa definiţi unit Game. Toţi vectorii sunt indexaţi incepând de la 0 (nu de la
1).
Deoarece ı̂ntregii din grid pot fi foarte mari, utilizatorii C/C++ sunt sfătuiţi să folosească tipul
de date long long, şi utilizatorii Pascal sunt sfătuiţi să folosească tipul de date Int64.
Timp maxim de executare/test: 13.0 secunde
Memorie: total 230 MB
http://blog.brucemerry.org.za/2013/07/ioi-2013-day-2-analysis.html
I disliked this problem because it has a nice solution that takes just a bit too much memory. I
only managed to get 80% for it in the time I spent on it, and I didn’t feel inspired to modify my
solution to pass fully.
In 1D, this can be solved by a fairly straightforward use of a segment tree: each node stores
the GCD of its two children. Since R can be quite big, this needs to be a sparse segment tree;
another alternative would be a balanced binary tree.
In 2D, it is tempting to use a quadtree, but in fact that doesn’t guarantee poly-logarithmic
time. A 1 C query will force refinement down to the individual non-zero cell entries. Instead,
we can use a range tree, which is a tree of trees: an outer tree is built over the columns, and for
each column span corresponding to a node in this tree, we have an inner tree over the rows. Each
node in this inner tree corresponds to a rectangle of the grid, and stores the GCD of elements
from this rectangle. A query now uses the columns to select O log C nodes from the outer tree
i.e., O log C inner trees, and applies a query to each of them. Queries thus take O log R log C
time when the implementation uses segment trees for the inner and outer trees. With balanced
2
binary trees, it would only be O log N u .
Unfortunately, using segment trees also requires O log R log C memory per non-zero element,
which just exceeds the available memory. Using balanced binary trees instead should fit within
memory, but is a lot more painful to implement. I think it might also be possible to make it work
by sticking with segment trees, but compressing the representation by compacting chains of nodes
with one child.
CAPITOLUL 7. IOI 2013 7.4. GAME 784
#include <stdio.h>
#include <stdlib.h>
#include "game.h"
#include<bits/stdc++.h>
#include "game.h"
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
struct node
{
node *l, *r;
int pos, key, mn, mx;
long long val, g;
node(int position, long long value)
{
l = r = nullptr;
mn = mx = pos = position;
key = rnd();
val = g = value;
}
void pull()
{
g = val;
if(l) g = __gcd(g, l->g);
if(r) g = __gcd(g, r->g);
mn = (l ? l->mn : pos);
mx = (r ? r->mx : pos);
}
};
//memory O(n)
struct treap
{
node *root;
treap()
{
root = nullptr;
}
{
if (!l || !r) return l ? l : r;
if (l->key < r->key)
{
l->r = merge(l->r, r);
l->pull();
return l;
}
r->l = merge(l, r->l);
r->pull();
return r;
}
long long query(int l, int r) //gcd of a_i such that l <= i <= r
{
if (!root) return 0;
return query(root, l, r);
}
{
ST *l, *r;
treap t;
int b, e;
ST()
{
l = r = nullptr;
}
if (b != e)
{
if (x <= (b + e) / 2)
{
if (!l) l = new ST(b, (b + e) / 2);
l->upd(x, y, val);
}
else
{
if (!r) r = new ST((b + e) / 2 + 1, e);
r->upd(x, y, val);
}
}
fix(y);
}
long long query(int i, int j, int st, int en) //gcd of a[x][y]
// such that i <= x <= j && st <= y <= en
{
if (e < i || j < b) return 0;
if (i <= b && e <= j) return t.query(st, en);
long long ans = 0;
if (l) ans = __gcd(ans, l->query(i, j, st, en));
if (r) ans = __gcd(ans, r->query(i, j, st, en));
return ans;
}
};
int r, c, q;
ST t;
{
return t.query(P, U, Q, V);
}
int main()
{
auto t1 = clock();
int R, C, N;
int P, Q, U, V;
long long K;
int i, type;
int res;
if (res != 1)
fail("Failed to read R from input file.");
if (R < 1 || R > MAX_SIZE)
fail("R is out of bounds.");
if (res != 1)
fail("Failed to read C from input file.");
if (C < 1 || C > MAX_SIZE)
fail("C is out of bounds.");
if (res != 1)
fail("Failed to read N from input file.");
if (N < 0 || N > MAX_N)
fail("N is out of bounds.");
auto t2 = clock();
init(R, C);
auto t3 = clock();
if (type == 1)
{
res = scanf("%d%d%lld", &P, &Q, &K);
update(P, Q, K);
}
else
if (type == 2)
{
res = scanf("%d%d%d%d", &P, &Q, &U, &V);
auto t4 = clock();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include "game.h"
#include<ctime>
#include<iostream>
#include <assert.h>
#include <stddef.h>
struct layer2_node
{
layer2_node(int low, int high)
: low(low), high(high), lft(NULL), rht(NULL), value(0LL) { }
int low;
int high;
layer2_node* lft;
layer2_node* rht;
long long value;
};
struct layer1_node
{
layer1_node() : lft(NULL), rht(NULL), l2(0, MAXC) { }
layer1_node* lft;
CAPITOLUL 7. IOI 2013 7.4. GAME 789
layer1_node* rht;
layer2_node l2;
};
update2(nnode, Q, K);
}
if(low + 1 == high)
{
update2(&node->l2, Q, K);
}
else
{
layer1_node*& nnode = P < mid ? node->lft : node->rht;
(P < mid ? high : low) = mid;
if(nnode == NULL)
{
nnode = new layer1_node();
}
update1(nnode, low, high, P, Q, K);
int main()
{
auto t1 = clock();
CAPITOLUL 7. IOI 2013 7.4. GAME 791
int R, C, N;
int P, Q, U, V;
long long K;
int i, type;
int res;
if (res != 1)
fail("Failed to read R from input file.");
if (R < 1 || R > MAX_SIZE)
fail("R is out of bounds.");
if (res != 1)
fail("Failed to read C from input file.");
if (C < 1 || C > MAX_SIZE)
fail("C is out of bounds.");
if (res != 1)
fail("Failed to read N from input file.");
if (N < 0 || N > MAX_N)
fail("N is out of bounds.");
auto t2 = clock();
init(R, C);
auto t3 = clock();
if (type == 1)
{
res = scanf("%d%d%lld", &P, &Q, &K);
update(P, Q, K);
}
else
if (type == 2)
{
res = scanf("%d%d%d%d", &P, &Q, &U, &V);
auto t4 = clock();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include "game.h"
#include <bits/stdc++.h>
struct node2
{
int l, r;
long long v;
node2 *L, *R;
node2(int a, int b)
{
l = a, r = b;
v = 0;
L = R = NULL;
}
};
struct node1
{
int l, r;
node2 *now;
node1 *L, *R;
node1(int a, int b)
{
l = a, r = b;
now = new node2(1, _C);
L = R = NULL;
}
};
node1 *root;
int main()
{
auto t1 = clock();
CAPITOLUL 7. IOI 2013 7.4. GAME 794
int R, C, N;
int P, Q, U, V;
long long K;
int i, type;
int res;
if (res != 1)
fail("Failed to read R from input file.");
if (R < 1 || R > MAX_SIZE)
fail("R is out of bounds.");
if (res != 1)
fail("Failed to read C from input file.");
if (C < 1 || C > MAX_SIZE)
fail("C is out of bounds.");
if (res != 1)
fail("Failed to read N from input file.");
if (N < 0 || N > MAX_N)
fail("N is out of bounds.");
auto t2 = clock();
init(R, C);
auto t3 = clock();
if (type == 1)
{
res = scanf("%d%d%lld", &P, &Q, &K);
update(P, Q, K);
}
else
if (type == 2)
{
res = scanf("%d%d%d%d", &P, &Q, &U, &V);
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/05.st-4-random-1.in",
(char*)"game.out",
(char*)"../tests/05.st-4-random-1.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
7.5 Robots
Problema 5 - Robots 100 de puncte
Frăţiorul Maritei şi-a lăsat jucăriile peste tot pe podeaua din sufragerie. Din fericire, Marita
a construit roboţi speciali pentru a strânge jucăriile. Ea are nevoie de ajutorul vostru pentru a
determina care roboţi ar trebui să culeagă jucăriile.
Există T jucării, fiecare cu o greutate - număr ı̂ntreg W i şi o dimensiune - număr ı̂ntreg
S i. Roboţii sunt de două tipuri: weak şi small.
Există A roboţi weak. Fiecare robot weak are o greutate limită X i, şi poate să care orice
jucărie cu greutatea strict mai mică decât X i. Dimensiunea jucăriei nu contează.
Există B roboţi small . Fiecare robot small are o dimensiune limită Y[i], şi poate să care
jucării cu dimensiunea strict mai mică decât Y i. Greutatea jucăriei nu contează.
Oricare robot al Maritei poate să culeagă exact o jucarie pe minut. Roboţi diferiţi pot căra
jucării diferite ı̂n acelaşi timp.
Sarcina voastră este să determinaţi dacă roboţii Maritei pot culege toate jucăriile şi ı̂n caz
afirmativ care este timpul minim in care acestea pot fi culese.
Exemple
Ca un prim exemplu, presupunem că există A 3 roboţi weak cu greutatea limită X 6, 2, 9,
B 2 roboţi small cu dimensiunea limită Y 4, 7, şi T 10 jucării după cum urmează:
Număr de jucării 0 1 2 3 4 5 6 7 8 9
Greutăţi 4 8 2 7 1 5 3 8 7 10
Dimensiuni 6 5 3 9 8 1 3 7 6 5
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 796
Cel mai scurt timp pentru a culege toate jucăriile este de trei minute:
Robotul Robotul Robotul Robotul Robotul
Weak 0 Weak 1 Weak 2 Small 0 Small 1
Primul minut Jucăria 0 Jucăria 4 Jucăria 1 Jucăria 6 Jucăria 2
Al doilea minut Jucăria 5 Jucăria 3 Jucăria 8
Al treilea minut Jucăria 7 Jucăria 9
Ca un al doilea exemplu, presupunem că există A 2 roboţi weak cu greutatea limită X
2, 5, B 1 robot small cu dimensiunea limită Y 2, şi T 3 jucării după cum urmează:
Număr jucărie 0 1 2
Greutăţi 3 5 2
Dimensiuni 1 3 2
Niciun robot nu poate culege jucăria de greutate 5 si dimensiune 3 deci este imposibil ca roboţii
să culeaga toate jucăriile.
Implementare
Trebuie să submitaţi un fişier care implementează funcţia putaway() după cum urmează:
Funcţia voastră: putaway()
C/C++
Pascal
Descriere
Această funcţie trebuie să returneze cel mai mic număr de minute necesar pentru ca roboţii să
culeagă toate jucăriile , sau să returneze -1 dacă acest lucru nu este posibil.
Parametri
A: Numărul de roboţi weak.
B: Numărul de roboţi small.
T: Numărul de jucării.
X: Un vector de ı̂ntregi de lungime A conţinând greutăţile limită pentru fiecare robot weak.
Y: Un vector de ı̂ntregi de lungime B conţinând dimensiunile limită pentru fiecare robot
small.
W: Un vector de ı̂ntregi de lungime T conţinând greutatea fiecărei jucării.
S: Un vector de ı̂ntregi de lungime T conţinând dimensiunea fiecărei jucării.
Returnează: Cel mai mic număr de minute ı̂n care se pot culege toate jucăriile sau -1 dacă
jucăriile nu pot fi culese.
Exemple
Aici aveţi descris primul exemplu:
Parametri Valori
A 3
B 2
T 10
X [6, 2, 9]
Y [4, 7]
W [4, 8, 2, 7, 1, 5, 3, 8, 7, 10]
S [6, 5, 3, 9, 8, 1, 3, 7, 6, 5]
Valoare returnată 3
Aici aveţi descris al doilea exemplu
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 797
Parametri Valori
A 2
B 1
T 3
X [2, 5]
Y [2]
W [3, 5, 2]
S [1, 3, 2]
Valoare returnată 1
Restricţii
Limită de timp: 3 secunde
Limită de memorie limit: 64 MiB
1 & T & 1, 000, 000
0 & A, B & 50, 000 şi 1 & A B
1 & X i, Y i, W i, S i & 2, 000, 000, 000
Subtask-uri
Subtask Puncte Restricţii suplimentare
1 14 T 2 şi A B 2 (Exact două jucării şi doi roboţi)
2 14 B 0 (toţi roboţii sunt weak)
3 25 T & 50, şi A B & 50
4 37 T & 10, 000 şi A B & 1, 000
5 10 (Niciuna)
Testare
Graderul de pe calculatorul vostru va citi datele de intrare din fişierul robots.in, care trebuie
să aibă următorul format:
linia 1: A B T
linia 2: X 0 ... X A 1
linia 3: Y 0 ... Y B 1
următoarele T linii: W i S i
Astfel, primul exemplu prezentat ar trebui sa primească datele de intrare in următorul format
3 2 10
6 2 9
4 7
4 6
8 5
2 3
7 9
1 8
5 1
3 3
8 7
7 6
10 5
http://blog.brucemerry.org.za/2013/07/ioi-2013-day-2-analysis.html
As is commonly the case for problems that ask how long some agents need to achieve a goal,
the answer can be found by a binary search on the answer. So we need to decide whether the
robots can clear the floor in S seconds.
We can simplify the problem slightly by noting that for each toy, we only need to know how
many weak and how many small robots are able to move it, which can be found by binary searching
the two lists (after sorting them). Of course, if a toy cannot be moved by any robot, return -1.
Let’s first decide the actions of the weak robots, starting from the weakest. There will be some
set of toys it can handle. Since they effectively differ only in size, the weakest robot should work
from the largest downwards, so as to make the job of the small robots easier. Also, there is never
any reason for it to move fewer than S toys, unless it runs out. Now consider the 2nd-weakest
robot. There will be extra toys it can handle, plus any light toys that the weakest robot didn’t
have time for. Since the weakest robot is finished, the difference in weights are irrelevant, and the
2nd-weakest robot should again work in decreasing order of size amongst the toys it can handle.
The same process can be continued for the remaining weak robots.
Now consider the small robots, from largest to smallest. These can again take up to S toys,
starting from the largest remaining one. If a robot is unable to handle the largest remaining toy,
then S was too small.
Implementation can be done using a priority queue, implemented as a binary heap, representing
toys that are light enough to be handled by the current robot and ordered with the largest at the
head. The toys are initially sorted by weight. Each time a new weak robot is considered, new
elements are added from the list of toys to the priority queue, and the robot then removes items
starting from the head of the queue.
2
Assuming that T is larger than A, B, the running time will be O T log T : one log T for
the binary search, the other for the priority queue operations. I think that it may be possible to
reduce this to something like O T log T log max A, B using the right sort of data structure
for the priority queue (to allow S items to be removed in log time): something like an interval
tree for the number of toys of each size.
#include <stdio.h>
#include <stdlib.h>
#include "robots.h"
#include<ctime>
#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
int V[1000000];
std::pair<int,int> D[1000000];
int R[50000];
std::vector<int> E[50000];
int putaway(int A, int B, int T, int X[], int Y[], int W[], int S[])
{
int i,j,l,r,mid;
for(i=0;i<T;i++)
{
D[i].first=W[i]+1;
D[i].second=S[i]+1;
}
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 799
std::sort(X,X+A);
std::sort(Y,Y+B);
std::sort(D,D+T);
for(i=0;i<T;i++)
if((!A||D[i].first>X[A-1])&&(!B||D[i].second>Y[B-1]))
return -1;
l=1;
r=T;
while(l<r)
{
mid=(l+r)/2;
for(i=0;i<T;i++)V[i]=0;
for(i=0;i<B;i++)E[i].clear();
for(i=0;i<T;i++)
{
j=std::lower_bound(Y,Y+B,D[i].second)-Y;
if(j<B)E[j].push_back(i);
}
j=0;
for(i=B-1;i>=0;i--)
{
j+=mid;
if(j>2e9)j=2e9;
while(j>0&&E[i].size())
{
V[E[i][E[i].size()-1]]=1;
E[i].pop_back();
j--;
}
}
for(i=0;i<A;i++)R[i]=0;
j=0;
for(i=0;i<T;i++)if(!V[i])
{
while(j<A&&(X[j]<D[i].first||R[j]==mid))j++;
if(j<A)
{
V[i]=1;
R[j]++;
}
else break;
}
if(i==T)r=mid;
else l=mid+1;
}
return r;
}
int main()
{
auto t1 = clock();
int A, B, T, i;
int res;
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 800
auto t2 = clock();
auto t3 = clock();
printf("%d\n", answer);
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.515
t3-t2 = 8.761
t4-t3 = 0
argc = 4
checker
../tests/st5-random-highS-highW-clusters.in
robot.out
../tests/st5-random-highS-highW-clusters.out
----------------------
1
Correct
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 801
#include <stdio.h>
#include <stdlib.h>
#include "robots.h"
#include<ctime>
#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
int V[1000000];
std::pair<int,int> D[1000000];
int R[50000];
std::vector<int> E[50000];
int putaway(int A, int B, int T, int X[], int Y[], int W[], int S[])
{
int i,j,k,l,r,mid;
for(i=0;i<T;i++)
{
D[i].first=W[i]+1;
D[i].second=S[i]+1;
}
std::sort(X,X+A);
std::sort(Y,Y+B);
std::sort(D,D+T);
for(i=0;i<T;i++)
if((!A||D[i].first>X[A-1])&&(!B||D[i].second>Y[B-1]))
return -1;
for(i=0;i<B;i++)E[i].clear();
for(i=0;i<T;i++)
{
j=std::lower_bound(Y,Y+B,D[i].second)-Y;
if(j<B)E[j].push_back(i);
}
l=1;
r=T;
while(l<r)
{
mid=(l+r)/2;
for(i=0;i<T;i++)V[i]=0;
j=0;
for(i=B-1;i>=0;i--)
{
j+=mid;
if(j>2e9)j=2e9;
for(k=E[i].size()-1;k>=0&&j>0;k--)
{
V[E[i][k]]=1;
j--;
}
}
for(i=0;i<A;i++)R[i]=0;
j=0;
for(i=0;i<T;i++)if(!V[i])
{
while(j<A&&(X[j]<D[i].first||R[j]==mid))j++;
if(j<A)
{
V[i]=1;
R[j]++;
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 802
}
else break;
}
if(i==T)r=mid;
else l=mid+1;
}
return r;
}
int main()
{
auto t1 = clock();
int A, B, T, i;
int res;
auto t2 = clock();
auto t3 = clock();
printf("%d\n", answer);
auto t4 = clock();
return 0;
}
/*
t2-t1 = 0.531
t3-t2 = 1.453
t4-t3 = 0
argc = 4
checker
../tests/st5-random-highS-highW-clusters.in
robot.out
../tests/st5-random-highS-highW-clusters.out
----------------------
1
Correct
#include <bits/stdc++.h>
#include "robots.h"
int n;
int A, B;
int X[N], Y[N];
ii a[N];
int id[N], root[N], sizev[N];
int dsu(int x)
{
if(x == root[x])
return x;
return root[x] = dsu(root[x]);
}
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 804
bool f(int x)
{
v.clear();
for(int i = 0; i <= A; i++)
{
root[i] = i;
sizev[i] = x;
}
int ptr = 0;
for(int i = B - 1; i >= 0; i--)
{
int rem = x;
while(ptr < v.size() and rem and Y[i] > v[ptr])
{
rem--;
ptr++;
}
}
return ptr == v.size();
}
int putaway(int A, int B, int n, int X[], int Y[], int W[], int S[])
{
:: n = n;
:: A = A;
:: B = B;
sort(X, X + A);
sort(Y, Y + B);
sort(a, a + n);
if(!f(n))
return -1;
int l = 1, r = n;
while(l < r)
{
int m = l + r >> 1;
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 805
if(f(m))
r = m;
else
l = m + 1;
}
return l;
}
int main()
{
auto t1 = clock();
int A, B, T, i;
int res;
auto t2 = clock();
auto t3 = clock();
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 806
printf("%d\n", answer);
auto t4 = clock();
return 0;
}
/*
t2-t1 = 2.005
t3-t2 = 1.218
t4-t3 = 0
argc = 4
checker
../tests/st5-random-highS-highW-clusters.in
robot.out
../tests/st5-random-highS-highW-clusters.out
----------------------
1
Correct
#include "robots.h"
#include <bits/stdc++.h>
vector<pair<int,int>> tw,ts,w;
int t;
bool used[maxt];
}
else
{
int cur = w[x].first;
int use = 0;
while(use < md && i < t && cur > tw[i].first)
{
if(used[tw[i].second])
{
i++;
continue;
}
used[tw[i].second] = 1;
i++;
use++;
}
}
}
for(int x=0;x<t;x++)
if(!used[x])
return 0;
return 1;
}
int putaway(int A, int B, int T, int X[], int Y[], int W[], int S[])
{
t = T;
for(int i=0;i<A;i++)w.push_back({X[i],0});
for(int i=0;i<B;i++)w.push_back({Y[i],1});
for(int i=0;i<T;i++)tw.push_back({W[i],i});
for(int i=0;i<T;i++)ts.push_back({S[i],i});
sort(w.begin(),w.end());
sort(tw.begin(),tw.end());
sort(ts.begin(),ts.end());
int md,lo=0,hi=T,ans=-1;
while(lo <= hi)
{
md = (lo+hi)/2;
if(can(md))
{
ans = md;
hi = md-1;
}
else
lo = md+1;
}
return ans;
}
int main()
{
auto t1 = clock();
int A, B, T, i;
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 808
int res;
auto t2 = clock();
auto t3 = clock();
printf("%d\n", answer);
auto t4 = clock();
return 0;
}
/*
t2-t1 = 2
t3-t2 = 2.453
t4-t3 = 0
argc = 4
checker
../tests/st5-random-highS-highW-clusters.in
robot.out
../tests/st5-random-highS-highW-clusters.out
----------------------
1
Correct
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 809
#include "robots.h"
#include <bits/stdc++.h>
vector<pair<int,int>> tw,ts,w;
int t;
bool used[maxt];
for(int x=0;x<t;x++)
if(!used[x])
return 0;
return 1;
}
int putaway(int A, int B, int T, int X[], int Y[], int W[], int S[])
{
t = T;
for(int i=0;i<A;i++)w.push_back({X[i],0});
for(int i=0;i<B;i++)w.push_back({Y[i],1});
for(int i=0;i<T;i++)tw.push_back({W[i],i});
for(int i=0;i<T;i++)ts.push_back({S[i],i});
CAPITOLUL 7. IOI 2013 7.5. ROBOTS 810
sort(w.begin(),w.end());
sort(tw.begin(),tw.end());
sort(ts.begin(),ts.end());
int md,lo=0,hi=T,ans=-1;
while(lo <= hi)
{
md = (lo+hi)/2;
if(can(md))
{
ans = md;
hi = md-1;
}
else
lo = md+1;
}
return ans;
}
int main()
{
auto t1 = clock();
int A, B, T, i;
int res;
{
res = scanf("%d%d", &W[i], &S[i]);
auto t2 = clock();
auto t3 = clock();
printf("%d\n", answer);
auto t4 = clock();
return 0;
}
/*
t2-t1 = 2
t3-t2 = 2.453
t4-t3 = 0
argc = 4
checker
../tests/st5-random-highS-highW-clusters.in
robot.out
../tests/st5-random-highS-highW-clusters.out
----------------------
1
Correct
7.6 Wombats
Problema 6 - Wombats 100 de puncte
Oraşul Brisbane a fost preluat de wombaţi mutanţi uriaşi şi voi trebuie să conduceţi oamenii
zona sigură.
Străzile din Brisbane formează un grid. Există R străzi orizontale care merg de la est la vest,
numerotate cu 0, ..., R 1 ı̂n ordine de la nord la sud şi C străzi verticale care merg de la nord
la sud, numerotate cu 0, ..., C 1 de la vest la est, ca in figura urmatoare.
CAPITOLUL 7. IOI 2013 7.6. WOMBATS 812
Wombaţii au invadat din nord şi oameni scapă prin sud. Oamenii pot fugi pe străzile orizontale
ı̂n ambele direcţii, dar pe străzile verticale ei vor putea fugi doar spre sud, spre zona sigură.
Intersecţia străzii orizontale P cu strada verticală Q este notată P, Q. Fiecare segment de
stradă dintre două intersecţii conţine un număr de wombaţi şi aceste numere se pot schimba ı̂n
timp.
Vi se cere să conduceţi anumite persoane din anumite intersecţii date din nord (de pe strada
orizontală 0) la anumite intersecţii din sud (pe strada orizontală R 1), folosind o rută care conţine
cât mai puţini wombaţi posibil.
Iniţial veţi primi dimensiunea gridului şi numărul de wombaţi de pe fiecare segment de stradă.
ı̂n continuare veţi primi o serie de E evenimente din unul din următoarele două tipuri:
change, care modifică numărul de wombaţi pe un anumit segment de strada
escape, prin care o anumită persoană soseşte la o amunită intersecţie dată de pe strada
orizontală 0 şi trebuie să găsiţi un traseu până la o anumită intersecţie dată de pe linia R 1
şi trece peste cât mai puţini wombaţi posibil.
O a treia persoană soseşte ı̂n A 0, 2 şi doreşte să scape la intersecţia B 2, 1. Acum
numărul minim de wombaţi cu care se ı̂ntâlneşte este 5, cum este indicat de linia punctată.
CAPITOLUL 7. IOI 2013 7.6. WOMBATS 813
Implementare
Va trebui sa submitaţi un fişier implementând procedurile init(), changeH() şi
changeV() şi funcţia escape(), după cum urmează:
Procedura vostră: init()
C/C++
Pascal
Descriere
Această procedură vă dă configuraţia iniţiala a hărţii, şi vă permite să iniţializaţi eventualele
variabile globale şi structuri de date. Va fi apelată o singură dată, ı̂nainte de orice apel către
changeH(), changeV() sau escape().
Parametrii
R : Numărul de drumuri orizontale.
C : Numărul de drumuri verticale.
H : Array bidimensional de dimensiune R C 1, unde H P Q vă dă numarul de
wombaţi de pe segmentul de drum orizontal din dintre intersecţiile P, Q şi P, Q 1.
V : Array bidimensional de dimensiune R 1 C, unde V P Q vă dă numărul de
wombaţi de pe segmentul de drum vertical dintre intersecţiile P, Q şi P 1, Q.
Pascal
procedure changeH(P, Q, W: LongInt);
Descriere
Acestă procedură va fi apelată atunci când numărul de wombaţi se modifică pe segmentul
orizontal dintre intersecţiile (P, Q) şi (P, Q + 1).
Parametrii
P : Indică care drum orizontal este afectat ( 0 P R - 1 ).
Q : Indică ı̂ntre care două drumuri verticale se află segmentul ( 0 Q C - 2 ).
Pascal
Descriere
Acestă procedură va fi apelată când numărul de wombaţi se modifică pe pe segmentul de drum
vertical dintre intersecţiile (P, Q) şi (P + 1, Q).
Parametrii
CAPITOLUL 7. IOI 2013 7.6. WOMBATS 814
Pascal
Descriere
Acestă funcţie trebuie să calculeze numărul minim de wombaţi pe care o persoană ı̂i va ı̂ntâlni
atunci când călătoreşte de la intersecţia (0, V1) la (R-1, V2).
Parametrii
V1 : Indică unde o persoană ı̂ncepe pe rândul orizontal 0 ( 0 V1 C-1 ).
V2 : Indică unde o persoana sfârşeşte pe rândul orizontal R-1 ( 0 V2 C-1 ).
Returnează: Numărul minim de wombaţi pe care persoana va fi necesar să ı̂i ı̂ntâlnească.
Exemplu de Sesiune
Următorul scenariu descrie exemplul de mai sus:
Function Call Returns
init(3, 4, [[0,2,5], [7,1,1], [0,4,0]], [[0,0,0,2], [0,3,4,7]])
escape(2,1) 2
escape(3,3) 7
changeV(0,0,5)
changeH(1,1,6)
escape(2,1) 5
Constrângeri
Limită de timp: 20 secunde
Limită de memorie: 256 MiB
2 & R & 5 000
1 & C & 200
Cel mult 500 de schimbări (apeluri la changeH() sau changeV())
Cel mult 200 000 apeluri către escape()
Cel mult 1 000 wombaţi pe fiecare segment ı̂n orice moment.
Subtaskuri
Subtask Punctaje Constrângeri Adiţionale a Inputului
1 9 C 1
2 12 R, C & 20, şi nu vor fi apeluri către changeH() sau changeV()
3 16 R, C & 100, şi vor fi cel mult 100 de apeluri către escape()
4 18 C 2
5 21 C & 100
6 24 (None)
Testare
Graderul de pe computerul vostru va citi input din fişierul wombats.in, care va fi ı̂n următorul
format:
linia 1: R C
linia 2: H 00 ... H 0C 2
...
linia R 1: H R 10...H R 1C 2
linia R 2: V 00...V 0C 1
CAPITOLUL 7. IOI 2013 7.6. WOMBATS 815
...
linia 2R: V R 20...V R 2C 1
următoarea linie: E
următoarele E linii: un eveniment pe linie, ı̂n ordinea ı̂n care apar
Dacă C 1, liniile goale conţinând numărul de wombaţi pe drumurile orizontale (liniile 2 ...
R 1) nu sunt necesare.
Linia fiecărui eveniment trebuie să fie ı̂n una din formatele:
pentru a indica changeH(P, Q, W): 1 P Q W
pentru a indica changeV(P, Q, W): 2 P Q W
pentru a indica escape(V1, V2): 3 V 1 V 2
În acest fel, exemplul de mai sus trebuie să fie dat ı̂n următorul format:
3 4
0 2 5
7 1 1
0 4 0
0 0 0 2
0 3 4 7
5
3 2 1
3 3 3
2 0 0 5
1 1 1 6
3 2 1
Note de limbaj
C/C++ Trebuie să faceţi #include "wombats.h".
Pascal Trebuie să definiţi unit Wombats. Toţi vectorii sunt indexaţi de la 0 (nu de la 1).
Vedeţi template-urile de soluţii de pe calculatoarele voastre pentru exemple.
Timp maxim de executare/test: 20.0 secunde
Memorie: total 256 MB
http://blog.brucemerry.org.za/2013/07/ioi-2013-day-1-analysis.html
I found this to be the most difficult of the tasks. Apart from being conceptually difficult, it
also required a reasonably amount of tuning, and my solution still takes over 10s in many cases.
The basis of the solution is to note that C is relatively small, and so it is feasible to precompute
the costs to get from any point on row X to any point on row Y , for some X and Y . Let’s write
such a table as rX, Y x. What’s less obvious is that it’s possible to combine rX, Y x and rY, Z x to
2
produce rX, Z x in O C time. The trick is to use the fact that optimal paths won’t cross over
each other. Thus, if i $ j, X, i to Z, j 1 goes via Y, p, and X, i 1 to Z, j goes via
Y, q , then the optimal path from X, i to Z, j will go via Y, r where p & r & q. By iterating
in order of increasing j i, it is possible to compute rX, Z x in quadratic time.
We can combine this observation with a segment tree: for each appropriate i and a, we maintain
ra 2i, a 1 2ix, computing it either directly (i 0) or by combining two smaller intervals as
above (where the upper bound exceeds R 1, it is clamped). Each change invalidates O log R of
2
these, so the time to update after a change is O C logR. Queries can be answered in O 1 time
using the root of the segment tree.
The catch with this approach is that it requires too much memory: we can’t even afford R
different rX, Y x tables. Instead of keeping rX, X 1x at the finest level of the segment tree, we
can instead store, say, r10X, 10X 10x for each X, and use 1/10th the memory. The cost is that
updating the base level of the segment tree will now take 10 times as long.
CAPITOLUL 7. IOI 2013 7.6. WOMBATS 816
#include "wombats.h"
#include <bits/stdc++.h>
void upd(int l1, int r1, int i=1, int l2=0, int r2=bc-1)
{
if(l2==r2)
{
memset(st[i], 0x3f, sizeof(st[i]));
for(int j=0; j<c; ++j)
{
st[i][j][j]=0;
for(int k=l2*bs; k<(l2+1)*bs; ++k)
{
for(int l=1; l<c; ++l)
st[i][j][l]=min(st[i][j][l-1]+h[k][l-1],st[i][j][l]);
for(int l=c-1; l; --l)
st[i][j][l-1]=min(st[i][j][l]+h[k][l-1],st[i][j][l-1]);
for(int l=0; l<c; ++l)
st[i][j][l]+=v[k][l];
}
}
return;
}
int m2=(l2+r2)/2;
if(l1<=m2)
upd(l1, r1, 2*i, l2, m2);
if(m2<r1)
upd(l1, r1, 2*i+1, m2+1, r2);
memset(o, 0, 4*c);
for(int j1=0; j1<c; ++j1)
{
for(int j2=c-1; ˜j2; --j2)
{
array<int, 2> d{INT_MAX, 0};
for(int k=o[j2]; k<=o[j2+1]; ++k)
d=min(array<int,2>{st[2*i][j1][k]+st[2*i+1][k][j2], -k},d);
st[i][j1][j2]=d[0];
o[j2]=-d[1];
}
}
}
int main()
{
auto t1 = clock();
std::freopen("../tests/100x100-bottom-changes-many-queries.in","r",stdin);
std::freopen("wombats.out", "w", stdout);
auto t2 = clock();
init(R, C, H, V);
auto t3 = clock();
if (event == 1)
{
res = scanf("%d%d%d", &P, &Q, &W);
changeH(P, Q, W);
}
else
if (event == 2)
{
res = scanf("%d%d%d", &P, &Q, &W);
changeV(P, Q, W);
}
else
if (event == 3)
{
res = scanf("%d%d", &V1, &V2);
auto t4 = clock();
return 0;
}
void upd(int l1, int r1, int i=1, int l2=0, int r2=bc-1)
{
if(l2==r2)
{
memset(st[i], 0x3f, sizeof(st[i]));
for(int j=0; j<c; ++j)
{
st[i][j][j]=0;
for(int k=l2*bs; k<(l2+1)*bs; ++k)
{
for(int l=1; l<c; ++l)
st[i][j][l]=min(st[i][j][l-1]+h[k][l-1],st[i][j][l]);
for(int l=c-1; l; --l)
st[i][j][l-1]=min(st[i][j][l]+h[k][l-1],st[i][j][l-1]);
for(int l=0; l<c; ++l)
st[i][j][l]+=v[k][l];
}
}
return;
}
int m2=(l2+r2)/2;
if(l1<=m2)
upd(l1, r1, 2*i, l2, m2);
if(m2<r1)
upd(l1, r1, 2*i+1, m2+1, r2);
memset(o, 0, 4*c);
}
}
}
int main()
{
auto t1 = clock();
std::freopen("../tests/100x100-bottom-changes-many-queries.in", "r",stdin);
std::freopen("wombats.out", "w", stdout);
auto t2 = clock();
init(R, C, H, V);
auto t3 = clock();
if (event == 1)
{
res = scanf("%d%d%d", &P, &Q, &W);
changeH(P, Q, W);
}
else
if (event == 2)
{
res = scanf("%d%d%d", &P, &Q, &W);
changeV(P, Q, W);
}
else
if (event == 3)
{
res = scanf("%d%d", &V1, &V2);
auto t4 = clock();
return 0;
}
#include "wombats.h"
#include <bits/stdc++.h>
void upd(int l1, int r1, int i=1, int l2=0, int r2=bc-1)
{
if(l2==r2)
{
memset(st[i], 0x3f, sizeof(st[i]));
for(int j=0; j<c; ++j)
{
st[i][j][j]=0;
for(int k=l2*bs; k<(l2+1)*bs; ++k)
{
for(int l=1; l<c; ++l)
st[i][j][l]=min(st[i][j][l-1]+h[k][l-1], st[i][j][l]);
for(int l=c-1; l; --l)
st[i][j][l-1]=min(st[i][j][l]+h[k][l-1],st[i][j][l-1]);
for(int l=0; l<c; ++l)
st[i][j][l]+=v[k][l];
}
CAPITOLUL 7. IOI 2013 7.6. WOMBATS 821
}
return;
}
int m2=(l2+r2)/2;
if(l1<=m2)
upd(l1, r1, 2*i, l2, m2);
if(m2<r1)
upd(l1, r1, 2*i+1, m2+1, r2);
memset(o, 0, 4*c);
for(int j1=0; j1<c; ++j1)
{
for(int j2=c-1; ˜j2; --j2)
{
array<int, 2> d{INT_MAX, 0};
for(int k=o[j2]; k<=o[j2+1]; ++k)
d=min(array<int, 2>{st[2*i][j1][k]+st[2*i+1][k][j2],-k},d);
st[i][j1][j2]=d[0];
o[j2]=-d[1];
}
}
}
int main()
{
auto t1 = clock();
std::freopen("../tests/100x100-bottom-changes-many-queries.in","r",stdin);
std::freopen("wombats.out", "w", stdout) ;
auto t2 = clock();
init(R, C, H, V);
auto t3 = clock();
if (event == 1)
{
res = scanf("%d%d%d", &P, &Q, &W);
changeH(P, Q, W);
}
else
if (event == 2)
{
res = scanf("%d%d%d", &P, &Q, &W);
changeV(P, Q, W);
}
else
if (event == 3)
{
res = scanf("%d%d", &V1, &V2);
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
{
CAPITOLUL 7. IOI 2013 7.6. WOMBATS 823
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/100x100-bottom-changes-many-queries.in",
(char*)"wombats.out",
(char*)"../tests/100x100-bottom-changes-many-queries.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
Leonardo a inventat odometrul: o căruţă care putea măsura distanţele aruncând pietricele
după cum se roteau roţile acesteia. Numărând pietricelele aflam numărul de rotiri al roţii, ceea
ce permitea utilizatorului să calculeze distanţă parcursa de odometru. Ca programatori, noi
am adăugat un soft de control odometrului, extinzăndu-i funcţionalităţile. Sarcina ta este să
programezi odometrul respectând regulile specificate mai jos.
Zona de funcţionare
Odometrul se mişcă pe o matrice pătratică imaginară având 256 256 celule. Fiecare celulă
poate conţine cel mult 15 pietricele şi se identifică printr-o pereche de coordonate (rând, coloană),
unde fiecare coordonată se află ı̂n intervalul 0, ..., 255. Pentru o celuă i, j , celulele adiacente
ei sunt (dacă există) i 1, j , i 1, j , i, j 1 şi i, j 1. Oricare celulă aflată pe primul
sau ultimul rând, sau pe prima sau ultima coloană, este numită frontieră. Odometrul ı̂ncepe
ı̂ntotdeauna din celula (0,0) (colţul nord-vest), orientat spre nord.
Comenzile de bază
Odometrul poate fi programat folosind următoarele comenzi.
left - se roteşte cu 90 de grade spre stânga (invers acelor de ceasornic) şi rămâne ı̂n celula
curentă (de exemplu: dacă ı̂nainte a fost orientat spre sud, după executarea comenzii va fi
orientat spre est).
right - se roteşte cu 90 de grade spre dreapta (ı̂n sensul acelor de ceasornic) şi rămâne ı̂n
celula curentă (de exemplu: dacă ı̂naintă a fost orientat spre vest, după executarea comenzii
va fi orientat spre nord).
move - se mută exact o unitate ı̂nainte (ı̂n direcţia ı̂n care este orientat odometrul) ı̂n celula
adiacentă. Dacă o astfel de celulă nu există (adică frontiera ı̂n această direcţie a fost deja
atinsă) atunci comanda nu are niciun efect.
get - elimină o pietricică din celula curentă. Dacă celula curentă nu are nicio pietricică,
atunci comanda nu are niciun efect.
put - adaugă o pietricică ı̂n celula curentă. Dacă celula curentă are deja 15 pietricele, atunci
comanda nu are niciun efect. Odometrul nu rămâne niciodată fără pietricele.
halt - ı̂ncheie execuţia programului.
Odometrul execută comenzile ı̂n ordinea ı̂n care sunt date ı̂n program. Programul trebuie să
conţină cel mult o comandă pe linie. Liniile goale vor fi ignorate. Simbolul # indică un comentariu;
orice text care urmează până la sfârşitul liniei, este ignorat. Dacă odometrul ajunge la sfârşitul
programului, execuţia se ı̂ncheie.
Examplul 1
38
aur: Adrian Budău, ICHB (Bucureşti)
. aur: Vlad Alexandru Gavrilă, ICHB (Bucureşti)
. aur: Rareş Darius Buhai, Liviu Rebreanu (Bistriţa)
. bronz: Radu Ştefan Voroneanu, IL Caragiale (Ploieşti).
824
CAPITOLUL 8. IOI 2012 8.1. PEBBLING ODOMETER 825
Fie următorul program pentru odometru. El duce odometrul ı̂n celula (0, 2), orientat spre est.
(remarcaţi că primul move este ignorat, deoarece odometrul este ı̂n colţul nord-vest orientat spre
nord).
Exemplul 2
Următorul program localizează prima (cea mai din vest) pietricică din rândul 0 şi se opreşte
acolo; dacă nu există nicio pietricică ı̂n rândul 0, programul se opreşte pe frontieră la sfârşitul
rândului. El foloseşte două etichete leonardo şi davinci.
right
leonardo:
pebble davinci \# pietricica gasita
border davinci \# sfarsitul randului
move
jump leonardo
davinci:
halt
Odometrul porneşte rotindu-se spre dreapta. Bucla ı̂ncepe cu declararea etichetei leonardo
şi se termină cu comanda jump leonardo. ı̂n buclă, odometrul verifică dacă se află pietricele
sau dacă se află pe frontieră la sfârşitul rândului; dacă nu, odometrul execută comanda move din
celula curentă 0, j ı̂n celula adiacenă 0, j 1 cât timp cea din urmă există. (Comanda halt
nu este strict necesara aici deoarece programul se ı̂ncheie oricum).
Enunţ
Tu trebuie să trimiţi un program ı̂n limbajul odometrului, cum a fost descris mai sus, care
să facă odometrul să se comporte conform aşteptărilor. Fiecare subtask (vezi mai jos) specifică
o comportare pe care odometrul trebuie să o ı̂ndeplinească şi restricţiile pe care soluţia trimisă
trebuie să le ı̂ndeplinească. Restricţiile se refer urătoarele două aspecte.
Dimensiunea programului - programul trebuie să fie suficient de scurt. Dimensiunea progra-
mului este numărul de comenzi pe care ı̂l conţine. Declaraţiile de etichete, comentariile şi
liniile libere nu se contorizează” ı̂n dimensiune.
Lungimea execuţiei - programul trebuie să se termine suficient de repede. Lungimea execuţiei
este numărul de paşi: fiecare execuţie a unei comenzi este numărată ca un pas, chiar dacă
comanda are efect sau nu; declararea etichetelor, comentariile şi liniile libere nu se numără
ca paşi.
CAPITOLUL 8. IOI 2012 8.1. PEBBLING ODOMETER 826
În primul exemplu, programul are dimensiunea 4 şi lungimea execuţiei 4. În al doilea exem-
plu, programul are dimensiunea 6 şi, când este executat pe o matrice având o singură pietricică
ı̂n celula (0,10), lungimea execuţiei este de 43 de paşi: right, 10 iteraţii prin buclă, fiecare
conţinând câte 4 paşi (pebble davinci; border davinci; move; jump leonardo), şi la
final, pebble davinci şi halt.
Subtask 1 [9 puncte]
La ı̂nceput se află x pietricele ı̂n celula (0,0) şi y pietricele ı̂n celula (0,1), ı̂n timp ce toate
celalte celule sunt libere. Reţineţi că pot fi cel mult 15 pietricele ı̂ntr-o celulă. Scrie un program
care se ı̂ncheie cu odometrul ı̂n celula (0,0) dacă x & y, sau ı̂n celula (0,1) ı̂n caz contrar (Nu
contează cum este orientat odometrul la sfârşit sau câte pietricele există, ı̂n final, ı̂n matrice şi
nici unde sunt aşezate).
Limite: Dimensiunea programului & 100, lungimea execuţiei & 1 000.
Subtask 2 [12 puncte]
La fel ca subtask-ul anterior, dar când programul se ı̂ncheie, celula (0,0) trebuie să conţină
exact x pietricele iar celula (0,1) trebuie să conţină exact y pietricele.
Limite: Dimensiunea programului & 200, lungimea execuţiei & 2 000.
Subtask 3 [19 puncte]
Există exact două pietricele pe rândul 0: una ı̂n celula 0, x, iar cealalta ı̂n celula 0, y ; x şi
y sunt distincte, iar x y este par. Scrie un program care lasă odometrul ı̂n celula (0, (x+y)/2),
adică exact la mijlocul dintre cele două celule care conţin pietricele. Starea finală a matricii este
irelevantă.
Limite: Dimensiunea programului & 100, lungimea execuţiei & 200 000.
Subtask 4 [pana la 32 de puncte]
Se află cel mult 15 pietricele ı̂n matrice, oricare două ı̂n celule diferite. Scrie un program care
le adună pe toate ı̂n colţul nord-vest; mai exact, dacă la ı̂nceput existau x pietricele ı̂n matrice,
atunci la sfârşit trebuie să existe exact x pietricele ı̂n celula (0,0) şi nici o altă pietricică ı̂n celelalte
celule.
Scorul acestui subtask depinde de lungimea execuţiei a programului trimis. Mai exact, dacă L
este lungimea de execuţie maximă a unui test, scorul tău va fi:
32 de puncte dacă L & 200 000;
32 - 32 log10 L©200 000 de puncte dacă 200 000 ¡ L $ 2 000 000;
0 puncte dacă L ' 2 000 000.
submisie pentru task-ul x va fi automat inclusă; dacă nu există deja trimis un astfel de program,
acest subtask va primi 0 puncte pentru acea submisie.
Ca de obicei, punctajul unui submit se calculează ı̂nsumand scorurile subtask-urilor, iar scorul
final al sarcinii este punctajul maxim din rândul submit-urilor precedente şi al ultimului.
Simulator
În scopuri de testare, vi se oferă un simulator de odometru, căruia ii poţi furniza programele tale
şi matricele de intrare. Programele odometrului vor fi scrise ı̂n formatul folosit pentru submit-uri
(de exemplu, unul din cele descrise mai sus).
Descrierea matricei va fi dată cu ajutorul următorului format: fiecare linie a fişierului trebuie
să conţină trei numere R, C şi P , semnificand faptul că celula din randul R şi coloana C conţine
P pietricele. Se presupune că celulele ce nu sunt specificate ı̂n descrierea matriceise nu conţin
pietricele. Pentru exemplificare se consideră următorul fişier:
0 10 3
4 5 12
Matricea descrisă de acest fişier trebuie să conţină 15 pietricele: 3 ı̂n celulă (0,10) şi 12 ı̂n
celulă (4,5).
Poţi invoca simulatorul de testare prin apelarea programului simulator.py ı̂n directorul
sarcinei tale, transmiţandui ca argument numele fişierului de program ca argument. Programul
de simulare va accepta ı̂n linia de comandă următoarele opţiuni:
-h va oferi o scurtă trecere ı̂n revistă a opţiunilor disponibile;
-g GRID_FILE ı̂ncarcă descrierea matricei din fişierul GRID_FILE (implicit: matricrea
vidă);
-s GRID_SIDE setează dimensiunea matricei ca fiind egală cu GRID_SIDE GRID_SIDE
(implicit 256, aşa cum este specificat ı̂n problemă); utilizarea unei matrice mai mici ar putea
fi utilă ı̂n cazul depănarii programului;
-m STEPS limitează numărul de paşi executaţi ı̂n procesul de simulare la cel mult STEPS;
-c intră ı̂n modul de compilare; ı̂n modul de compilare, simulatorul returnează exact aceiaşi
ieşire, dar ı̂n loc de a face o simulare cu Python, el generează şi compilează un mic program
ı̂n limbajul C. Acest lucru duce la cheltuieli mai mari la start, dar dă rezultate mult mai
rapid; se recomandă să-l foşoseşti atunci când se preconizează ca programul tau va rula mai
mult de circa 10 000 000 de paşi.
Numărul de submit-uri
Numărul maxim de submit-uri permise pentru această sarcină este de 128.
Timp maxim de executare/test: 2.0 secunde
Memorie: total 1024 MB
As an illustrative example, we give directly the solution of Subtask 5, where code sharing is
employed. Note that finding the minimum is not complicated, removing one pebble per cell.
However, all the removed pebbles should be put back to their cells, and this complicates the
solution.
Subtask 5: solution generator in Python
8 # the border, we’re ready to search for the next candidate minimum.
9 print "%d_test_next_row:" % i
10 print "right"
11 print "border %d_scan_all" % (i+1)
12 print "move"
13 print "right"
14 print "%d_test_next_row_l1:" % i
15 print "border %d_test_next_row_l1end" % i
16 print "move"
17 print "jump %d_test_next_row_l1" % i
18 print "%d_test_next_row_l1end:" % i
19 print "right"
20 # Start the evaluation of the next row of the grid.
21 print "%d_scan_all:" % i
22 print "right"
23 print "%d_test_scan_row:" % i
24 for j in xrange(i):
25 print "get"
26 print "pebble %d_test_scan_row_continue" % i
27 print "jump end_%d" % i
28 print "%d_test_scan_row_continue:" % i
29 for j in xrange(i):
30 print "put"
31 # When it hits the border, try to go to the next row and go back to the
32 # first column.
33 print "border %d_test_next_row" % i
34 print "move"
35 print "jump %d_test_scan_row" %i
36 # When you find the minimum, you can share the code that puts back the pebbles
37 # in the cell.
38 for i in xrange(14,0,-1):
39 print "end_%d:" % i
40 print "put"
41 print "end_0:"
42 # If all the cells have 15 pebbles, any position is ok.
43 print "15_scan_all:"
O versiune timpurie şi destul de sofisticată de ceea ce noi acum numim paraşută este descrisă
ı̂n lucrarea lui Leonardo Codex atlanticus (cca. 1485). Paraşuta lui Leonardo constă dintr-o pânză
cerată, ţinutâ deschisă cu ajutorul unei structuri din lemn ı̂n formă de piramidă.
Inelele legate
Cu 500 de ani mai târziu, paraşutistul Adrian Nicolae a testat proiectul lui Leonardo. ı̂n acest
scop, o structură uşoară modernă leagă paraşuta lui Leonardo de corpul uman. Această structură
este formată din carabine ı̂n formă de inele, confecţionate dintr-un material rezistent. Inelele pot
fi uşor legate ı̂ntre ele, iar fiecare inel poate fi ı̂nchis sau deschis din nou. Numim lanţ o secvenţă
de unul sau mai multe inele legate, ı̂n care fiecare inel este legat cu alte două inele, cu excepţia
primului şi ultimului, care sunt legate cu cate un singur inel, după cum este ilustrat mai jos. Prin
definiţie, un singur inel este, de asemenea, un lanţ.
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 829
Evident, ı̂ntrucât un inel poate fi legat nu numai cu două, dar cu trei şi chiar mai multe inele,
sunt posibile şi alte configuraţii. Spunem că un inel este critic, dacă după deschiderea şi eliminarea
acestuia, inele rămase formează un set de lanţuri disjuncte sau alte inele nu mai există. Prin alte
cuvinte, lipsa de inele este şi ea un lanţ.
Exemplu
Se consideră cele 7 inele din figura ce urmează, numerotate de la 0 la 6. Există două inele
critice. Unul din inelele critice este cel cu numărul 2. După eliminarea acestui inel, inelele rămase
formează lanturile [1], [0, 5, 3, 4] şi [6]. Un alt inel critic este cel cu numărul 3. După eliminarea
acestuia, inelele rămase formează lanţurile [1, 2, 0, 5], [4] şi [6]. Dacă am elimina un oricare alt
inel, nu vom obţine un set de lanţuri disjuncte. De exemplu, deşi după eliminarea inelului 5 vom
obţine lanţul [6], inelele legate 0, 1, 2, 3 şi 4 nu formează un lanţ.
Sarcină
Trebuie să elaborezi un program care calculează numărul de inele critice din configuraţia dată.
La ı̂nceput, există un anumit număr de inele disjuncte. După aceea, inele sunt legate ı̂mpreună.
La un moment dat, se cere să returnezi numărul de inele critice din configuraţia curentă. Mai
concret, trebui să implementezii trei rutine.
Init(N) - la ı̂nceput aceasta se apelează exact o singură dată pentru a afla numărul N de
inele disjuncte din configuraţia iniţială, numerotate de la 0 la N 1 (inclusiv).
Link(A, B) - cele două inele A şi B vor fi legate ı̂mpreună. Este garantat că A şi B
sunt diferite si nu sunt ı̂ncă legate ı̂n mod direct. Nu există alte restricţii suplimentare faţă
de A şi B, ı̂n particular, restricţii ce ar rezulta din constrangeri fizice. Evident, apelurile
Link(A,B) şi Link(B,A) sunt echivalente.
CountCritical() - returnează numărul de inele critice din configuraţia curentă.
Exemplu
Se consideră N 7 inele, care, iniţial, sunt deconectate. Vom arata o secvenţă posibilă de
apeluril, după ultimul din care se va obţine configuraţia prezentată ı̂n figura de mai sus.
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 830
Detalii de implementare
Tu trebuie să transmiţi exact un singur fişier, denumit rings.c, rings.cpp sau rings.pas.
Acest fişier implementează subprogramele descrise mai sus utilizand signaturile ce urmează.
Programele ı̂n limbajul C/C++
Aceste subprograme trebuie să se comporte aşa cum este descris mai sus. Desigur, eşti liber
să implementezi pentru uzul intern al acestora şi alte subprograme. Submit-urile tale nu trebuie
să interacţioneze ı̂n nici ı̂ntr-un fel cu intrarea / ieşirea standard, şi nici cu oricare alt fişier.
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 831
Model de evaluator
Modelul de evaluator citeşte intrarea ı̂n formatul ce urmează:
linia 1: N , L;
liniile 2, ..., L 1:
` -1 apelează CountCritical;
` A, B parametrii pentru Link.
A suboptimal solution covering all but the last subtask considers the following conditions:
if there is a vertex V of degree ' 4, no other vertex can be critical (because removing V still
leaves one or more vertices of degree ' 3); so if there is more than one vertex of degree ' 4,
there are no critical vertices;
if there is a vertex V of degree 3, each critical vertex is either V or one of its neighbors;
if the graph is linear (a set of disjoint paths), all of its vertices are critical.
These checks can be easily extended to the dynamic case of the last subtask: the only nontrivial
check is keeping track of cycle formation, which can be dealt with using suitable data structures
(union-find d.s., etc.).
N = number of vertices;
M = number of calls to Link;
C = number of calls to CountCritical.
#include<ctime>
#include<iostream>
#include <cstdio>
#include <vector>
#include <cassert>
int n;
bool quadruplication = 0;
int numcycles = 0;
int cycle_length;// If numcycles==1, here we store the length of the only cycle
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 832
int degree[4][MAXN];
bool islinear[4]; // Whether each graph is linear or not
void Init(int k)
{
n = k;
for (int i=0; i<n; ++i)
{
other_endpoint[0][i] = i;
}
}
degree[i][x]++;
degree[i][y]++;
if ( degree[i][x] == 3 || degree[i][y] == 3 )
{
islinear[i] = 0;
continue;
}
if ( other_endpoint[i][x] == y )
{
// Cycle!
islinear[i] = 0;
continue;
}
int a = other_endpoint[i][x];
int b = other_endpoint[i][y];
other_endpoint[i][x] = -1;
other_endpoint[i][y] = -1;
other_endpoint[i][a] = b;
other_endpoint[i][b] = a;
}
}
destroyed[0] = x;
destroyed[1] = neighbours[x][0];
destroyed[2] = neighbours[x][1];
destroyed[3] = neighbours[x][2];
}
}
int x = xx;
int y = yy;
if ( quadruplication == 0 )
{
neighbours[x].push_back(y);
neighbours[y].push_back(x);
degree[0][x]++;
degree[0][y]++;
if ( degree[0][y] == 3 )
{
quadruplicate(y);
return;
}
if ( other_endpoint[0][x] != y )
{ // A longer path is formed
int a = other_endpoint[0][x];
int b = other_endpoint[0][y];
other_endpoint[0][x] = -1;
other_endpoint[0][y] = -1;
other_endpoint[0][a] = b;
other_endpoint[0][b] = a;
}
else
{ // A cycle is formed
numcycles++;
if ( numcycles == 1 )
{
int length = 1;
int previous_node = x;
int current_node = neighbours[x][0];
while ( current_node != x )
{
int possibility = neighbours[ current_node ][0];
if ( possibility == previous_node )
possibility = neighbours[ current_node ][1];
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 834
previous_node = current_node;
current_node = possibility;
length++;
}
cycle_length = length;
}
}
}
else
{
add_new_edge(x,y);
}
}
int CountCritical()
{
if ( quadruplication == 0 )
{
switch (numcycles)
{
case 0:
return n;
case 1:
return cycle_length;
default:
return 0;
}
}
else
{
int answer = 0;
for (int i=0; i<4; ++i)
{
if ( islinear[i] ) answer++;
}
return answer;
}
}
int main()
{
auto t1 = clock();
int tmp;
auto t2 = clock();
int N, L;
tmp = scanf("%d %d", &N, &L);
assert(tmp == 2);
Init(N);
auto t3 = clock();
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 835
int i;
for (i = 0; i < L; i++)
{
int A, B;
tmp = scanf("%d", &A);
if (A == -1)
{
int critical;
critical = CountCritical();
printf("%d\n", critical);
}
else
{
tmp = scanf("%d", &B);
assert(tmp == 1);
Link(A, B);
}
}
auto t4 = clock();
return 0;
#include<ctime>
#include<iostream>
#include<cassert>
if (!ck)
{
E[a][deg[0][a]] = b, E[b][deg[0][b]] = a;
}
deg[ck][a]++, deg[ck][b]++;
if (ck && (deg[ck][a] >= 3 || deg[ck][b] >= 3))
{
chk[ck] = 1;
return;
}
a = Find(ck, a), b = Find(ck, b);
if (a == b)
{
if (!ck)
{
cyc++;
if (cyc == 1)Res = SZ[a];
}
else chk[ck] = 1;
}
else
{
par[ck][a] = b;
if (!ck)
{
SZ[b] += SZ[a];
SZ[a] = 0;
}
}
}
void Make(int a)
{
int i, j, k, x;
Num[1] = a;
for (i = 0; i < 3; i++)
{
Num[2 + i] = E[a][i];
}
chk[0] = 1;
for (k = 1; k <= 4; k++)
{
for (i = 1; i <= n; i++)par[k][i] = i;
for (i = 1; i <= n; i++)
{
for (j = 0; j < deg[0][i]; j++){
x = E[i][j];
if (i == Num[k] || x == Num[k] || x > i)continue;
Add(k, i, x);
}
}
}
}
}
}
int CountCritical()
{
if (!chk[0])
{
if (cyc == 2)Res = 0;
return Res;
}
int i, r = 0;
for (i = 1; i <= 4; i++)if (!chk[i])r++;
return r;
}
int main()
{
auto t1 = clock();
int tmp;
auto t2 = clock();
int N, L;
tmp = scanf("%d %d", &N, &L);
assert(tmp == 2);
Init(N);
auto t3 = clock();
int i;
for (i = 0; i < L; i++)
{
int A, B;
tmp = scanf("%d", &A);
if (A == -1)
{
int critical;
critical = CountCritical();
printf("%d\n", critical);
}
else
{
tmp = scanf("%d", &B);
assert(tmp == 1);
Link(A, B);
}
}
auto t4 = clock();
return 0;
#include <bits/stdc++.h>
vector<pp> links;
int n;
struct simulator
{
int deg [1000010];
int oppo[1000010];
bool crit;
int R;
int par[1000010];
int sz [1000010];
int cyc_cnt;
int cyc_size;
int R(int x)
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 839
{
return (par[x]==x)?x:(par[x]=R(par[x]));
}
int first_deg[1000010];
bool isSim;
simulator ss[4];
if(thr != -1)
{
vector<int> inj;
for(pp& l:links)
{
int a,b; tie(a,b)=l;
if(a==thr) inj.push_back(b);
if(b==thr) inj.push_back(a);
}
ss[3].init(thr);
for(int i=0; i<3; ++i) ss[i].init(inj[i]);
isSim = true;
}
}
else
{
for(int i=0; i<4; ++i)
ss[i].update(A, B);
}
}
int CountCritical()
{
if(!isSim)
{
if(cyc_cnt >= 2)
return 0;
else return cyc_cnt ? cyc_size : n;
}
int ans=0;
for(int i=0; i<4; ++i) if(ss[i].crit) ++ans;
return ans;
}
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 840
int main()
{
auto t1 = clock();
int tmp;
auto t2 = clock();
int N, L;
tmp = scanf("%d %d", &N, &L);
assert(tmp == 2);
Init(N);
auto t3 = clock();
int i;
for (i = 0; i < L; i++)
{
int A, B;
tmp = scanf("%d", &A);
if (A == -1)
{
int critical;
critical = CountCritical();
printf("%d\n", critical);
}
else
{
tmp = scanf("%d", &B);
assert(tmp == 1);
Link(A, B);
}
}
auto t4 = clock();
return 0;
}
#include<ctime>
#include<iostream>
#include<cassert>
void Make(int a)
{
int i, j, k, x;
Num[1] = a;
for (i = 0; i < 3; i++)
{
Num[2 + i] = E[a][i];
}
chk[0] = 1;
for (k = 1; k <= 4; k++)
{
for (i = 1; i <= n; i++)par[k][i] = i;
for (i = 1; i <= n; i++)
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 842
{
for (j = 0; j < deg[0][i]; j++)
{
x = E[i][j];
if (i == Num[k] || x == Num[k] || x > i)continue;
Add(k, i, x);
}
}
}
}
int CountCritical()
{
if (!chk[0])
{
if (cyc == 2)Res = 0;
return Res;
}
int i, r = 0;
for (i = 1; i <= 4; i++)if (!chk[i])r++;
return r;
}
int main()
{
auto t1 = clock();
int tmp;
auto t2 = clock();
int N, L;
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 843
auto t3 = clock();
int i;
for (i = 0; i < L; i++)
{
int A, B;
tmp = scanf("%d", &A);
if (A == -1)
{
int critical;
critical = CountCritical();
printf("%d\n", critical);
}
else
{
tmp = scanf("%d", &B);
assert(tmp == 1);
Link(A, B);
}
}
auto t4 = clock();
return 0;
#include<bits/stdc++.h>
struct Graph
{
vector<int> rep, deg;
int excluded = -1;
int find(int x)
{
return rep[x] < 0 ? x : rep[x] = find(rep[x]);
}
int max_deg = 0;
void add_edge(int a, int b)
{
if(a == excluded || b == excluded)
return;
max_deg = max(max_deg, ++deg[a]);
max_deg = max(max_deg, ++deg[b]);
join(a, b);
}
int n;
vector<pair<int, int>> edges;
Graph graph;
vector<Graph> without;
void Init(int N)
{
n = N;
graph = Graph(n);
}
for(int x : crit)
{
without.emplace_back(n, x);
for(auto &[u, v] : edges)
without.back().add_edge(v, u);
}
}
}
else
{
for(auto &g : without)
g.add_edge(A, B);
}
}
int CountCritical()
{
if(graph.max_deg < 3)
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 845
{
if(graph.bicomp == -1) return n;
if(graph.bicomp == -2) return 0;
return graph.get_cycle();
}
else
{
int ret = 0;
for(auto &g : without)
{
if(g.bicomp == -1 && g.max_deg < 3)
ret++;
}
return ret;
}
}
int main()
{
auto t1 = clock();
int tmp;
auto t2 = clock();
int N, L;
tmp = scanf("%d %d", &N, &L);
assert(tmp == 2);
Init(N);
auto t3 = clock();
int i;
for (i = 0; i < L; i++)
{
int A, B;
tmp = scanf("%d", &A);
if (A == -1)
{
int critical;
critical = CountCritical();
printf("%d\n", critical);
}
else
{
tmp = scanf("%d", &B);
assert(tmp == 1);
Link(A, B);
}
}
auto t4 = clock();
return 0;
#include<bits/stdc++.h>
int adj[maxn][2];
int n;
struct G
{
bitset<maxn> is_link;
int lab[maxn];
int banned = -1;
bool ok = 1;
void init(int u)
{
banned = u;
for(int i = 0 ; i < n ; ++i)lab[i] = -1;
for(int i = 0 ; i < n ; ++i)
{
for(int j = 0 ; j < 2 ; ++j)
{
if(adj[i][j] != -1 && i > adj[i][j])
{
Connect(i,adj[i][j]);
}
}
}
}
return;
}
if(lab[u] > lab[v])swap(u , v);
lab[u] += lab[v];
lab[v] = u;
}
} a[4];
int cycle = 0;
int CurState = 0;
int deg[maxn];
if(deg[a] == 3)
{
CurState = 3;
for(int i = 0 ; i < 2 ; ++i)
{
::a[i].init(adj[a][i]);
}
::a[2].init(b);
::a[3].init(a);
for(int i = 0 ; i < 4 ; ++i)
{
::a[i].Connect(a,b);
if((a != ::a[i].banned && deg[a] - ::a[i].is_link[a] > 2) ||
(b != ::a[i].banned && deg[b] - ::a[i].is_link[b] > 2))
{
::a[i].ok = 0;
}
}
return;
}
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 848
if(::a[0].FindLab(a) == ::a[0].FindLab(b))
{
if(CurState == 2)CurState = 4;
else cycle = dfs(a , b) , CurState = 2;
}
else
{
::a[0].Connect(a , b);
}
}
int CountCritical()
{
if(CurState == 4)return 0;
if(CurState == 3)
{
int res = 0;
for(int i = 0 ; i < 4 ; ++i)
{
res += a[i].ok;
}
if(res == 0)CurState = 4;
return res;
}
int main()
{
auto t1 = clock();
int tmp;
auto t2 = clock();
int N, L;
CAPITOLUL 8. IOI 2012 8.2. PARACHUTE RINGS 849
auto t3 = clock();
int i;
for (i = 0; i < L; i++)
{
int A, B;
tmp = scanf("%d", &A);
if (A == -1)
{
int critical;
critical = CountCritical();
printf("%d\n", critical);
}
else
{
tmp = scanf("%d", &B);
assert(tmp == 1);
Link(A, B);
}
}
auto t4 = clock();
return 0;
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../input/input54.txt",
(char*)"rings.out",
(char*)"../output/output54.txt",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
Subtask 1 [5 puncte]
Numărul de comenzi şi ı̂ntrebări este ı̂ntre 1 şi 100 (inclusiv) şi nu va exista niciun apel
UndoCommands.
Subtask 2 [7 puncte]
Numărul de comenzi şi ı̂ntrebări este ı̂ntre 1 şi 100 (inclusiv) şi niciun apel UndoCommands
nu va fi anulat.
Detalii de implementare
Trebuie să trimiţi exact un fişier, numit scrivener.c, scrivener.cpp sau
scrivener.pas. Acest fişier trebuie să implementeze subprogramele descrise mai sus folosind
următoarele semnături.
programele ı̂n limbajul C/C++
void Init();
void TypeLetter(char L);
void UndoCommands(int U);
char GetLetter(int P);
procedure Init;
procedure TypeLetter(L : Char);
procedure UndoCommands(U : LongInt);
function GetLetter(P : LongInt) : Char;
Aceste subprograme trebuie să se comporte aşa cum este descris mai sus. Desigur, eşti liber
să implementezi pentru uzul intern al acestora şi alte subprograme. Submit-urile tale nu trebuie
să interacţioneze ı̂n nici ı̂ntr-un fel cu intrarea / ieşirea standard, şi nici cu oricare alt fişier.
Modelul de evaluator
Modelul de evaluator citeşte intrarea ı̂n formatul ce urmează:
linia 1: numărul total de comenzi şi ı̂ntrebări din input;
pe fiecare dintre următoarele linii:
– T urmat de un spaţiu şi o literă mică a pentru comanda TypeLetter;
– U urmat de un spaţiu şi un număr ı̂ntreg pentru comanda UndoCommands;
– P urmat de un spaţiu şi un număr ı̂ntreg pentru comanda GetLetter.
A clever way to get an efficient solution consists in representing the evolution of the system through
a trie, containing all the contents of the text so far; a point in time is represented by a single
pointer to a node in the trie.
Command processing requires O 1 time:
typing a letter just requires moving down in the trie (creating a new node if necessary)
For all the subtasks except the final one, after processing all the commands, the final contents
can be extracted from the trie into an array and used to answer queries in O 1 time, giving O N
time and space overall.
Subtask 5 requires a definitely more sophisticated approach to find a point in the text. For
this it is sufficient to be able to determine the k-ancestor of the current node: There are a number
of standard data structures for this problem that give O N log N time overall. For example,
k
every node at depth D can contain a pointer to its 2 -th ancestor, where k is the position of the
rightmost 1 in the binary expansion of D.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include<ctime>
#include<iostream>
void Init();
void TypeLetter(char L);
void UndoCommands(int U);
char GetLetter(int P);
#include<cstdlib>
#define MAXC 1000000
#define LOGMAXC 20
class node
{
public:
char l;
node** parents;
int depth;
parents[0] = NULL;
}
else
{
depth=parent->depth+1;
parents = new node*[LOGMAXC];
parents[0] = parent;
for(int i=1, j=2; j<=depth+1; i++, j*=2)
{
parents[i] = parents[i-1]->parents[i-1];
}
}
};
};
node** command_base;
int n_commands;
node* current_position;
node* tree_root;
void Init()
{
command_base = new node*[MAXC];
n_commands = 0;
current_position = tree_root = new node(’\0’,NULL);
}
void TypeLetter(char L)
{
command_base[n_commands] = current_position;
n_commands++;
node* n = new node(L, current_position);
current_position = n;
}
void UndoCommands(int U)
{
node *n = command_base[n_commands - U];
command_base[n_commands] = current_position;
n_commands++;
current_position = n;
}
char GetLetter(int P)
{
node* n = current_position;
int distance = current_position->depth - P;
return n->l;
}
int main()
{
auto t1 = clock();
int tmp;
Init();
CAPITOLUL 8. IOI 2012 8.3. CRAYFISH SCRIVENER 854
auto t2 = clock();
int cmd_num;
tmp = scanf("%d", &cmd_num);
assert(tmp == 1);
auto t3 = clock();
int i;
for (i = 0; i < cmd_num; i++)
{
char cmd;
tmp = scanf(" %c", &cmd);
assert(tmp == 1);
if (cmd == ’T’)
{
char letter;
tmp = scanf(" %c", &letter);
assert(tmp == 1);
TypeLetter(letter);
}
else
if (cmd == ’U’)
{
int number;
tmp = scanf("%d", &number);
assert(tmp == 1);
UndoCommands(number);
}
else
if (cmd == ’P’)
{
int index;
char letter;
tmp = scanf("%d", &index);
assert(tmp == 1);
letter = GetLetter(index);
printf("%c\n", letter);
}
}
auto t4 = clock();
return 0;
}
// ------------------ end grader ----------------
/*
t2-t1 = 0.015
t3-t2 = 0
t4-t3 = 2.313
argc = 4
checker
../input/input49.txt
scrivener.out
../output/output49.txt
----------------------
1
Correct
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include<ctime>
#include<iostream>
void Init();
void TypeLetter(char L);
void UndoCommands(int U);
char GetLetter(int P);
#include <vector>
#include <map>
void Init() {}
void TypeLetter(char L)
{
int &n = trie[now][L];
if (n == 0)
{
n = ++node;
prv[n][0] = now;
for (int i=1;i<20;i++)
prv[n][i] = prv[prv[n][i-1]][i-1];
len[n] = len[now] + 1;
last[n] = L;
}
hist[++ttime] = now = n;
}
void UndoCommands(int U)
{
now = hist[ttime-U];
hist[++ttime] = now;
}
char GetLetter(int P)
{
int x = now;
P = len[x] - P - 1;
for (int i=0;i<20;i++)
if (P & (1 << i))
x = prv[x][i];
return last[x];
}
int main()
{
auto t1 = clock();
int tmp;
Init();
auto t2 = clock();
int cmd_num;
tmp = scanf("%d", &cmd_num);
assert(tmp == 1);
auto t3 = clock();
int i;
for (i = 0; i < cmd_num; i++)
{
char cmd;
tmp = scanf(" %c", &cmd);
assert(tmp == 1);
if (cmd == ’T’)
{
char letter;
tmp = scanf(" %c", &letter);
assert(tmp == 1);
TypeLetter(letter);
}
else
if (cmd == ’U’)
{
int number;
tmp = scanf("%d", &number);
assert(tmp == 1);
UndoCommands(number);
}
else
if (cmd == ’P’)
{
int index;
char letter;
tmp = scanf("%d", &index);
assert(tmp == 1);
letter = GetLetter(index);
printf("%c\n", letter);
}
}
auto t4 = clock();
return 0;
}
// ------------------ end grader ----------------
/*
t2-t1 = 0.015
t3-t2 = 0
t4-t3 = 2.859
#include <stdlib.h>
#include <stdio.h>
CAPITOLUL 8. IOI 2012 8.3. CRAYFISH SCRIVENER 857
#include <assert.h>
#include<ctime>
#include<iostream>
void Init();
void TypeLetter(char L);
void UndoCommands(int U);
char GetLetter(int P);
int go[1000005],len[1000005],t=1,par[1000005][20];
char al[1000005];
void Init(){}
void TypeLetter(char L)
{
al[t]=L;
len[t]=len[go[t-1]]+1;
par[t][0]=go[t-1];
int u=1;
while(1)
{
if(len[t]>=(1<<u))
{
par[t][u]=par[par[t][u-1]][u-1];
u++;
}
else break;
}
go[t]=t;
t++;
}
void UndoCommands(int U)
{
go[t]=go[t-U-1];
t++;
}
char GetLetter(int P)
{
int o=len[go[t-1]];
o=o-P-1;
if(o==0)return al[go[t-1]];
int u=0,h=go[t-1];
while(o)
{
if(o%2)
{
h=par[h][u];
}
o/=2;
u++;
}
return al[h];
}
int main()
{
auto t1 = clock();
int tmp;
CAPITOLUL 8. IOI 2012 8.3. CRAYFISH SCRIVENER 858
Init();
auto t2 = clock();
int cmd_num;
tmp = scanf("%d", &cmd_num);
assert(tmp == 1);
auto t3 = clock();
int i;
for (i = 0; i < cmd_num; i++)
{
char cmd;
tmp = scanf(" %c", &cmd);
assert(tmp == 1);
if (cmd == ’T’)
{
char letter;
tmp = scanf(" %c", &letter);
assert(tmp == 1);
TypeLetter(letter);
}
else
if (cmd == ’U’)
{
int number;
tmp = scanf("%d", &number);
assert(tmp == 1);
UndoCommands(number);
}
else
if (cmd == ’P’)
{
int index;
char letter;
tmp = scanf("%d", &index);
assert(tmp == 1);
letter = GetLetter(index);
printf("%c\n", letter);
}
}
auto t4 = clock();
return 0;
}
// ------------------ end grader ----------------
/*
t2-t1 = 0
t3-t2 = 0
t4-t3 = 2.203
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include<ctime>
#include<iostream>
void Init();
void TypeLetter(char L);
void UndoCommands(int U);
char GetLetter(int P);
void Init() { }
void TypeLetter(char L)
{
++cnt2;
S[cnt2] = L;
dep[cnt2] = dep[A[cnt]] + 1;
par[0][cnt2] = A[cnt];
for (int i = 1; i < 20; ++i)
par[i][cnt2] = par[i - 1][par[i - 1][cnt2]];
++cnt;
A[cnt] = cnt2;
}
void UndoCommands(int U)
{
int x = cnt - U;
++cnt;
A[cnt] = A[x];
}
char GetLetter(int P)
{
int x = A[cnt];
for (int i = 0; i < 20; ++i)
if (((dep[x] - P - 1) >> i) & 1)
{
x = par[i][x];
}
return S[x];
}
int main()
{
auto t1 = clock();
int tmp;
Init();
auto t2 = clock();
CAPITOLUL 8. IOI 2012 8.3. CRAYFISH SCRIVENER 860
int cmd_num;
tmp = scanf("%d", &cmd_num);
assert(tmp == 1);
auto t3 = clock();
int i;
for (i = 0; i < cmd_num; i++)
{
char cmd;
tmp = scanf(" %c", &cmd);
assert(tmp == 1);
if (cmd == ’T’)
{
char letter;
tmp = scanf(" %c", &letter);
assert(tmp == 1);
TypeLetter(letter);
}
else
if (cmd == ’U’)
{
int number;
tmp = scanf("%d", &number);
assert(tmp == 1);
UndoCommands(number);
}
else
if (cmd == ’P’)
{
int index;
char letter;
tmp = scanf("%d", &index);
assert(tmp == 1);
letter = GetLetter(index);
printf("%c\n", letter);
}
}
auto t4 = clock();
return 0;
}
// ------------------ end grader ----------------
/*
t2-t1 = 0
t3-t2 = 0
t4-t3 = 2.359
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
CAPITOLUL 8. IOI 2012 8.4. IDEAL CITY 861
(char*)"../input/input49.txt",
(char*)"scrivener.out",
(char*)"../output/output49.txt",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
Leonardo, ca mulţi alţi oameni de ştiinţă şi artişti italieni de vârsta lui, era foarte interesat
de planificarea oraşelor si urbanism. El dorea să modeleze un oraş ideal: confortabil, spaţios, şi
raţional ı̂n privinţa utilizării resurselor, mult diferite de oraşele ı̂ngustate şi claustrofobice din evul
mediu.
Oraşul ideal
Oraşul era format din N blocuri plasate pe un grid infinit de formă pătrată format din celule.
Fiecare celulă se identifică prin perechea de coordonate (rând, coloană). Celula (0,0) este ı̂n colţul
din stânga sus a gridului. Pentru celula i, j , celulele adiacente (dacă există) sunt: i 1, j ,
i 1, j , i, j 1, şi i, j 1. Fiecare block, când este plasat pe grid, acoperă exact o celulă. Un
bloc poate fi plasat ı̂n celula i, j dacă şi numai dacă 1 & i, j & 2 2. Vom folosi, de asemenea,
31
coordonatele celulelor pentru a ne referi la blocurile plasate pe ele. Două blocuri sunt adiacente
dacă sunt plasate pe celule adiacente. ı̂ntr-un oraş ideal, toate blocurile sale sunt conectate astfel
ı̂ncât nu există ”găuri” ı̂n interiorul frontierei, adică celulele trebuie să ı̂ndeplinească următoarele
două condiţii.
Pentru oricare două celule neacoperite, există cel puţin o secvenţă de celule neacoperite
adiacente care le conectează.
Pentru oricare două celule acoperite, există cel puţin o secvenţă de celule acoperite adiacente
care le conectează.
Exemplul 1
Nici una din configuraţiile de blocuri de mai jos nu reprezintă un oraş ideal: primele două de
la stânga nu respectă prima condiţie, a treia nu respectă a doua condiţie, iar a patra nu respectă
nici una dintre condiţii.
Distanţa
CAPITOLUL 8. IOI 2012 8.4. IDEAL CITY 862
Când traversăm oraşul, o săritură ı̂nseamnă trecerea de la un bloc la un alt bloc adiacent.
Celulele neacoperite nu pot fi traversate. Fie v 0, v1 , ..., vN 1 coordonatele a N blocuri plasate
pe grid. Pentru oricare două blocuri distincte aflate la coordonatele vi şi vj , distanţa dintre
d vi , vj este cel mai mic număr de salturi necesare pentru a ajunge de la un bloc la celălalt.
Exemplul 2
Configuraţia de mai jos reprezintă un oraş ideal format din N 11 blocuri la coordonatele
v0 2, 5, v1 2, 6, v2 3, 3, v3 3, 6, v4 4, 3, v5 4, 4, v6 4, 5, v7 4, 6,
v8 5, 3, v9 5, 4, şi v10 5, 6. De exemplu, d v1 , v3 1, d v1 , v8 6, d v6 , v10 2, şi
d v9 , v10 4.
Enunţ
Sarcina ta este să scrii un program care, primind un oraş ideal, să calculeze suma distanţelor
dintre oricare perechi de blocuri vi şi vj cu i $ j. Mai exact, programul tău trebuie să calculeze
următoarea sumă:
=
d vi , vj , unde 0 & i $ j & N 1
Mai exact, trebuie să implementezi o rutină DistanceSum(N,X,Y) care, primind N şi doi
vectori X şi Y care descriu oraşul, calculează formula de mai sus. Atât X cât şi Y conţin exact N
elemente; blocul i se află la coordonatele X i, Y i cu 0 & i & N 1, şi 1 & X i, Y i & 2 2.
31
Deoarece rezultatul poate fi prea mare pentru a fi reprezentat pe 32 de biţi, el trebuie calculat
modulo 1 000 000 000 (un miliard).
ı̂n exemplul 2, sunt 11 10 / 2 = 55 perechi de blocuri. Suma distanţelor dintre toate perechile
este 174.
Subtask 1 [11 puncte]
Se consideră că N & 200.
Subtask 2 [21 de puncte]
Se consideră că N & 2 000.
Subtask 3 [23 de puncte]
Se consideră că N & 100 000.
În plus, următoarele două condiţii se ı̂ndeplinesc: pentru două celule acoperite i şi j astfel
ı̂ncât X i X j , oricare celulă dintre ele este acoperită; pentru două celul acoperite i şi j astfel
ı̂ncât Y i Y j , oricare celulă dintre ele este acoperită;
Subtask 4 [45 de puncte]
Se consideră că N & 100 000.
Detalii de implementare
Trebuie să trimiţi exact un fişier, numit city.c, city.cpp sau city.pas. Acest fişier
trebuie să implementeze subprogramul descris mai sus având următoarele semnături.
Programe C/C++
Programe Pascal
Acest subprogram trebuie să se comporte cum a fost descris mai sus. Desigur poţi implementa
alte subprograme pentru uz intern. Submisia ta nu trebuie să interacţioneze ı̂n vre-un fel cu
intrarea/ieşirea standard, şi nici cu alte fişiere.
Exemplu de evaluator
Exemplul de evaluator furnizat aşteaptă inputul ı̂n următorul format:
linia 1: N ;
liniile 2, ..., N 1: X i, Y i.
Simple solutions use Floyd-Warshall algorithm or iterated BFS on the unary-cost edges, and both
3 2
require O N space: time is O N for Floyd-Warshall, and O N for the iterated BFS, which
requires N times the number O N of edges.
A more efficient solution is the following one.
For every row r, consider the connected groups of cells on row r; each such group becomes
a node of a tree, with a weight corresponding to the cardinality of the group. Two nodes of
this tree are adjacent iff there are at least two cells in the corresponding groups sharing a
common edge. Repeat the same argument for every column c.
The above description yields two node-weighted trees, one (let us call it TH) corresponding
to horizontal node-groups and another (TV) for vertical node-groups.
Now, a shortest path between any two cells can be decomposed into two shortest paths
along TV and TH: the two corresponding integers are called the vertical and horizontal
contribution, respectively.
Let us limit ourselves to the horizontal contributions. The sum of all horizontal contributions
can be computed as the sum of w x w y d x, y over all possible distinct pairs of distinct
nodes x and y in TV: here, w x and w y are their weight (number of cells) and d x, y is
their distance in TV.
The latter summation can be computed in linear time in the number of edges of TV, by
¬
observing that it is equivalent to the sum of S e S e over all edges e of TV, where
¬
S e and S e are the sum of the weights of the two components of the tree obtained after
removing the edge e.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include<ctime>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
struct Point
{
int x;
int y;
Point() {}
int n;
Point squares[MAXN];
void exchange()
{ // Exchanges the x and y coordinates of all the points.
for (int i=0; i<n; ++i)
{
squares[i] = Point( squares[i].y, squares[i].x );
}
}
struct Node
{
int x;
int ymin;
int ymax;
vector<int> neighbours;
Node () {}
ymin = _ymin;
ymax = _ymax;
}
};
vector<Node> nodes;
void make_tree()
{ // Builds the tree of vertically/horizontally-collapsed nodes
// Create nodes
int cont = 0;
while ( cont < n )
{
int x = squares[cont].x;
int ymin = squares[cont].y;
int y = ymin;
int i;
for (i=cont+1; i<n; ++i)
{
if ( squares[i].y == y+1 ) y++;
else break;
}
int ymax = y;
cont = i;
// Create edges
int cont1,cont2;
cont1 = 0;
for ( cont2 = 1; cont2 < nodes.size(); cont2++ )
{
while ( ( nodes[cont1].x + 1 < nodes[cont2].x ) ||
( nodes[cont1].x + 1 == nodes[cont2].x &&
nodes[cont1].ymax < nodes[cont2].ymin ) )
cont1++;
int numedges = 0;
while ( nodes[cont1].x + 1 == nodes[cont2].x &&
nodes[cont1].ymin <= nodes[cont2].ymax )
{
numedges++;
nodes[cont1].neighbours.push_back(cont2);
nodes[cont2].neighbours.push_back(cont1);
cont1++;
}
bool visited[MAXN];
long long int s; // sum of all weights
long long int tot; // required total
long long int const MOD = 1000000000;
visited[k] = 1;
tot += w * (s - w);
tot %= MOD;
return w;
}
s = 0;
tot = 0;
for (int i=0; i<nodes.size(); ++i)
{
s += weight(i);
s %= MOD;
visited[i] = 0;
}
dfs(0);
return tot;
}
exchange();
return sol;
}
int main()
{
auto t1 = clock();
int tmp;
int N, i;
CAPITOLUL 8. IOI 2012 8.4. IDEAL CITY 867
auto t2 = clock();
auto t3 = clock();
printf("%d\n", ds);
auto t4 = clock();
return 0;
#include <bits/stdc++.h>
#define pb push_back
#define MOD 1000000000
struct pt
{
int x,y,v;
pt(){}
pt(int x_,int y_):x(x_),y(y_){}
bool operator < (const pt& r) const
{
return x!=r.x?x<r.x:y<r.y;
}
} s[100000];
CAPITOLUL 8. IOI 2012 8.4. IDEAL CITY 868
mat path;
int n;
int cnt[100000];
path.clear();
path.assign(sz,vec());
for(int i=0;i<N;i++)
{
pt* it=lower_bound(s,s+N,pt(s[i].x-1,s[i].y));
if(it->x==s[i].x-1&&it->y==s[i].y) path[s[i].v].pb(it->v);
it=lower_bound(s,s+N,pt(s[i].x+1,s[i].y));
if(it->x==s[i].x+1&&it->y==s[i].y) path[s[i].v].pb(it->v);
}
for(int i=0;i<sz;i++)
{
sort(path[i].begin(),path[i].end());
path[i].erase(unique(path[i].begin(),path[i].end()),path[i].end());
}
ll ret=0;
dfs(0,0,ret);
return (int)ret;
}
int main()
{
auto t1 = clock();
CAPITOLUL 8. IOI 2012 8.4. IDEAL CITY 869
int tmp;
int N, i;
tmp = scanf("%d", &N);
assert(tmp == 1);
auto t2 = clock();
auto t3 = clock();
printf("%d\n", ds);
auto t4 = clock();
return 0;
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include<ctime>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
int a,xx,yy,i,j,p,q,back,t,x[100002],y[100002];
long long sum,mod=1e9,sz[100002];
std::vector<int>G[100002],E[100002];
struct A
{
int num,s,e;
};
std::vector<A>T[100002];
void f()
{
t=0;
for(i=0;i<=a;i++)
G[i].clear(),T[i].clear(),E[i].clear();
for(i=1;i<=a;i++)
{
G[x[i]].push_back(y[i]);
}
for(i=0;G[i].size();i++)
std::sort(G[i].begin(),G[i].end());
for(i=0;G[i].size();i++)
{
back=G[i][0];
for(j=0;j<G[i].size();j++)
{
if(j==G[i].size()-1||G[i][j]+1!=G[i][j+1])
{
T[i].push_back({t++,back,G[i][j]});
sz[t-1]=G[i][j]-back+1;
if(j!=G[i].size()-1)back=G[i][j+1];
}
}
}
for(i=1;T[i].size();i++)
{
p=0;q=0;
while(p<T[i-1].size()&&q<T[i].size())
{
if(T[i-1][p].e<T[i][q].s||T[i][q].e<T[i-1][p].s)
{
}
else
{
E[T[i-1][p].num].push_back(T[i][q].num);
E[T[i][q].num].push_back(T[i-1][p].num);
}
if(T[i-1][p].e<T[i][q].e) p++;
CAPITOLUL 8. IOI 2012 8.4. IDEAL CITY 871
else q++;
}
}
dfs(0,-1);
}
int main()
{
auto t1 = clock();
int tmp;
int N, i;
tmp = scanf("%d", &N);
assert(tmp == 1);
auto t2 = clock();
auto t3 = clock();
printf("%d\n", ds);
auto t4 = clock();
return 0;
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include<ctime>
#include<iostream>
#include <algorithm>
#include <vector>
int n;
const int MOD = 1e9;
const int PMAX = 2147483646;
pi point[100000];
int idx[100000];
int cnt[100000];
vector<int> edge[100000];
bool haveNext(int i)
{
if (i == n - 1) return false;
if (point[i].first != point[i + 1].first) return false;
if (point[i].second + 1 != point[i + 1].second) return false;
return true;
}
int bsearch(pi x)
{
int s = 0, e = n - 1;
int m;
while (s < e)
{
m = (s + e) / 2;
if (point[m] == x) return m;
if (point[m] < x) s = m + 1;
else e = m - 1;
}
if (point[s] == x) return s;
return -1;
}
int ans;
CAPITOLUL 8. IOI 2012 8.4. IDEAL CITY 873
if (x)
{
llong sum = ret;
sum *= n - ret;
ans = (ans + sum) % MOD;
}
return ret;
}
int getAns()
{
ans = 0;
sort(point, point + n);
idx[0] = 0;
edge[0].clear();
cnt[0] = 1;
for (int i = 1; i < n; ++i)
{
if (haveNext(i - 1))
++cnt[idx[i] = idx[i - 1]];
else
cnt[idx[i] = idx[i - 1] + 1] = 1, edge[idx[i]].clear();
if (j == -1) continue;
edge[idx[i]].push_back(idx[j]);
edge[idx[j]].push_back(idx[i]);
}
dfs(0, -1);
return ans;
}
int t = getAns();
for (int i = 0; i < n; ++i)
{
point[i] = { Y[i], X[i] };
}
int main()
{
auto t1 = clock();
int tmp;
CAPITOLUL 8. IOI 2012 8.4. IDEAL CITY 874
int N, i;
tmp = scanf("%d", &N);
assert(tmp == 1);
auto t2 = clock();
auto t3 = clock();
printf("%d\n", ds);
auto t4 = clock();
return 0;
#include <stdlib.h>
#include <assert.h>
#include<ctime>
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
CAPITOLUL 8. IOI 2012 8.4. IDEAL CITY 875
vector<int>E[101000];
int n, SZ[101000], P[101000];
long long Res, D[101000], C[101000];
struct point
{
int x, y, num;
bool operator < (const point &p) const
{
return x != p.x ? x < p.x : y < p.y;
}
} w[101000], w2[101000], L[101000];
void Do()
{
int i, cnt = 0, a, b, j, cc = 0;
sort(w, w + n);
for (i = 0; i < n; i++)
{
if (!i || w[i].x != w[i - 1].x || w[i - 1].y + 1 != w[i].y)
SZ[++cnt] = 0;
SZ[cnt]++;
w2[i].num = cnt, w2[i].x = w[i].y, w2[i].y = w[i].x;
}
DFS(1, 0);
for (i = 1; i <= cnt; i++)E[i].clear();
}
Do();
for (i = 0; i < N; i++)
{
w[i].x = Y[i], w[i].y = X[i];
}
Do();
return Res%1000000000;
}
int main()
{
auto t1 = clock();
int tmp;
int N, i;
tmp = scanf("%d", &N);
assert(tmp == 1);
auto t2 = clock();
auto t3 = clock();
printf("%d\n", ds);
auto t4 = clock();
return 0;
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../input/input40.txt",
(char*)"city.out",
(char*)"../output/output40.txt",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
Leonardo era foarte activ când lucra la ”Cina cea de taină”, cea mai faimoasă pictură murală:
una din primele sarcini ale zilei era să decidă ce vopsele să folosească ı̂n cursul zilei. El avea nevoie
de multe culori, dar putea păstra pe schelă doar un număr limitat de culori. Pe lânga alte lucruri,
asistentul său trebuia să urce pe schelă pentru a-i furniza culorile şi pentru a le coborâ pe un
anumit raft pe podea.
În această problemă, trebuie să scrieţi două programe separate pentru a ajuta asistentul.
Primul program va primi instrucţiunile lui Leonardo (secvenţa de culori de care Leonardo are
nevoie ı̂n timpul zilei), şi crează un scurt string de biţi, numit secvenţă ajutătoare. ı̂n timpul
procesării cerinţelor lui Leonardo din cursul zilei, asistentul nu va avea acces la cerinţele ce vor
urma, el va avea acces doar la secvenţa ajutătoare produsă de primul program. Al doilea program
va primi secvenţa ajutătoare, şi apoi va primi şi procesa cerinţele lui Leonarda ı̂ntr-o manieră ”on-
line” (adică una câte una). Acest program trebuie să ı̂nţeleagă ce reprezintă secvenţa ajutătoare
şi să facă alegerile optime. Totul este explicat mai jos ı̂n detaliu.
Mutarea culorilor ı̂ntre raft şi schelă
Vom considera un scenariu simplificat. Presupunem că există N culori numerotate de la 0
la N 1, şi ı̂n fiecare zi, Leonardo ı̂i cere asistentului o nouă culoare de exact N ori. Fie C o
secnvenţă de N culori cerute de Leonardo. Putem privi C ca o secvenţă de N numere, fiecare
ı̂ntre 0 şi N 1, inclusiv. Unele culori ar putea să nu apară deloc ı̂n C, iar altele ar putea să apară
de mai multe ori.
Schela este ı̂ntotdeauna plină şi conţine K din cele N culori, cu K $ N. Iniţial, schela conţine
culorile de la 0 la K 1, inclusiv.
CAPITOLUL 8. IOI 2012 8.5. LAST SUPPER 878
Asistentul procesează cererile lui Leonardo una câte una. Oricând culoarea cerută este deja pe
schelă, asistentul se poate odihni. Altfel, el trebuie să ia culoarea cerută de pe raft şi să o ducă
pe schelă. Desigur, nu va mai fi loc pentru o nouă culoare, deci asistentul trebuie să aleagă una
din culorile existente pe schelă şi să o ducă pe raft, astfel ı̂ncât să facă loc pentru noua culoare.
Strategia optimă a lui Leonardo
Asistentul vrea să se odihnească de cât mai multe ori posibil. Numărul de cereri ı̂n care el se
poate odihni depinde de alegerile din timpul procesului. Mai precis, de fiecare dată când asistentul
trebuie să elimine o culoare de pe schelă, diferite alegeri pot condice la diferite situaţii viitoare.
Leonardo ı̂i explică asistentului cum poate să-şi atingă scopul cunoscând secvenţa C. Cea mai
bună alegere de a elimina o culoare de pe schelă se obţine examinând culorile existente pe schelă,
şi ce cerinţe au mai rămas ı̂n C. O culoare trebuie alese dintre cele de pe schelă respectând
următoarele reguli:
Dacă există o culoare pe schelă care nu va mai fi niciodată necesară ı̂n viitor, asistentul
trebuie să elimine o astfel de culoare de pe schelă.
Altfel, culoarea eliminată de pe schelă trebuie să fie aceea care va fi necesară cel mai târziu.
(Adică, dintre toate culorile de pe schelă, găsim viitoarea sa apariţie ı̂n cererile care urmează.
Culoarea ı̂ntoarsă pe raft va fi cea care este necesară ultima)
Se poate demonstra că utilizând strategia lui Leonardo, asistentul se va odhni de cele mai
multe ori.
Exemplul 1
Fie N 4, deci avem 4 culori (numerotate de la 0 la 3) şi 4 cereri. Fie secvenţa de cereri
C 2, 0, 3, 0. Presupunem K 2, adică Leonardo are o schelă capabilă să ţină 2 culori ı̂n
acelaşi timp. Cum s-a mai sus, iniţial, schela conţine culorile 0 şi 1, deci conţinutul schelei este:
[0, 1]. Un posibil mod ı̂n care asistentul poate rezolva cererile este următorul.
Prima culoare cerută (culoarea 2) nu este pe schelă. Asistentul o pune pe schelă şi decide
să elimine culoarea 1. Acum schela conţine culorile [0, 2].
Următoarea culoare cerută (culoarea 0) se află deja pe schelă, deci asistentul se poate odihni.
Pentru a treia cerere (culoarea 3), asistentul scoate culoarea 0, schimbând schela ı̂n
configuraţia [3, 2].
În final, a patra cerere (culoarea 0) trebuie să fie mutată de pe raft pe schelă. Asistentul
decide să elimine culoarea 2, deci schela devine acum [3, 0].
Se observă că ı̂n exemplul de mai sus, asistentul nu a urmat strategia optimă a lui Leonardo.
Strategia optimă ar fi eliminat culoarea 2 la pasul 3, deci asistentul s-ar fi putut odihni din
nou ı̂n pasul final.
Strategia asistentului când memoria sa este limitată
Dimineaţa, asistentul ı̂i cere lui Leonardă să scrie secvenţa C pe o foaie de hârtie, astfel ı̂ncât
să găsească şi să urmeze strategia optimă. Cu toate acestea, Leonardo este obsedat să-şi păstreze
tehnicile de lucru secrete, deci refuză să-i permită asistentului să folosească hârtia. El ı̂l lasă pe
asistent doar să citească secvenţa C şi să ı̂ncerce să o memoreze.
Din păcate, asistentul nu are o memorie bună. El este capabil să memoreze cel mult M biţi.
Din acest motiv, este posibil să nu poate reconstrui ı̂ntreaga secvenţă C. Totuşi, asistentul trebuie
să găsească o idee inteligentă pentru reconcstruiea secvenţei folosind biţii pe care ı̂i va memora.
Vom numi această secvenţă secvenţă ajutătoare şi o vom nota cu A.
Exemplul 2
De dimineaţă, asistentul poate lua hârtia lui Leonardo cu secvenţa C, să o citească, şi să facă
toate alegerile necesare. Un lucru pe care ar putea să-l facă ar fi să examineze starea schelei
după fiecare cerere. De exemplu, când foloseşte strategia (neoptimă) dată ı̂n exemplul 1, secvenţa
stărilor schelei ar fi [0, 2], [0, 2], [3, 2], [3, 0]. (Reamintim că el ştie că starea iniţială a schelei este
[0, 1]).
Acum presupunem că M 16, deci asistentul este capabil să reţină până la 16 biţi de informaţii.
Cum N 4, se pot memora culorile utilizând 2 biţi. De aceea, 16 biţi sunt suficienţi pentru a
stoca secvenţa de mai sus cu stările schelei. Deci, asistentul poate construi următoarea secvenţă
ajutătoare: A = (0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0).
În cursul zilei, asistentul poate decodifica această secvenţă ajutătoare şi o poate utiliza ı̂n
alegerile sale.
CAPITOLUL 8. IOI 2012 8.5. LAST SUPPER 879
(Desigur, cu M 16, asistentul poate să memoreze ı̂ntreagă secvenţă C, utilizând doar 8 din
cei 16 biţi disponibili. In acest exemplu am vrut doar să arătăm că există mai multe opţiuni, fără
a da orice solutie bună)
Enunţ
Trebuie să scrii două programe separate ı̂n acelaşi limbaj de programare. Aceste programe vor
fi executate pe rând, fără ca acestea să poată comunica ı̂ntre ele ı̂n timpul execuţiei.
Primul program va fi cel utilizat de asistent dimineaţa. Acest program va primi secvenţa C,
iar el trebuie să calculeze secvenţa de ajutor A.
Al doilea program va fi cel utilizat de asistent ı̂n cursul zilei. Acest program va primi secvenţa
ajutătoare A, iar el trebuie să proceseze şirul C cu cererile lui Leonardo. De remarcat că acest
program va primi secvenţa C element cu element, iar fiecare element curent trebuie să fie procesat
ı̂nainte de a fi primit următorul.
Mai exact, ı̂n primul program trebuie implementată o singură rutină
ComputeAdvice(C, N, K,M) având ca input vectorul C cu N elmente ı̂ntregi (fiecare
ı̂n 0, ..., N 1), numărul K de culori care pot ı̂ncăpea pe schelă, şi numărm M de biţi disponibili
pentru secvenţa ajutătoare. Acest program trebuie să calculeze secvenţa ajutătoare A, care poate
conţine cel mult M biţi. După aceasta, programul trebuie să transmită secvenţa A sistemului,
apelând pentru fiecare bit din A (ı̂n ordine), următoarea rutină:
WriteAdvice(B) - adaugă bitul B secvenţei ajutătoare A (poţi apela această rutină de
cel mult M ori).
În al doilea program trebuie să implementezi o singură rutină Assist(A, N, K, R). Inputul
acestei rutine este secvenţa ajutătoare A, intregii N şi K definiţi mai sus, şi numărul curent de biţi
R al secvenţei A (R & M ). Această rutină trebuie să execute strategia propusă de voi asistentului,
folosind următoarele rutine care ı̂ţi sunt oferite:
GetRequest() - returnează următoarea culoare cerută de către Leonardo. (Nu este oferită
nicio altă informaţie referitoare la cererile care urmează).
PutBack(T) - mută culoarea T din schelă ı̂napoi pe raft. Poţi apela această rutină doar
dacă culoarea T este una din culorile de pe schelă.
În timpul execuţiei rutina Assist trebuie să apeleze GetRequest de exact N ori, de fiecare
dată primind una din cele N cereri ale lui Leonardo, ı̂n ordine. După fiecare apel GetRequest,
dacă culoarea returnată nu se află pe schelă, trebuie apelat PutBack(T) cu T ales de tine.
Dacă culoarea se află pe schelă nu trebuie apelat PutBack deloc. Dacă nu se procesează aşa, se
consideră eroare şi aceasta va cauza ı̂ntreruperea execuţiei programului. Vă amintim că la ı̂nceput
schela conţine toate culorile de la 0 la K 1, inclusiv.
Un test va fi considerat rezolvat doar dacă cele două rutine respectă toate constrângerile, iar
numărul total de apeluri PutBack este acelaşi cu cel din strategia optimă a lui Leonardo. De
remarcat că dacă există mai multe strategii de a obţine acelaşi număr de apeluri PutBack, se
poate utiliza oricare dintre ele. (Adică nu este obligatoriu să fie urmată strategia lui Leonardo,
dacă există o strategie la fel de bună).
Exemplul 3
În continuarea exemplului 2, presupunem că ı̂n ComputeAdvice ai calculat A = (0,
0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0). Pentru a comunica aceasta sistemului, tre-
buie să realizezi următoarea secvenţă de apeluri: WriteAdvice(0), WriteAdvice(0),
WriteAdvice(1), WriteAdvice(0), WriteAdvice(0), WriteAdvice(0), WriteAd-
vice(1)—, WriteAdvice(0), WriteAdvice(1), WriteAdvice(1), WriteAd-
vice(1)—, WriteAdvice(0), WriteAdvice(1), WriteAdvice(1), WriteAdvice(0)—,
WriteAdvice(0).
A doua rutină Assist va fi apoi executată, primind secvenţa A de mai sus, şi valorile N 4,
K 2 şi R 16. Apoi, rutina Assist trebuie să facă exact N 4 apeluri GetRequest.
De asemenea, după unele dintre aceste cereri, Assist trebuie apelat PutBack(T) cu alegeri
potrivite pentru T .
Tabelul de mai jos arată secvenţa de apeluri corespunzătoare alegerilor (neoptime) pentru
exemplul 1. Liniuţa ”-” din tabel arată că nu s-a apelat PutBack.
CAPITOLUL 8. IOI 2012 8.5. LAST SUPPER 880
GetRequest() Acţiune
2 PutBack(1)
0 -
3 PutBack(0)
0 PutBack(2)
Subtask 1 [8 puncte]
N & 5 000.
Poţi folosi cel mult M = 65 000 biţi.
Subtask 2 [9 puncte]
N & 100 000.
Poţi folosi cel mult M = 2 000 000 biţi.
Subtask 3 [9 puncte]
N & 100 000.
K & 25 000.
Poti folosi cel mult M = 1 500 000 biţi.
Detalii de implementare
Trebuie să trimiţi exact două fişiere ı̂n acelaşi limbaj de programare.
Primul fişier trebuie numit advisor.c, advisor.cpp sau advisor.pas. Acest fişier tre-
buie să implementeze rutina ComputeAdvice după cum a fost descrisă mai sus şi trebuie să
apeleze WriteAdvice. Al doilea fişier trebuie numit assistant.c, assistant.cpp sau
assistant.pas. Acest fişier trebuie să implementeze rutina Assist după cum a fost descrisă
mai sus şi poate apela GetRequest şi PutBack.
Semnăturile celor două rutine sunt următoarele.
Programe C/C++
Programe Pascal
Aceste rutine trebuie să se comporte aşa cum s-a descris mai sus. Desigur, sunteţi liberi
să implementaţi alte rutine pentru uzul intern. Pentru programele C/C++, rutinele interne
trebuie declarate static, ca evaluatorul să le poată lega. Alternativ, evidaţi să aveţi două
rutine (una ı̂n fiecare program) cu acelaşi nume. Submisiile voastre nu au voie să interacţioneze
cu intrarea/ieşirea standard, sau cu orice alt fişier.
Când scrieţi soluţiile, trebuie să aveţi grije la următoarele instructiuni (modelele pe care le
puteţi găsi pe calculator, respectă cerinţele listate mai jos).
Programe C/C++
La ı̂nceputul sursei, trebuie să includeţi fişierul advisor.h ı̂n programul advisor şi
assistant.h ı̂n programul assistant. Acest lucru poate fi realizat inserând ı̂n sursă linia:
#include "advisor.h"
sau
#include "assistant.h"
Cele două fişiere advisor.h şi assistant.h vor fi furnizate atât pe calculator (ı̂ntr-un
director) cât şi pe interfaţa web a concursului. De altfe, vei avea acces (prin aceleaşi canale) la
cod şi scripturi pentru a compila şi testa soluţia pe calculator. Mai precis, după copierea soluţiei ı̂n
directorul cu aceste scripturi, trebuie să rulaţi compile_c.sh or compile_cpp.sh (ı̂n funcţie
de limbajul de programare al codului).
Programe Pascal
Trebuie să utilizaţi uniturile advisorlib ı̂n programul advisor şi assistantlib ı̂n pro-
gramul assistant. Acest lucru poate fi realizat inserând ı̂n sursă linia:
uses advisorlib;
sau
uses assistantlib;
Cele două fişiere advisorlib.pas şi assistantlib.pas vor fi furnizate atât pe calculator
(ı̂ntr-un director) cât şi pe interfaţa web a concursului. De altfe, vei avea acces (prin aceleaşi
canale) la cod şi scripturi pentru a compila şi testa soluţia pe calculator. Mai precis, după
copierea soluţiei ı̂n directorul cu aceste scripturi, trebuie să rulaţi compile_pas.sh
Exemplu de evaluator
Exemplul de evaluator va accepta inputul ı̂n următorul format:
linia 1: N , K, M ;
liniile 2, ..., N 1: C i.
Let us first describe how to compute the optimal strategy of Leonardo in O N log N time.
Use an array of size N and scan the requests in C backwards: for each request, it is possible
to compute how far in the future the same color will be requested.
Process the requests in C forward: for each request, we can determine if the color is in the
scaffold and which of the colors to remove; the latter can be established in time O log N by
keeping a priority queue of colors where the priority is determined by the time of the next
request.
For encoding the advice, the trivial solution would be to use N log K bits, i.e. log K for
every color fault (i.e., every time the requested color is missing from the scaffold): this way
we might specify exactly which color (within the K colors available on the scaffold) should
be removed.
Here is an alternative encoding that uses only N K bits and it is optimal in the worst case.
Divide the colors currently in the scaffold between ”active” and ”passive”: an ”active” color
is one that will be requested before it is removed from the scaffold according to the optimal
strategy of Leonardo; a ”passive” one will not.
Using N K bits it is possible to keep track of which colors are active:
` The initial active colors can be specified using K bits overall.
` Moreover, with each request we can provide a bit saying if the currently requested color
is active.
Note that removing any passive color is always ok. Of course, if you remove it arbitrarily
you will not produce the optimal solution you started from, but an equivalent one with the
same number of colors removed.
#include "advisor.h"
#include "assistant.h"
#include <cstdio>
#include <queue>
#include <cassert>
#include <stack>
#include<ctime>
#include<iostream>
struct Color
{
int id;
int np; // next position
CAPITOLUL 8. IOI 2012 8.5. LAST SUPPER 883
Color () {}
priority_queue<Color> coda;
int accumulated = 0;
int counter = 0;
if ( events[j].empty() )
{
WriteAdvice(0);
continue;
}
if ( events[j].front() == 0 )
{
events[j].pop();
WriteAdvice(0);
}
else
{
WriteAdvice(1);
}
}
}
bool in_the_scaffold[MAXN];
queue<int> passive; // queue of passive colors
if ( !in_the_scaffold[color] )
{
in_the_scaffold[ passive.front() ] = 0;
in_the_scaffold[ color ] = 1;
PutBack( passive.front() );
passive.pop();
if ( real_advice[k+i] == 0 ) passive.push(color);
}
}
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
static int N, K, M;
static int *C;
static int R;
static unsigned char *A;
int GetRequest(void)
{
int req;
if (expect_put_back)
{
fprintf(stderr, "Not putting back color when it is not on the scaffold\n");
exit(1);
}
req = C[++current_request];
if (!in_scaffold[req])
expect_put_back = TRUE;
else
expect_put_back = FALSE;
void PutBack(int T)
{
int req;
if (!expect_put_back)
{
fprintf(stderr,"Putting back a color when it is already on the scaffold\n");
exit(1);
}
if (!in_scaffold[T])
{
fprintf(stderr, "Putting back a color that is not on the scaffold\n");
exit(1);
}
CAPITOLUL 8. IOI 2012 8.5. LAST SUPPER 886
req = C[current_request];
in_scaffold[req] = TRUE;
in_scaffold[T] = FALSE;
expect_put_back = FALSE;
if (R < M)
{
fprintf(fadvice, "%hhu ", a);
A[R] = a;
R++;
}
else
{
fprintf(stderr, "Advisor is providing too many bits of advice\n");
exit(1);
};
}
int main()
{
auto t1 = clock();
int tmp;
int i;
auto t2 = clock();
ComputeAdvice(C, N, K, M);
fprintf(fadvice, "\n2\n");
auto t3 = clock();
Assist(A, N, K, R);
printf("E\n");
auto t4 = clock();
return 0;
}
// ------------------- end grader ----------------------
#include "advisor.h"
#include "assistant.h"
#include <bits/stdc++.h>
continue ;
}
set<int> actives ;
bool scaff[MAXN] ;
lp(i,0,N)
{
int x = GetRequest() ;
if( scaff[x] )
{
if( A[++idx] ) actives.insert( x ) ;
continue ;
}
scaff[x] = true ;
PutBack(toErase) ;
}
}
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
CAPITOLUL 8. IOI 2012 8.5. LAST SUPPER 889
#define FALSE 0
#endif
static int N, K, M;
static int *C;
static int R;
static unsigned char *A;
int GetRequest(void)
{
int req;
if (expect_put_back) {
fprintf(stderr, "Not putting back color when it is not on the scaffold\n");
exit(1);
}
req = C[++current_request];
if (!in_scaffold[req])
expect_put_back = TRUE;
else
expect_put_back = FALSE;
void PutBack(int T)
{
int req;
if (!expect_put_back)
{
fprintf(stderr,"Putting back a color when it is already on the scaffold\n");
exit(1);
}
if (!in_scaffold[T])
{
fprintf(stderr, "Putting back a color that is not on the scaffold\n");
exit(1);
}
req = C[current_request];
in_scaffold[req] = TRUE;
in_scaffold[T] = FALSE;
expect_put_back = FALSE;
if (R < M)
{
fprintf(fadvice, "%hhu ", a);
A[R] = a;
R++;
}
else
{
fprintf(stderr, "Advisor is providing too many bits of advice\n");
CAPITOLUL 8. IOI 2012 8.5. LAST SUPPER 890
exit(1);
};
}
int main()
{
auto t1 = clock();
int tmp;
int i;
auto t2 = clock();
ComputeAdvice(C, N, K, M);
fprintf(fadvice, "\n2\n");
auto t3 = clock();
Assist(A, N, K, R);
printf("E\n");
auto t4 = clock();
return 0;
}
// ------------------- end grader ----------------------
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 891
8.6 Tournament
Problema 6 - Turnirul 100 de puncte
În anul 1491 ducele de Milano Lodovico l-a rugat pe Leonardo să-i orchestreze nunta sa cu
Beatrice d’Este, care includea şi un mare turneu, ce trebuia să dureze trei zile. Dar cel mai vestit
cavaler ı̂ntârzia ...
Turnirul
Într-un turneu, N cavaleri sunt mai ı̂ntâi aranjaţi ı̂ntr-o linie, iar poziţiile lor de-a lungul liniei
sunt numerotate de la 0 la N 1. Arbitrul turneului stabileşte o rundă cerând să iasă din linie
cavalerii din poziţiile dintre S şi E inclusiv (unde 0 & S $ E & N 1). Toţi cavalerii de pe poziţiile
ı̂ntre S şi E (inclusiv) se luptă ı̂ntre ei. Câştigătorul acestei lupte se ı̂ntoarce la locul său din linie
şi rămâne ı̂n turneu, ı̂n timp ce perdanţii iese de pe câmp şi sunt eliminaţi din turneu.
În continuare, cavalerii rămaşi se aranjează de-a lungul liniei, de la ı̂nceputul ei, păstrând
ordinea lor relativă din linia precedentă, ocupând astfel poziţiile de la 0 la N E S 1. ı̂n
continuare, arbitrul stabileşte runda următoare, repetând acest proces până când rămâne doar
un singur cavaler. Leonardo cunoaşte faptul că toţi cavalerii au puteri diferite, reprezentate prin
ranguri distincte de la 0 (cel mai slab) la N 1 (cel mai puternic). De asemenea, el cunoaşte exact
ce echipe vor fi desemnate de arbitru pentru cele C runde. La urma urmei el e Leonardo, ... şi el
este sigur că ı̂n fiecare din aceste runde va câştiga cavalerul cu rangul cel mai ı̂nalt.
Cavalerul ce a ı̂ntârziat
Cei N 1 din totalul de N cavaleri sunt deja aranjaţi ı̂n linie. Lipseşte doar cavalerul cel mai
vestit. Acest cavaler are rangul R şi vine la turnir un pic mai târziu. Pentru a crea o atmosferă
de divertisment, Leonardo vrea să exploateze popularitatea cavalerului ı̂ntârziat şi alege pentru el
o astfel de poziţie ı̂n linie, care va maximiza numărul de runde pe care cavalerul ı̂ntârziat le va
câştiga.
Reţineţi că nu suntem interesaţi ı̂n rundele ı̂n care nu participă cavelerul ı̂ntârziat, ci doar ı̂n
rundele la care el ia parte şi le câştigă.
Exemplu
Pentru N 5, cei N 1 cavaleri aranjaţi ı̂n linie au rangurile [1, 0, 2, 4], respectiv. Evident,
rangul cavalerului ı̂ntârziat este R 3. Pentru fiecare dim cele C 3 runde, arbitrul intenţionează
să scoată din linie cavalerii de pe poziţiile S, E , ı̂n următoarea ordine: (1, 3), (0, 1), (0, 1).
Dacă Leonardo plasează cavalerul ı̂ntârziat ı̂n prima poziţie, rangurile cavalerilor de pe linie
vor fi [3, 1, 0, 2, 4]. ı̂n prima rundă se vor lupta cavalerii de pe a poziţiile 1, 2, 3, cu rangurile 1,
0, 2, iar ı̂nvingător va fi cavalerul cu rangul 2. Cavalerii din linia nouă vor avea rangurile [3, 2, 4].
ı̂n următoarea rundă se vor lupta cavalerii cu rangurile 3 şi 2 (din poziţiile 0, 1), câştigător va fi
cavalerul cu rangul R 3. După acestă rundă rangurile cavalerilor din linie vor fi [3, 4]. Runda
finala (cavalerii de pe poziţiile 0, 1) este câştigată de cavalerul cu rangul 4. Prin urmare, cavalerul
ı̂ntârziat câştigă doar o runda (a doua).
În cazul ı̂n care Leonardo ar plasa cavalerul ı̂ntârziat ı̂ntre cavalerii cu rangurile 1 si 0, linia
ar arăta ı̂n felul următor: [1, 3, 0, 2, 4]. De data aceasta, ı̂n prima rundă participă cavalerii cu
rangurile 3, 0, 2, câştigător fiind cavalerul cu rangul R 3. Linia urmatoare este formată din
cavalerii cu rangurile [1, 3, 4]. ı̂n runda următoare participă cavalerii cu rangurile (1 şi 3), din
nou cı̂ştigător fiind cel cu rangul R 3. Linia finală este formată din cavalerii cu rangurile [3,
4], câştigător fiind cel cu rangul 4. Astfel, cavalerul ı̂ntârziat câştigă două runde; de fapt, acesta
este cel mai bun plasament posibil, deoarece nu există nici o altă modalitate de plasare ı̂n care
cavalerul ı̂ntârziat ar câştiga mai mult decât de două ori.
Sarcină
Trebuie să scrii un program care alege cea mai bună poziţie pentru cavalerul ı̂ntârziat, astfel
ı̂ncât numărul de runde castigate de el sa fie maxim, aşa cum şi-o doreşte Leonardo. Mai exact,
trebuie să elaborezi o rutina denumită GetBestPosition (N, C, R, K, S, E), unde:
N este numărul de cavaleri;
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 892
Toate apelurile acestei rutine vor fi corecte: E i va fi mai mic decât numărul curent de cavaleri
rămaşi pentru runda i 1, iar după C runde va rămânea exact un singur cavaler.
GetBestPosition(N, C, R, K, S, E) trebuie să returneze cea mai bună poziţie P ı̂n
care Leonardo trebuie să-l plaseze pe cavalerul ı̂ntârziat (0 & P & N 1). Dacă există mai multe
poziţii echivalente, retunaţi poziţia cea mai mică. (Poziţia P este o poziţia 0-bazată a cavalerului
ı̂ntârziat ı̂n linia rezultat. Prin alte cuvinte, P este numărul celorlaţi cavaleri care ı̂n soluţia
optimală stau ı̂naintea cavalerului ı̂ntârziat. ı̂n particular, P 0 semnifică faptul că cavalerul
ı̂ntârziat este la ı̂nceputul liniei, iar P N 1 semnifică faptul că el este la sfârşitul liniei).
Subtask 1 [17 puncte]
Se considră că N & 500.
Subtask 2 [32 de puncte]
Se considră că N & 5 000.
Detalii de implementare
Trebuie să transmiţi exact un singur fişier, denumit tournament.c\verb,
tournament.cpp sau tournament.pas. Acest fiţier trebuie să implementeze subpro-
gramul descris mai sus, având următoarele signaturi:
Programele C/C++
int GetBestPosition(int N, int C, int R, int *K, int *S, int *E);
Programele Pascal
Aceste subprograme trebuie să se comporte aşa cum este descris mai sus. Desigur, pentru
uzul intern eşti liber să pui ı̂n aplicare şi alte subprograme. Submit-urile tale nu trebuie să
interacţioneze ı̂n nici un fel cu intrarea/ieşirea standard şi cu alte fişiere.
Model de evaluator
Modelul de evaluator furnizat de mediul de evaluare acceptă următorul format al datelor de
intrare:
linia 1: N , C, R;
liniile 2, ..., N : K i;
liniile N 1, ..., N C: S i, E i.
Solutions of various ranges of complexity are possible: all of them are essentially based on the
trivial idea of trying all possible positions and simulating the tournament.
3 2
A trivial way to do that takes time O N . We hereby describe a O N -time solution.
The whole tournament can be thought of as a tree whose leaves represent the knights and
where all other nodes represent the winner of a round. The structure of the tree is the same
regardless of where we put ourselves in the initial rank, only labels of the nodes (i.e., round
winners) change.
2 2
The latter tree leads to an O N solution: the tree construction takes time O N ; then
for each of the possible N positions, we have to determine how far up our knight can go, so
2
we are left with another O N checks. To go down to O N log N time we need to optimize
the tree construction and the tournaments simulations.
To speed up the tree construction to O N log N , we can use a binary range tree to get
quickly the knight that is currently in any given challenged position.
To speed up the second phase, we make two observations.
1. Let us call ”white”/”black” the knights that are weaker/stronger than the late knight.
Then, when we place the late knight in a certain position, we have to determine how far
up we can go without finding a node that has some black leaf below it. For example, if
we decide to place the late knight in the leftmost position, we want to find the leftmost
node that has the longest path to a leaf and contains only white leaves under it.
2. Every time we place the knight in a given position, we are simply shifting (to the left)
every knight to his left.
Combining these two observations, we dont need to actually try a position to see how far up
we can go: it is sufficient to proceed as described in the first observation but allowing the
leftmost descendant to be black, and requiring only the remaining ones to be white.
Doing it in this way, the second phase is O N because of the second observation.
#include<ctime>
#include <cstdio>
#include <iostream>
#include <cassert>
#include <vector>
#include <queue>
struct Node
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 894
{
int start;
int end;
Node() {}
int n,c,o;
bool rankb[MAXN];
// Range tree
int range_tree[MAXLOGN][MAXN];
int size_of_the_range_tree; // the size of the range tree
void make_range_tree()
{
int m = n;
int step = 0;
while ( m > 0 )
{
for (int i=0; i<m; ++i)
{
if ( step == 0 ) range_tree[step][i] = 1;
else
{
range_tree[step][i] = range_tree[step-1][2*i] +
range_tree[step-1][2*i+1];
}
}
if ( m > 1 ) m = (m+1)/2;
else m = 0;
step++;
}
size_of_the_range_tree = step;
if ( step == 0 )
{
assert(k == 1);
return m;
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 895
if ( range_tree[step-1][2*m] >= k )
return find_knight( k, step-1, 2*m );
else
return find_knight( k - range_tree[step-1][2*m], step-1, 2*m+1 );
}
// Calls tree
vector<Node> calls_tree;
int GetBestPosition(int N, int C, int R, int *K, int *S, int *E)
{
n = N;
c = C;
int o = R;
make_range_tree();
rankb[0] = 1;
Node nodo = Node( 0, 0 );
nodo.all_white = 1;
nodo.almost_all_white = 1;
nodo.where_best = 0;
calls_tree.push_back( nodo );
father[0] = 0;
bool all_white = 1;
bool almost_all_white = 1;
queue<int> to_change;
father[knight] = calls_tree.size();
if ( calls_tree[old_int].all_white == 0 )
{
all_white = 0;
if ( j > s ) almost_all_white = 0;
else
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 896
if ( calls_tree[old_int].almost_all_white == 0 )
almost_all_white = 0;
}
while ( !(to_change.empty()) )
{
int knight = to_change.front();
to_change.pop();
change( knight, -1 );
}
interval.all_white = all_white;
interval.almost_all_white = almost_all_white;
if ( almost_all_white )
{
interval.best_result = the_best + 1;
interval.where_best = calls_tree[ best_child ].where_best;
// Found an interval for which it is possible
// to win interval.best_result times by starting in
// position interval.where_best
}
else
{
interval.best_result = the_best;
interval.where_best = calls_tree[ best_child ].where_best;
}
calls_tree.push_back(interval);
}
int t = calls_tree.size();
return calls_tree[t-1].where_best;
}
int main()
{
auto t1 = clock();
int tmp;
auto t2 = clock();
int N, C, R;
int *K, *S, *E;
tmp = scanf("%d %d %d", &N, &C, &R);
assert(tmp == 3);
K = (int*) malloc((N-1) * sizeof(int));
S = (int*) malloc(C * sizeof(int));
E = (int*) malloc(C * sizeof(int));
int i;
for (i = 0; i < N-1; i++)
{
tmp = scanf("%d", &K[i]);
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 897
assert(tmp == 1);
}
for (i = 0; i < C; i++)
{
tmp = scanf("%d %d", &S[i], &E[i]);
assert(tmp == 2);
}
auto t3 = clock();
auto t4 = clock();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include<ctime>
#include<iostream>
int getnth(int n)
{
int x = 1;
while (x < Z)
{
x <<= 1;
if (cnt[x] < n) n -= cnt[x++];
}
return x - Z;
}
int add[Z],res[Z];
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 898
int GetBestPosition(int N, int C, int R, int *K, int *S, int *E)
{
int i,peo,x,y;
for (i=0;i<C;i++)
{
peo = E[i] - S[i];
S[i] = getnth(S[i]+1);
x = nextv[S[i]];
while (peo--)
{
up(x,-1);
x = nextv[x];
}
E[i] = x - 1;
nextv[S[i]] = x;
}
for (i=0;i<C;i++)
{
if (add[E[i]] == add[S[i]])
{
res[S[i]]++;
res[E[i]]--;
}
}
return ind;
}
int main()
{
auto t1 = clock();
int tmp;
auto t2 = clock();
int N, C, R;
int *K, *S, *E;
tmp = scanf("%d %d %d", &N, &C, &R);
assert(tmp == 3);
K = (int*) malloc((N-1) * sizeof(int));
S = (int*) malloc(C * sizeof(int));
E = (int*) malloc(C * sizeof(int));
int i;
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 899
auto t4 = clock();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include<ctime>
#include<iostream>
#include<algorithm>
int read1(int x)
{
if(x==-1)return -1;
int a=1;
while(a<idx)
{
if(T[2*a]<x)x-=T[2*a],a=2*a+1;
else a=2*a;
}
return a-idx;
}
{
ret=max(ret,T[a]);
ret=max(ret,T[b]);
a = (a+1)>>1, b = (b-1)>>1;
}
return ret;
}
int sum[100010],ans;
int d[100010];
int GetBestPosition(int N, int C, int R, int *K, int *S, int *E)
{
int i;
for(i=0;i<N;i++)d[i]=i+1,T[i+idx]=1;
for(i=idx-1;i;i--)T[i]=T[i<<1] + T[i<<1|1];
for(i=0;i<C;i++)
{
int a = read1(S[i]+1);
int tmp = a;
for(int j=0;j<E[i]-S[i];j++)
{
tmp = d[tmp];
update(tmp);
}
d[a] = d[tmp];
E[i] = d[tmp]-1;
S[i] = a;
}
for(i=0;i<N-1;i++)T[i+idx]=K[i];
for(i=idx-1;i;i--)T[i]=max(T[i<<1],T[i<<1|1]);
for(i=0;i<C;i++)
{
int s = read2(S[i],E[i]-1);
if(s<R)sum[S[i]]++,sum[E[i]+1]--;
}
for(i=0;i<N;i++)sum[i]+=sum[i-1];
for(i=0;i<N;i++)if(sum[ans]<sum[i])ans=i;
return ans;
}
int main()
{
auto t1 = clock();
int tmp;
auto t2 = clock();
int N, C, R;
int *K, *S, *E;
tmp = scanf("%d %d %d", &N, &C, &R);
assert(tmp == 3);
K = (int*) malloc((N-1) * sizeof(int));
S = (int*) malloc(C * sizeof(int));
E = (int*) malloc(C * sizeof(int));
int i;
for (i = 0; i < N-1; i++)
{
tmp = scanf("%d", &K[i]);
assert(tmp == 1);
}
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 901
auto t4 = clock();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include<ctime>
#include<iostream>
#include <cstdio>
#include <algorithm>
struct bit
{
int tree[131073], lim;
void add(int x, int v)
{
while(x <= lim)
{
tree[x] += v;
x += x & -x;
}
}
int lbnd(int x)
{
int p = 0;
for(int i=lim/2; i; i >>= 1)
{
if(tree[p+i] < x)
{
x -= tree[p+i];
p += i;
}
}
return ++p;
}
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 902
void init(int n)
{
for(lim = 1; lim <= n; lim <<= 1);
for(int i=1; i<=n; i++) add(i,1);
}
} bit;
struct rmq
{
int tree[265000], lim;
void init(int n, int* a)
{
for(lim = 1; lim <= n; lim <<= 1);
for(int i=0; i<n; i++)
{
tree[lim + i + 1] = a[i];
}
int dx[100005];
int GetBestPosition(int N, int C, int R, int *K, int *S, int *E)
{
for (int i=0; i<C; i++)
{
S[i]++;
E[i]++;
}
bit.init(N);
rmq.init(N-1,K);
for (int i=0; i<C; i++)
{
int st = bit.lbnd(S[i]);
int ed = bit.lbnd(E[i] + 1) - 1;
for (int j=E[i]; j>S[i]; j--)
{
bit.add(bit.lbnd(j),-1);
}
S[i] = st;
E[i] = min(ed,N)-1;
if(rmq.q(S[i],E[i]) < R)
{
dx[S[i]]++;
dx[E[i]+1]--;
}
}
for (int i=1; i<=N-1; i++)
{
dx[i] += dx[i-1];
}
return (int)(max_element(dx+1,dx+N) - dx - 1);
}
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 903
int main()
{
auto t1 = clock();
int tmp;
auto t2 = clock();
int N, C, R;
int *K, *S, *E;
tmp = scanf("%d %d %d", &N, &C, &R);
assert(tmp == 3);
K = (int*) malloc((N-1) * sizeof(int));
S = (int*) malloc(C * sizeof(int));
E = (int*) malloc(C * sizeof(int));
int i;
for (i = 0; i < N-1; i++)
{
tmp = scanf("%d", &K[i]);
assert(tmp == 1);
}
for (i = 0; i < C; i++)
{
tmp = scanf("%d %d", &S[i], &E[i]);
assert(tmp == 2);
}
auto t3 = clock();
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
CAPITOLUL 8. IOI 2012 8.6. TOURNAMENT 904
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../input/input30.txt",
(char*)"tournament.out",
(char*)"../output/output30.txt",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
Botanist Somhed regularly takes groups of students to one of Thailand’s largest tropical gar-
dens.
The landscape of this garden is composed of N fountains (numbered 0, 1, , N 1) and M
trails.
Each trail connects a different pair of distinct fountains, and can be traveled in either direction.
There is at least one trail leaving each fountain. These trails feature beautiful botanical collections
that Somhed would like to see. Each group can start their trip at any fountain.
Somhed loves beautiful tropical plants. Therefore, from any fountain he and his students will
take the most beautiful trail leaving that fountain, unless it is the most recent trail taken and
there is an alternative. In that case, they will take the second most beautiful trail instead. Of
course, if there is no alternative, they will walk back, using the same trail for the second time.
Note that since Somhed is a professional botanist, no two trails are considered equally beautiful
for him.
His students are not very interested in the plants. However, they would love to have lunch
at a premium restaurant located beside fountain number P . Somhed knows that his students
will become hungry after taking exactly K trails, where K could be different for each group of
students.
Somhed wonders how many different routes he could choose for each group, given that:
each group can start at any fountain;
the successive trails must be chosen in the way described above; and
each group must finish at fountain number P after traversing exactly K trails.
Note that they may pass fountain number P earlier on their route, although they still need to
finish their route at fountain number P .
Your task
Given the information on the fountains and the trails, you have to find the answers for Q
groups of students; that is, Q values of K.
Write a procedure count_routes(N,M,P,R,Q,G) that takes the following parameters:
N - the number of fountains. The fountains are numbered 0 through N 1.
M - the number of trails. The trails are numbered 0 through M 1. The trails will be given
in decreasing order of beauty: for 0 & i $ M 1, trail i is more beautiful than trail i 1.
P - the fountain at which the premium restaurant is located.
R - a two-dimensional array representing the trails. For 0 & i $ M , trail i connects the
fountains Ri0 and Ri1. Recall that each trail joins a pair of distinct fountains, and
no two trails join the same pair of fountains.
39
argint: Vlad Alexandru Gavrilă, ICHB (Bucureşti)
. argint: Adrian Budău, ICHB (Bucureşti)
. argint: Andrei Purice, IL Caragiale (Ploieşti)
. 253p: Mihai-Dan Gheorghe, ICHB (Bucureşti).
905
CAPITOLUL 9. IOI 2011 9.1. TROPICAL GARDEN 906
For 0 & i $ Q, your procedure must find the number of possible routes with exactly Gi trails
that group i could possibly take to reach fountain P . For each group i, your procedure should
call the procedure answer(X) to report that the number of routes is X. The answers must be
given in the same order as the groups. If there are no valid routes, your procedure must call
answer(0).
Examples
Example 1
Consider the case shown in Figure 1,
where N=6, M=6, P=0, Q=1, G[0]=3, and
1 2
0 1
0 3
R=
3 4
4 5
1 5
Note that trails are listed in decreasing order of beauty.
That is, trail 0 is the most beautiful one, trail 1 is the second
most beautiful one, and so on.
There are only two possible valid routes that follow 3 trails:
1 2 1 0, and
5 4 3 0.
The first route starts at fountain 1. The most beautiful trail from here leads to fountain 2. At
fountain 2, the group has no choice, they must return using the same trail. Back at fountain 1,
the group will now avoid trail 0 and choose trail 1 instead. This trail does indeed bring them to
the fountain P 0.
Thus, the procedure should call answer(2).
Example 2
Consider the case shown in Figure 2,
where N=5, M=5, P=2, Q=2, G[0]=3, G[1]=1, and
1 0
1 2
R= 3 2
1 3
4 2
For the first group, there is only one valid route that
reaches fountain 2 after following 3 trails: 1 0 1
2.
For the second group, there are two valid routes that reach
fountain 2 after following 1 trail: 3 2, and 4 2.
Therefore, the correct implementation of count_routes should first call answer(1) to
report the answer for the first group, and then call answer(2) to report the answer for the
second group.
Subtasks
Subtask 1 (49 points)
2 & N & 1 000
1 & M & 10 000
Q 1
each element of G is an integer between 1 and 100, inclusive.
Q 1
each element of G is an integer between 1 and 1 000 000 000, inclusive.
Implementation details
Limits
CPU time limit: 5 seconds
Memory limit: 256 MB
Note: There is no explicit limit for the size of stack memory. Stack memory counts towards
the total memory usage.
Interface (API)
Implementation folder: garden/
To be implemented by contestant: garden.c or garden.cpp or garden.pas
Contestant interface: garden.h or garden.pas
Grader interface: gardenlib.h or gardenlib.pas
Sample grader: grader.c or grader.cpp or grader.pas
Sample grader input: grader.in., grader.in.2, ...
Note: The sample grader reads the input in the following format:
– Line 1: N , M , and P .
– Lines 2 to M 1: description of the trails; i.e., line i 2 contains Ri0 and Ri1,
separated by a space, for 0 & i $ M .
– Line M 2: Q.
– Line M 3: array G as a sequence of space-separated integers.
– Line M 4: array of expected solutions as a sequence of space-separated integers.
Expected output for sample grader input: grader.expect.1, grader.expect.2, ...
For this task, each one of these files should contain precisely the text ”Correct.”
In this task, we would like to compute the number of possible paths that could have led each
group to the specified intersection P , using the given number of steps K.
Notice that each path is completely determined by its initial intersection. Thus, to compute
the number of possible paths, we only need to check whether each intersection, if used as an initial
intersection, would bring the group to intersection P after exactly K steps. As we need to check
all N initial intersections for each of the Q groups, an efficient algorithm for checking whether
the group will be at intersection P after exactly K steps is needed, which will be discussed in
following sections.
1 Graph construction
This problem can be treated as a graph problem. A natural approach is to construct a graph
G containing the following information: for each intersection, where the group would move to.
Since they may take only one of the two most beautiful trails, we will use two vertices to represent
an intersection. Namely, for the i-th intersection, let vi represent this intersection where the next
¬
chosen trail must be the most beautiful trail incident to it, and vi represent this same intersection
but where the next chosen trail must be the second most beautiful trail incident to it (or the most
beautiful trail if no alternative is available). In other words, vi represents the i-th intersection when
CAPITOLUL 9. IOI 2011 9.1. TROPICAL GARDEN 908
¬
the last taken trail is not the most beautiful trail incident to this intersection, and vi represents
this intersection when the last taken trial is the most beautiful one incident to this intersection.
Now for each vertex, we add an outgoing edge representing the most beautiful or second most
beautiful trail, according to the conditions mentioned above. With this, G will contain 2N vertices,
and exactly one outgoing edge from each vertex.
The construction of the graph G takes O M N running time by first creating 2N vertices,
then scanning through the array R representing trails, and conditionally adding these edges to G
under the described conditions.
2 An O M N KQ solution
A simple way to check where the couple would arrive after K steps is to simulate their path,
for each intersection as an initial vertex. Since they always choose the most beautiful trail in the
first steps, the corresponding starting vertices in G are v0 , ..., vN 1 .
To simulate their walk, we simply start at some vertex vs , then follow the unique outgoing
edge for that vertex, and repeat this process for K steps. Since the vertices corresponding to
¬
intersection P are vP and vP , then this path ends at this intersection if and only if after K steps,
we stop at one of these vertices. That is, to find the number of possible paths, we simulate their
walk for all possible initial vertices vi , and count the number of starting vertices that end at vP
¬
or vP after K steps.
Clearly, this process takes O K total running time for each starting vertex. Since there are
N possible starting vertices and Q questions, this algorithm takes O M N KQ running time,
including graph construction. This running time is sufficient to fully solve subtask 1.
3 An O M N Q log K solution
As K becomes large in subtask 2, we need a better way to simulate the algorithm mentioned
in the previous section. Notice that the edges in G represents 1-step traveling. To simulate faster,
we will use the permutation-composition approach.
k
We first precompute the result of 2 -step traveling from each vertex in G, where k 0, 1, 2, ...,
using a technique similar to successive squaring. Let Tv,2k represents the vertex we arrive at after
k
traveling from v for 2 steps. Then for k 0, 1, 2, ..., we can compute Tv,2k easily:
If k 0, then the destination is specified in G; otherwise, we compose the two paths of length
k1
2 using the formula
Tv,2k TTv,2k1 ,2k1 .
k k1
In other words, traveling 2 steps from v is the same as traveling 2 steps from v, then from
k1
that vertex, continue for 2 more steps.
Then, notice that for each value of K, we can decompose this number into sum of distinct,
non-negative powers of two. Suppose that K 2 1 2 2 ... 2 l where k1 $ k2 $ ... $ kl for some
k k k
positive integer l. Then the result of traveling k steps from v can be found by simply composing
k k k
travelings of 2 1 , 2 2 , ..., 2 l that we have precomputed. Using this technique, therefore, we can
compute the destination for each starting intersection in O log K running time.
Note that since K $ 2 , we only need to compute Tv,2k for k 0, 1, 2, ..., 29.
30
This algorithm takes O N log K extra running time to compute the values of Tv,2k , as each
of them can be computed in constant time. Then, we can find the destination of each path in
O log K . Thus, the total running time is O M N Q log K , which is sufficient to fully solve
subtask 2.
4 An O M N Q solution
Let us consider a more general question of determining whether a path starting at vertex s
with length K ends at vertex t. Recall that each vertex in G has exactly one outgoing edge. So,
from any initial vertex, by simply following these edges, we will eventually enter a cycle. Thus, if
we start at s, exactly one of the following conditions are met:
We never reach t.
We reach t just once exactly after some number of steps F . In this case, t is reachable, but
is not on any cycle.
We reach t for the first time after some number of steps F , and enter it every C steps. In
this case, t is reachable, and is on a cycle of size C.
CAPITOLUL 9. IOI 2011 9.1. TROPICAL GARDEN 909
For our purpose of solving the problem, s can vary depending on our initial vertex; namely, it
¬
can be any of the vertices vi for i 0, 1, ..., N 1. However, t can only be vertices vP and vP .
Since t does not vary very much, it is easier to check whether t is on a cycle, and whether it is
possible to reach t from s.
T
To solve this problem, we create the graph G , which is the same as graph G with its edges
reversed. Then, we perform a depth-first search on this graph starting at t. During this search,
we keep track of the distance of each reachable vertex from t. This number is the distance from s
to t in G; that is, the number of steps F that brings us from s to t for the first time. At the same
time, if we reach some vertex with a departing edge to t, then we obtain the size of the cycle C,
which is the distance from t to that vertex plus 1.
Thus, whether the path in G starting at s with length K ends at t can be determined as
following:
T
If we cannot reach s in G , then this path in G cannot end at t.
T
If we reach s in G after F steps, but t is not on a cycle, then this path in G ends at t if
and only if K F .
T
If we reach s in G after F steps, and t is in a cycle of size C, then this path in G ends at t
if and only if K F nC for some non-negative integer n.
For our task, the path starting at the i-th intersection with length K will end at intersection
¬
P if and only if the path in G starting at vi with length K ends at vP or vP . Note that during
T
the implementation, we do not need to create graph G, but we can create G directly. It is also
convenient to first create an array for storing Fs for each vertex s. We then initialize Fs and C
to 1, and update them during the depth-first search. We perform the search twice, starting at vP
¬
and vP , respectively.
Since the depth-first search takes O M N running time and each query can be checked in
constant running time, this algorithm takes O M N Q running time in total, which is sufficient
to obtain full marks for this task.
#include "garden.h"
#include "gardenlib.h"
#include<ctime>
#include<iostream>
#include <cstdio>
#include <vector>
#include <initializer_list>
static int N, M, P, Q;
static int R[MAX_M][2];
static int G[MAX_Q];
static int solutions[MAX_Q];
static int answers[MAX_Q];
static int answer_count;
int outlist[2*MAXN];
vector<int> inlist[2*MAXN];
bool visit[2*MAXN];
int ans1[2*MAXN], ans2[2*MAXN];
void run(int P, int dist, int *ans, int &res, int oP)
{
if(visit[P])
{
if(P == oP) res = dist;
return;
}
visit[P] = true;
if(P<N) ans[dist]++;
for(auto x: inlist[P])
run(x, dist+1, ans, res, oP);
}
void count_routes(int _N, int M, int P, int R[][2], int Q, int G[])
{
N = _N;
for(int i=0; i<N; ++i) minv1[i] = minv2[i] = -1;
for(int i=0; i<M; ++i)
{
int u = R[i][0], v = R[i][1];
for(int x: {u, v})
{
int y = u+v-x;
if(minv1[x] == -1) minv1[x] = y;
else if(minv2[x] == -1) minv2[x] = y;
}
}
void read_input()
{
int i;
my_assert(3==scanf("%d %d %d",&N,&M,&P));
for(i=0; i<M; i++)
my_assert(2==scanf("%d %d",&R[i][0],&R[i][1]));
my_assert(1==scanf("%d",&Q));
for(i=0; i<Q; i++)
my_assert(1==scanf("%d",&G[i]));
for(i=0; i<Q; i++)
my_assert(1==scanf("%d",&solutions[i]));
CAPITOLUL 9. IOI 2011 9.1. TROPICAL GARDEN 911
void answer(int x)
{
if(answer_count>=Q)
{
printf("Incorrect. Too many answers.\n");
exit(0);
}
answers[answer_count] = x;
answer_count++;
}
int main()
{
auto t1 = clock();
int correct, i;
read_input();
auto t2 = clock();
answer_count = 0;
count_routes(N,M,P,R,Q,G);
auto t3 = clock();
if(answer_count!=Q)
{
printf("Incorrect. Too few answers.\n");
exit(0);
}
correct = 1;
for(i=0; i<Q; i++)
if(answers[i]!=solutions[i])
correct = 0;
if(correct)
printf("Correct.\n");
else
{
printf("Incorrect.\n");
printf("Expected: ");
for(i=0; i<Q; i++)
printf("%d ",solutions[i]);
printf("\nReturned: ");
for(i=0; i<Q; i++)
printf("%d ",answers[i]);
}
auto t4 = clock();
#include "garden.h"
#include "gardenlib.h"
#include<ctime>
#include<iostream>
static int N, M, P, Q;
static int R[MAX_M][2];
static int G[MAX_Q];
static int solutions[MAX_Q];
static int answers[MAX_Q];
static int answer_count;
#include <cstring>
if(!chk[p % 2][arr[x]])
f(arr[x], p);
if(dis[p % 2][arr[x]])
dis[p % 2][x] = dis[p % 2][arr[x]] + 1;
}
if(mem1[x] == -1)
mem1[x] = y;
else if(mem2[x] == -1)
mem2[x] = y;
if(mem1[y] == -1)
mem1[y] = x;
else if(mem2[y] == -1)
mem2[y] = x;
}
CAPITOLUL 9. IOI 2011 9.1. TROPICAL GARDEN 913
if(mem2[i] != -1)
{
if(mem1[mem2[i]] == i && mem2[mem2[i]] != -1)
arr[2 * i + 1] = 2 * mem2[i] + 1;
else
arr[2 * i + 1] = 2 * mem2[i];
}
}
if(!c[0])
c[0] = c[1];
if(!c[1])
c[1] = c[0];
for(int i = 0; i < Q; i++)
{
int ans = 0;
for(int r=0;r<2;r++)
{
int t = G[i];
if(t > 2 * N && c[r])
t -= ((t - 2 * N + c[r] - 1) / c[r]) * c[r];
if(t <= 2 * N)
ans += sum[r][t];
}
answer(ans);
}
}
void read_input()
{
int i;
my_assert(3==scanf("%d %d %d",&N,&M,&P));
for(i=0; i<M; i++)
my_assert(2==scanf("%d %d",&R[i][0],&R[i][1]));
my_assert(1==scanf("%d",&Q));
for(i=0; i<Q; i++)
my_assert(1==scanf("%d",&G[i]));
for(i=0; i<Q; i++)
my_assert(1==scanf("%d",&solutions[i]));
}
void answer(int x)
CAPITOLUL 9. IOI 2011 9.1. TROPICAL GARDEN 914
{
if(answer_count>=Q)
{
printf("Incorrect. Too many answers.\n");
exit(0);
}
answers[answer_count] = x;
answer_count++;
}
int main()
{
auto t1 = clock();
int correct, i;
read_input();
auto t2 = clock();
answer_count = 0;
count_routes(N,M,P,R,Q,G);
auto t3 = clock();
if(answer_count!=Q)
{
printf("Incorrect. Too few answers.\n");
exit(0);
}
correct = 1;
for(i=0; i<Q; i++)
if(answers[i]!=solutions[i])
correct = 0;
if(correct)
printf("Correct.\n");
else
{
printf("Incorrect.\n");
printf("Expected: ");
for(i=0; i<Q; i++)
printf("%d ",solutions[i]);
printf("\nReturned: ");
for(i=0; i<Q; i++)
printf("%d ",answers[i]);
}
auto t4 = clock();
#include "garden.h"
#include "gardenlib.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
#include <cstdio>
#include <vector>
#include <initializer_list>
static int N, M, P, Q;
static int R[MAX_M][2];
static int G[MAX_Q];
static int solutions[MAX_Q];
static int answers[MAX_Q];
static int answer_count;
#include <queue>
for(int i=0;i<N;i++)
{
to[i<<1]=(adj[i][0]<<1)|(i==adj[adj[i][0]][0]);
if(adj[i].size()>1)
{
to[i<<1|1]=(adj[i][1]<<1)|(i==adj[adj[i][1]][0]);
}
else
{
to[i<<1|1]=to[i<<1];
}
}
CAPITOLUL 9. IOI 2011 9.1. TROPICAL GARDEN 916
for(int i=0;i<N*2;i++)
{
from[to[i]].push_back(i);
}
bfs(P<<1,dist[0]);
bfs(P<<1|1,dist[1]);
int cycle[2];
cycle[0]=dist[0][P<<1]?dist[0][P<<1]:INF;
cycle[1]=dist[1][P<<1|1]?dist[1][P<<1|1]:INF;
for(int q=0; q<Q; q++)
{
int K=G[q];
int ans=0;
for(int i=0;i<N*2;i+=2)
{
if(dist[0][i]) ans+=(K>=dist[0][i]&&(K-dist[0][i])%cycle[0]==0);
if(dist[1][i]) ans+=(K>=dist[1][i]&&(K-dist[1][i])%cycle[1]==0);
}
answer(ans);
}
}
void read_input()
{
int i;
my_assert(3==scanf("%d %d %d",&N,&M,&P));
for(i=0; i<M; i++)
my_assert(2==scanf("%d %d",&R[i][0],&R[i][1]));
my_assert(1==scanf("%d",&Q));
for(i=0; i<Q; i++)
my_assert(1==scanf("%d",&G[i]));
for(i=0; i<Q; i++)
my_assert(1==scanf("%d",&solutions[i]));
}
void answer(int x)
{
if(answer_count>=Q) {
printf("Incorrect. Too many answers.\n");
exit(0);
}
answers[answer_count] = x;
answer_count++;
}
int main()
{
auto t1 = clock();
int correct, i;
read_input();
auto t2 = clock();
answer_count = 0;
count_routes(N,M,P,R,Q,G);
auto t3 = clock();
if(answer_count!=Q)
{
printf("Incorrect. Too few answers.\n");
exit(0);
}
correct = 1;
for(i=0; i<Q; i++)
if(answers[i]!=solutions[i])
correct = 0;
CAPITOLUL 9. IOI 2011 9.2. RACE 917
if(correct)
printf("Correct.\n");
else {
printf("Incorrect.\n");
printf("Expected: ");
for(i=0; i<Q; i++)
printf("%d ",solutions[i]);
printf("\nReturned: ");
for(i=0; i<Q; i++)
printf("%d ",answers[i]);
}
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/subtask3/grader.in.14",
(char*)"garden.out",
(char*)"../tests/subtask3/grader.expect.14",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
9.2 Race
Problema 2 - Race 100 de puncte
Author: Martin Fixman
CAPITOLUL 9. IOI 2011 9.2. RACE 918
In conjunction with the IOI, Pattaya City will host a race: the International Olympiad in
Racing (IOR) 2011. As the host, we have to find the best possible course for the race.
In the Pattaya-Chonburi metropolitan area, there are N cities connected by a network of N 1
highways. Each highway is bidirectional, connects two different cities, and has an integer length in
kilometers. Furthermore, there is exactly one possible path connecting any pair of cities. That is,
there is exactly one way to travel from one city to another city by a sequence of highways without
visiting any city twice.
The IOR has specific regulations that require the course to be a path whose total length is
exactly K kilometers, starting and ending in different cities. Obviously, no highway (and therefore
also no city) may be used twice on the course to prevent collisions. To minimize traffic disruption,
the course must contain as few highways as possible.
Your task
Write a procedure best_path(N,K,H,L) that takes the following parameters:
N - the number of cities. The cities are numbered 0 through N 1.
K - the required distance for the race course.
H - a two-dimensional array representing highways. For 0 & i $ N 1, highway i connects
the cities H i0 and H i1.
L - a one-dimensional array representing the lengths of the highways. For 0 & i $ N 1, the
length of highway i is Li.
You may assume that all values in the array H are between 0 and N 1, inclusive, and that
the highways described by this array connect all cities as described above. You may also assume
that all values in the array L are integers between 0 and 1 000 000, inclusive.
Your procedure must return the minimum number of highways on a valid race course of length
exactly K. If there is no such course, your procedure must return -1.
Examples
Example 1
Consider the case shown in Figure 1, where N=4, K=3,
0 1 1
H= 1 2 L= 2
1 3 4
The course can start in city 0, go to city 1, and terminate in city 2. Its
length will be exactly 1 km + 2 km = 3 km, and it consists of two highways.
This is the best possible course; therefore best_path(N,K,H,L) must return 2.
Example 2
Consider the case shown in Figure 2, where N=3, K=3,
0 1 1
H= L=
1 2 1
There is no valid course. In this case, best_path(N,K,H,L) must return -1.
Example 3
Consider the case shown in Figure 3, where N=11, K=12,
0 1 3
0 2 4
2 3 5
3 4 4
4 5 6
H= L=
0 6 3
6 7 2
6 8 5
8 9 6
8 10 7
One possible course consists of 3 highways: from city 6
via city 0 and city 2 to city 3. Another course starts in city 10 and goes via city 8 to city 6. Both
of these courses have length exactly 12 km, as required. The second one is optimal, as there is no
valid course with a single highway. Hence, best_path(N,K,H,L) must return 2.
CAPITOLUL 9. IOI 2011 9.2. RACE 919
Subtasks
Subtask 1 (9 points)
1 & N & 100
1 & K & 100
The network of highways forms the simplest possible line: For 0 &i$ N 1, highway i
connects cities i and i 1.
Implementation details
Limits
CPU time limit: 3 seconds
Memory limit: 256 MB Note: There is no explicit limit for the size of stack memory. Stack
memory counts towards the total memory usage.
Interface (API)
Implementation folder: race/
To be implemented by contestant: race.c or race.cpp or race.pas
Contestant interface: race.h or race.pas
Grader interface: race.h or racelib.pas
Sample grader: grader.c or grader.cpp or grader.pas
Sample grader input: grader.in.1, grader.in.2, ... Note: The sample grader reads
the input in the following format:
– Line 1: N and K.
– Lines 2 to N : information on the highways; i.e., line i 2 contains H i0, H i1,
and Li, separated by a space, for 0i $ N 1.
– Line N 1: the expected solution.
Expected output for sample grader input: grader.expect.1, grader.expect.2, ...
For this task, each one of these files should contain precisely the text ”Correct.”
Note that the second question is very important because if we can guarantee that the sizes of
all resulting trees are small, we can bound the number of recursion levels.
1 Finding the solution containing u
Consider the case that P contains node u. Let’s consider a simpler case where we only want
to find if there exists a path of length exactly K that contains u.
If u is one of the endpoints in P , we can find the path using one application of depth first
search (DFS).
However, if u is ”inside” P , then two of u’s adjacent nodes x and y must also be in P . Thus,
we shall find x and y.
Consider some node w adjacent to u. With one application of DFS, we can find the set Lw of
all path lengths for all paths starting at u and containing edge u, w.
Hence, to find x and y, we need to find two nodes x and y such that there exists a pair lx " Lx
and ly " Ly for which lx ly K. This can be done by DFS from u through every edge u, w
for all adjacent nodes w with careful book keeping using an array A0, ..., K of size K 1.
The running time for this step is O N .
2 Finding the right node
Our goal is to find node u such that after deleting u, each resulting trees are all sufficiently
”small”. In this case, we shall find node u such that each remaining tree has at most N 2 nodes.
We shall refer to node u as the central node.
It is not clear if such a node exists. So let’s argue about that first.
¬
Pick an arbitrary node v as a candidate. Denote by T T rv x the forest obtained by deleting
¬
v from T . For each node w adjacent to v, denote by Tw the tree containing w in T . If every tree
¬
Tw " T has at most N 2 nodes, we are done and v is the required central node.
Otherwise there exists one tree Tw that contains more than N 2 nodes. (Note that there can
be only one tree violating our criteria.) In this case, we pick w as our new candidate and repeat
the process.
This process will eventually stop at some candidate node and that’s the required central node.
To see this, note that after leaving v, we shall never go back to pick v again; since there are N
nodes, the process can repeat at most N times.
After knowing that the central node exists, there are many ways to find it. We can follow the
process directly as in the argument. But this is too slow to be useful.
The following are two procedures that fid the central node in O N log N time and O N time.
2.1 Bottom-up approach
We can find node u in a bottom-up fashion. We shall keep a priority queue Q of all ”processed”
subtrees using their sizes as weights.
We maintain, for each node, its state which can either be new or processed; initially all nodes
are new. Every node also has a weight. Initially every node has weight of 1.
We start with all leaf nodes in Q. Note that each node in Q is every node which has all but
one of its adjacent nodes processed. For each node v " Q, we denote by p v the unique neighbor
of v which is new.
While there are nodes in Q, we extract node v with the smallest weight. We update v state
to processed and increase the weight of p v by v’s weight. If all but one neighbor of p v are
processed, we insert v into Q.
Using this procedure, the last node inserted to Q is the desired central node.
2.2 DFS with bookkeeping
With DFS and a good bookkeeping, we can find the central node in O N .
We pick an arbitrary node r to start a DFS. With this procedure, we can consider T as rooted
at r and the parent-child relationship between adjacent pairs of nodes are clearly defined.
While performing DFS, we compute, for each node v, the number of its descendants D v .
With this information, we can figure out if a candidate u is the central node. For each node w
adjacent to u, if w is one of u’s children, the size of the resulting tree containing w after deleting
CAPITOLUL 9. IOI 2011 9.2. RACE 921
u is D w 1. If w is u’s parent, the size of the resulting tree containing w after deleting u is
n1 = D v 1,
v "Ch u
where Ch u are a set of children of u. If the size of each resulting tree is at most N 2, u is the
desired central node. The time needed to check u is proportional to u’s degree. Therefore, we can
check all nodes in time O N .
3 Running time
Let T N be the worst-case running time when the tree has N nodes. We can write the
recurrence as
T N A N cN =
T Ni ,
i
where A N is the time for finding u, Ni is the size of the i-th new trees, and c is some
constant.
Since we know that Ni & N ©2, there are at most O log N levels of the recursion.
If we use O N -time to find u, each level would run in time O N and the total running time
is O N log N . If we use a slower O N log N -time procedure, the total running time will be
2
O N log N .
4 Notes
There are other heuristics for finding u that do not always work. Here are some examples.
#include "race.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
static int N, K;
static int H[MAX_N][2];
static int L[MAX_N];
static int solution;
#include <vector>
#include <algorithm>
#include <unordered_map>
void f(int x, int par, unordered_map <int, int> &d, int &L, int &W)
CAPITOLUL 9. IOI 2011 9.2. RACE 922
{
d[0] = 0;
for (auto &y : v[x])
{
if (y.x == par) continue;
unordered_map <int, int> d2;
int L2 = 0, W2 = 0;
f(y.x, x, d2, L2, W2);
L2++;
W2 += y.w;
if (d.size() < d2.size())
{
d.swap(d2);
swap(L, L2);
swap(W, W2);
}
return ans;
}
void read_input()
{
int i;
my_assert(2==scanf("%d %d",&N,&K));
for(i=0; i<N-1; i++)
my_assert(3==scanf("%d %d %d",&H[i][0],&H[i][1],&L[i]));
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
int ans;
read_input();
auto t2 = clock();
ans = best_path(N,K,H,L);
auto t3 = clock();
if(ans==solution)
printf("Correct.\n");
else
printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
auto t4 = clock();
return 0;
}
#include<ctime>
#include<iostream>
static int N, K;
static int H[MAX_N][2];
static int L[MAX_N];
static int solution;
#include <bits/stdc++.h>
typedef pair<int,int> P;
#define F first
#define S second
#define PB push_back
#define INF 1000000000
int n,k,vs[200005],w[200005],la[200005],ans=INF;
vector<P>g[200005];
map<int,int>m[200005];
if(m[vx].find(k-w[vx]-w[vy]-i->F)!=m[vx].end())
ans=min(ans,m[vx][k-w[vx]-w[vy]-i->F] + i->S + la[vx]+la[vy]);
}
for(map<int,int>::iterator i=m[vy].begin();i!=m[vy].end();i++)
{
int c=i->F-w[vx]+w[vy];
if(m[vx].find(c)!=m[vx].end())
m[vx][c]=min(m[vx][c],i->S-la[vx]+la[vy]);
else
m[vx][c]=i->S-la[vx]+la[vy];
}
vs[y]=vx;
}
for(int i=0;i<n;i++)
vs[i]=i,m[i][0]=0;
dfs(0,-1);
if(ans==INF)return -1;
else return ans;
}
void read_input()
{
int i;
my_assert(2==scanf("%d %d",&N,&K));
for(i=0; i<N-1; i++)
my_assert(3==scanf("%d %d %d",&H[i][0],&H[i][1],&L[i]));
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
int ans;
read_input();
auto t2 = clock();
ans = best_path(N,K,H,L);
auto t3 = clock();
CAPITOLUL 9. IOI 2011 9.2. RACE 925
if(ans==solution)
printf("Correct.\n");
else
printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
auto t4 = clock();
return 0;
}
#include "race.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
static int N, K;
static int H[MAX_N][2];
static int L[MAX_N];
static int solution;
#include <bits/stdc++.h>
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int rnd(int l,int r){return l+rng()%(r-l+1);}
//#define unx 1
#ifndef unx
#include "race.h"
#endif
int n,cnt,k,ret;
int sz[NN],dd[NN],f[NN*5];
vector<ii> val;
vector<ii> ad[NN];
void ctr(int u)
{
cnt=0;
dfs1(u);
dd[u=ftr(u)]=1;
f[0]=0;
vector<int> reval;
forv(v,ad[u])
if(!dd[v.fi])
{
dfs2(v.fi,u,v.se,1);
forv(i,val)
if(f[k-i.fi]>-1)
ret=min(ret,i.se+f[k-i.fi]);
forv(i,val)
f[i.fi]=f[i.fi]<0 ? i.se :
min(f[i.fi],i.se), reval.push_back(i.fi);
val.clear();
}
forv(i,reval) f[i]=-1;
forv(v,ad[u])
if(!dd[v.fi]) ctr(v.fi);
}
ctr(0);
return ret<n ? ret : -1;
}
void read_input()
{
int i;
my_assert(2==scanf("%d %d",&N,&K));
for(i=0; i<N-1; i++)
my_assert(3==scanf("%d %d %d",&H[i][0],&H[i][1],&L[i]));
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
int ans;
read_input();
auto t2 = clock();
ans = best_path(N,K,H,L);
auto t3 = clock();
if(ans==solution)
printf("Correct.\n");
else
printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/subtask4/grader.in.16",
(char*)"rase.out",
(char*)"../tests/subtask4/grader.expect.16",
CAPITOLUL 9. IOI 2011 9.3. RICE HUB 928
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
In the countryside, you can find a long straight road known as the Rice Way. Along this road
there are R rice fields. Each field is located at an integer coordinate between 1 and L, inclusive.
The rice fields will be presented in non-decreasing order of their coordinates. Formally, for
0 & i $ R, rice field i is at coordinate X i. You may assume that 1 & X 0 & ... & X R 1 & L.
Please note that multiple rice fields may share the same coordinate.
We plan to construct a single rice hub as a common place to store as much of the harvest as
possible. As with the rice fields, the hub has to be at an integer coordinate between 1 and L,
inclusive.
The rice hub can be at any location, including one that already contains one or more rice fields.
Each rice field produces exactly 1 truckload of rice every harvest season. To transport the rice
to the hub, the city has to hire a truck driver. The driver charges 1 Baht to transport a truckload
of rice per unit of distance towards the hub. In other words, the cost of transporting rice from a
given field to the rice hub is numerically equal to the difference between their coordinates.
Unfortunately, our budget for this season is tight: we may only spend at most B Baht on
transportation. Your task is to help us strategically place the hub to gather as much rice as
possible.
Your task
Write a procedure besthub(R,L,X,B) that takes the following parameters:
R - the number of rice fields. The fields are numbered 0 through R 1.
L - the maximum coordinate.
X - a one-dimensional array of integers sorted from smallest to largest. For each 0 & i $ R,
field i is located at X i.
B - the budget.
Your procedure must find an optimal location of the hub and return the maximum number of
truckloads of rice that can be transported to the hub within the budget.
Note that the total cost of transporting the rice can be very large. The budget is given as a
64-bit integer, and we recommend that you use 64-bit integers in your computation. In C/C++,
use the type long long; in Pascal, use the type Int64.
Example
1
2
Consider the case where R 5, L 20, B 6, and X = 10
12
14
CAPITOLUL 9. IOI 2011 9.3. RICE HUB 929
For this case, there are multiple optimal locations for the hub: you can place it anywhere
between locations 10 and 14, inclusive. The figure above shows one of these optimal locations.
You will then be able to transport rice from fields at coordinates 10, 12, and 14. For any optimal
hub location, the total cost of this transportation will be at most 6 Baht. Clearly, no hub location
will allow us to gather rice from more than three fields, hence this solution is optimal and besthub
should return 3.
Subtasks
Subtask 1 (17 points)
1 & R & 100
1 & L & 100
0 & B & 10 000
No two rice fields share the same coordinate (only for this subtask).
Implementation details
Limits
CPU time limit: 1 second
Memory limit: 256 MB Note: There is no explicit limit for the size of stack memory. Stack
memory counts towards the total memory usage.
Interface (API)
Implementation folder: ricehub/
To be implemented by contestant: ricehub.c or ricehub.cpp or ricehub.pas
Contestant interface: ricehub.h or ricehub.pas
Sample grader: grader.c or grader.cpp or grader.pas
Sample grader input: grader.in.1, grader.in.2, ...
Note: The sample grader reads the input in the following format:
– Line 1: R, L, and B.
– Lines 2 to R 1: locations of rice fields; i.e., line i 2 contains X i, for 0 & i $ R.
– Line R 2: the expected solution.
Expected output for sample grader input: grader.expect.1, grader.expect.2, ...
For this task, each one of these files should contain precisely the text ”Correct.”
CAPITOLUL 9. IOI 2011 9.3. RICE HUB 930
The key insight to solving this problem is the observation that for any K rice fields located
at r0 & r1 & ... & rK 1 , the transportation cost from all these K fields is minimized by placing
the rice hub at a median. For example, when K 1, the hub should be at r0 , and when K 2,
placing it between r0 and r1 is optimal.
In this problem, we will place the rice hub at rK ©2$ for simplicity.
Following this observation, we denote a solution by a sequence S N
r0 , ..., rR1 and let ¶S ¶
denote the length of S, which is the solution’s value (the number of rice fields whose rice will be
transported to the hub). The cost of S is
cost S = ¶r j h S ¶,
rj "S
where p s t©2$.
2
This O R algorithm suffices to solve subtask 3.
3 An O R log R solution
Applying a binary search to find the right length in place of a linear search improves the
running time to O R log R and suffices to solve all subtasks.
4 An O R solution
We replace binary search with a variant of linear search carefully designed to take advantage
of the feedback obtained each time we examine a combination of rice fields. In particular, imagine
adding in the rice fields one by one. In iteration i, we add ri and find (1) Si i, the best solution
that uses only (a subsequence of) the first i rice fields (i.e., Si N
r0 , ..., ri 1, and (2) Si , the
best solution that uses only (a subsequence of) the first i rice fields and contains ri 1.
This can be computed inductively as follows. As a base case, when i 0, both Si and Si
are just
r0 and cost 0, which is within the budget B ' 0. For the inductive case, assume that
Si and Si are known. Now consider that Si1 is Si appended with ri , denoted by Si ri , if the
cost cost Si ri is at most B, or otherwise it is the longest prefix of Si ri that costs at most
B. Futhermore, Si1 is the better of Si and Si1 . To implement this, we represent each Si by its
starting point s and ending point t; thus, each iteration involves incrementing t and possibly s,
but s is always at most t.
CAPITOLUL 9. IOI 2011 9.3. RICE HUB 931
Since cost
rs , ..., rt takes O 1 to compute, the running time of this algorithm is O R and
suffices to solve all subtasks.
#include "ricehub.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
static int R, L;
static long long B;
static int X[MAX_R];
static int solution;
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
int ans;
read_input();
auto t2 = clock();
ans = besthub(R,L,X,B);
auto t3 = clock();
if(ans==solution)
printf("Correct.\n");
else
CAPITOLUL 9. IOI 2011 9.3. RICE HUB 932
auto t4 = clock();
return 0;
}
#include<ctime>
#include<iostream>
static int R, L;
static long long B;
static int X[MAX_R];
static int solution;
#include <bits/stdc++.h>
n = R; lim = B;
for(i=0; i<n; ++i)
x[i] = X[i], s[i] = s[i-1] + x[i];
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
int ans;
read_input();
auto t2 = clock();
ans = besthub(R,L,X,B);
auto t3 = clock();
if(ans==solution)
printf("Correct.\n");
else
printf("Incorrect. Returned %d instead of %d.\n",ans,solution);
auto t4 = clock();
return 0;
}
#include<ctime>
#include<iostream>
static int R, L;
static long long B;
static int X[MAX_R];
CAPITOLUL 9. IOI 2011 9.3. RICE HUB 934
#include<bits/stdc++.h>
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
int ans;
read_input();
auto t2 = clock();
ans = besthub(R,L,X,B);
auto t3 = clock();
if(ans==solution)
printf("Correct.\n");
else
printf("Incorrect. Returned %d instead of %d.\n",ans,solution);
auto t4 = clock();
return 0;
CAPITOLUL 9. IOI 2011 9.3. RICE HUB 935
#include "ricehub.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
static int R, L;
static long long B;
static int X[MAX_R];
static int solution;
#include <vector>
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
CAPITOLUL 9. IOI 2011 9.3. RICE HUB 936
int ans;
read_input();
auto t2 = clock();
ans = besthub(R,L,X,B);
auto t3 = clock();
if(ans==solution)
printf("Correct.\n");
else
printf("Incorrect. Returned %d instead of %d.\n",ans,solution);
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/subtask4/grader.in.19",
(char*)"rasehub.out",
(char*)"../tests/subtask4/grader.expect.19",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
In the worst case, Benjamas will reach an exit chamber in 7 units of time. Hence,
travel_plan should return 7.
Example 2
Consider the case shown in Figure 2,
where N=5, M=7, K=2, and
0 2 4
0 3 3
3 2 2
1
R= 2 1 L = 10 P=
3
0 1 100
0 4 7
3 4 9
Here is an optimal escape plan:
If you ever reach chamber 0, take the corridor leading to chamber 3. However, if that corridor
is blocked, then take the corridor leading to chamber 2.
If you ever reach chamber 2, take the corridor leading to chamber 3. However, if that corridor
is blocked, then take the corridor leading to chamber 1.
Don’t bother about chamber 4; according to this escape plan you cannot possibly reach it.
Benjamas will reach one of the exit chambers no later than after 14 units of time. Therefore,
travel_plan should return 14.
Subtasks
Subtask 1 (46 points)
3 & N & 1 000.
The underground city is a tree. That is, M N 1 and for each pair of chambers i and j
there is a sequence of corridors connecting i and j.
Every exit chamber is connected to exactly one other chamber.
Any other chamber is connected directly to three or more other chambers.
Implementation details
Limits
CPU time limit: 2 seconds
CAPITOLUL 9. IOI 2011 9.4. CROCODILE’S UNDERGROUND CITY 939
Interface (API)
Implementation folder: crocodile/
To be implemented by contestant: crocodile.c or crocodile.cpp or crocodile.pas
Contestant interface: crocodile.h or crocodile.pas
Grader interface: crocodile.h or crocodilelib.pas
Sample grader: grader.c or grader.cpp or grader.pas and crocodilelib.pas
Sample grader input: grader.in.1, grader.in.2, ...
Note: The sample grader reads the input in the following format:
– Line 1: N , M , and K.
– Lines 2 to M 1: For 0 & i $ M , line i 2 contains Ri0, Ri1, and Li,
separated by a space.
– Line M 2: a list of K integers P 0, P 1, ..., P K 1, separated by a space.
– Line M 3: the expected solution.
Expected output for sample grader input: grader.expect.1, grader.expect.2, ...
For this task, each one of these files should contain precisely the text ”Correct.”
A moment’s thought reveals striking similarity between Dijkstra’s single-source shortest path
algorithm and our algorithm for trees. Indeed, the algorithm iteratively grows the frontier set,
where at any point in time, a node u is in the set if T u has been determined. From this view, our
algorithm for trees can be seen as running Dijkstra’s algorithm starting from the exit chambers.
The algorithm is standard except for how the cost at a node is defined.
Consider the following algorithm: For all nodes u, set T u to 1 except when u is an exit
chamber, set T u 0. Initially, the frontier set S contains exactly the exit chambers. During
the execution of the algorithm, we maintain that for w S, the cost of w can be conceptually
computed by producing the list rv " N w T v L w, v x, sorting this list, and returning
40
the second value (i.e., the second smallest value in this list). When a node u enters the frontier
(it has the lowest cost among non-frontier nodes), T u is set to the cost of u at that moment.
Claim 1. For each node u, Benjamas can reach an exit from u in T u time regardless of
what the gatekeeper does. Furthermore, the crocodile gatekeeper can force Benjamas to spend T u
time in the underground city.
This claim can be shown by a similar inductive argument as in the tree case and by observing
that as in Dijkstra’s algorithm, once a node enters the frontier its cost cannot decrease because
the edges have positive cost.
Implementation Details. For each node, we can maintain its cost by keeping two numbers
- the smallest value and the second smallest value - which can be updated in O 1 when the
neighboring values change. Using this, Dijkstra’s algorithm takes O M N log N using a heap
2
or O N without using one.
#include "crocodile.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
static int N, M;
static int R[MAX_M][2];
static int L[MAX_M];
static int K;
static int P[MAX_N];
static int solution;
#include <vector>
#include <queue>
#include <utility>
int travel_plan(int N, int M, int R[][2], int L[], int K, int P[])
{
40
N w denotes the set of neighbors of w
CAPITOLUL 9. IOI 2011 9.4. CROCODILE’S UNDERGROUND CITY 941
while (!pq.empty())
{
pi x = pq.top();
pq.pop();
if(v0[x.second] == 0)
{
v0[x.second] = 1;
continue;
}
if(v1[x.second]) continue;
v1[x.second] = 1;
if(x.second == 0) return x.first;
for (int i=0; i<graph[x.second].size(); i++)
{
pi t = graph[x.second][i];
if(v1[t.second]) continue;
pq.push(pi(t.first + x.first,t.second));
}
}
void read_input()
{
int i;
my_assert(3==scanf("%d %d %d",&N,&M,&K));
for(i=0; i<M; i++)
my_assert(3==scanf("%d %d %d",&R[i][0],&R[i][1],&L[i]));
for(i=0; i<K; i++)
my_assert(1==scanf("%d",&P[i]));
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
int ans;
read_input();
auto t2 = clock();
ans = travel_plan(N,M,R,L,K,P);
auto t3 = clock();
if(ans==solution)
printf("Correct.\n");
else
printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
auto t4 = clock();
return 0;
}
#include "crocodile.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
static int N, M;
static int R[MAX_M][2];
static int L[MAX_M];
static int K;
static int P[MAX_N];
static int solution;
#include <queue>
#define NN 100000
#define MM 1000000
#define INF 1000000000
struct Inque
{
int x;
int w;
Inque(int _x=0,int _w=0):x(_x),w(_w){}
bool operator<(const Inque &r)const
{
return w>r.w;
}
};
int sta[NN+1],chi[MM*2+1],wei[MM*2+1],nxt[MM*2+1],m,n;
int d[2][NN+1];
bool v[NN+1];
priority_queue<Inque> Q;
int travel_plan(int _n, int _m, int R[][2], int L[], int K, int P[])
{
int i,j;
CAPITOLUL 9. IOI 2011 9.4. CROCODILE’S UNDERGROUND CITY 943
n=_n; m=_m;
for(i=0;i<m;i++)
{
addEdge(R[i][0],R[i][1],L[i],i*2+1);
addEdge(R[i][1],R[i][0],L[i],i*2+2);
}
for(i=0;i<n;i++)
{
for(j=0;j<2;j++) d[j][i]=INF+1;
}
for(i=0;i<K;i++)
{
for(j=0;j<2;j++) d[j][P[i]]=0;
Q.push(Inque(P[i],0));
}
for(i=0;i<n;i++)
{
while(!Q.empty() && v[Q.top().x]) Q.pop();
if(Q.empty()) break;
Inque t=Q.top(); Q.pop();
if(t.x==0) break;
v[t.x]=true;
for(j=sta[t.x];j;j=nxt[j])
{
bool l=true;
if(d[0][chi[j]]>t.w+wei[j])
{
d[1][chi[j]]=d[0][chi[j]];
d[0][chi[j]]=t.w+wei[j];
}
else
if(d[1][chi[j]]>t.w+wei[j])
{
d[1][chi[j]]=t.w+wei[j];
}
else
{
l=false;
}
if(l)
{
if(d[1][chi[j]]!=INF+1)
{
Q.push(Inque(chi[j],d[1][chi[j]]));
}
}
}
}
return d[1][0];
}
void read_input()
{
int i;
my_assert(3==scanf("%d %d %d",&N,&M,&K));
for(i=0; i<M; i++)
my_assert(3==scanf("%d %d %d",&R[i][0],&R[i][1],&L[i]));
for(i=0; i<K; i++)
my_assert(1==scanf("%d",&P[i]));
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
int ans;
read_input();
auto t2 = clock();
ans = travel_plan(N,M,R,L,K,P);
auto t3 = clock();
if(ans==solution)
printf("Correct.\n");
else
printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
auto t4 = clock();
return 0;
}
#include "crocodile.h"
#include<ctime>
#include<iostream>
static int N, M;
static int R[MAX_M][2];
static int L[MAX_M];
static int K;
static int P[MAX_N];
static int solution;
#include <bits/stdc++.h>
head[u]=cnt++;
}
int travel_plan(int N, int M, int R[][2], int L[], int K, int P[])
{
for (int i=0;i<N;i++){vis[i]=0;head[i]=-1;}
for (int i=0;i<M;i++)
{
add(R[i][0],R[i][1],L[i]);
add(R[i][1],R[i][0],L[i]);
}
while(!Q.empty())
{
int dis=Q.top().first,u=Q.top().second;Q.pop();
if (++vis[u]!=2)continue;
if (u==0)return dis;
for (int i=head[u];i!=-1;i=a[i].nxt)
Q.push(make_pair(dis+a[i].d,a[i].v));
}
void read_input()
{
int i;
my_assert(3==scanf("%d %d %d",&N,&M,&K));
for(i=0; i<M; i++)
my_assert(3==scanf("%d %d %d",&R[i][0],&R[i][1],&L[i]));
for(i=0; i<K; i++)
my_assert(1==scanf("%d",&P[i]));
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
int ans;
read_input();
auto t2 = clock();
ans = travel_plan(N,M,R,L,K,P);
auto t3 = clock();
if(ans==solution)
printf("Correct.\n");
else
printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
auto t4 = clock();
return 0;
}
CAPITOLUL 9. IOI 2011 9.4. CROCODILE’S UNDERGROUND CITY 946
#include "crocodile.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
static int N, M;
static int R[MAX_M][2];
static int L[MAX_M];
static int K;
static int P[MAX_N];
static int solution;
#include<bits/stdc++.h>
int travel_plan(int N, int M, int R[][2], int L[], int K, int P[])
{
vector<vector<pair<int, int>>> adj(N);
for(int i = 0; i < M; i++)
{
int u = R[i][0], v = R[i][1];
adj[u].emplace_back(v, L[i]);
adj[v].emplace_back(u, L[i]);
}
vector<int> vis(N);
priority_queue<pair<int, int>> Q;
for(int i = 0; i < K; i++)
{
vis[P[i]]++;
Q.emplace(0, P[i]);
}
while(!Q.empty())
{
auto [d, v] = Q.top();
Q.pop();
if(vis[v]++ == 1)
{
if(v == 0) return -d;
for(auto &[u, w] : adj[v])
Q.emplace(d - w, u);
}
}
void read_input()
{
int i;
CAPITOLUL 9. IOI 2011 9.4. CROCODILE’S UNDERGROUND CITY 947
my_assert(3==scanf("%d %d %d",&N,&M,&K));
for(i=0; i<M; i++)
my_assert(3==scanf("%d %d %d",&R[i][0],&R[i][1],&L[i]));
for(i=0; i<K; i++)
my_assert(1==scanf("%d",&P[i]));
my_assert(1==scanf("%d",&solution));
}
int main()
{
auto t1 = clock();
int ans;
read_input();
auto t2 = clock();
ans = travel_plan(N,M,R,L,K,P);
auto t3 = clock();
if(ans==solution)
printf("Correct.\n");
else
printf("Incorrect. Returned %d, Expected %d.\n",ans,solution);
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/subtask3/grader.in.7",
(char*)"crocodile.out",
(char*)"../tests/subtask3/grader.expect.7",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
CAPITOLUL 9. IOI 2011 9.5. DANCING ELEPHANTS 948
In the following act, the elephant at position 15 dances to position 32. After this act, we need
at least two cameras to take the snapshot.
In the next act, the elephant at position 10 moves to position 7. For the new arrangement of
elephants, we need three cameras to photograph all of them.
In this interactive task, you have to determine the minimum number of cameras needed to
take the pictures after each of the acts. Note that the number of cameras needed may increase,
decrease, or stay the same between acts.
Your task
Write the following procedures:
CAPITOLUL 9. IOI 2011 9.5. DANCING ELEPHANTS 949
Example
10
15
Consider the case where N 4, L 10, and the initial positions of the elephants are X =
17
20
First, your procedure init will be called with these parameters. Afterwards, your procedure
update will be called once for each act. Here is an example sequence of calls and their correct
return values:
act call parameters return value
1 update(2,16) 1
2 update(1,25) 2
3 update(3,35) 2
4 update(0,38) 2
5 update(2,0) 3
Subtasks
Subtask 1 (10 points)
There are exactly N 2 elephants.
Initially, and after each act, the positions of all elephants will be distinct.
Your procedure update will be called at most 100 times.
Subtask 5 (3 points)
1&N & 150 000.
CAPITOLUL 9. IOI 2011 9.5. DANCING ELEPHANTS 950
Implementation details
Limits
CPU time limit: 9 seconds
Note: The collection templates in the C++ Standard Library (STL) can be slow; in par-
ticular, it might not be possible to solve subtask 5 if you use them.
Memory limit: 256 MB
Note: There is no explicit limit for the size of stack memory. Stack memory counts towards
the total memory usage.
Interface (API)
Implementation folder: elephants/
To be implemented by contestant: elephants.c or elephants.cpp or elephants.pas
Contestant interface: elephants.h or elephants.pas
Sample grader: grader.c or grader.cpp or grader.pas
Sample grader input: grader.in.1, grader.in.2, ...
Note: The sample grader reads the input in the following format:
– Line 1: N , L, and M , where M is the number of acts in the show.
– Lines 2 to N 1: the initial positions; i.e., line k 2 contains X k for 0 & k $ N .
– Lines N 2 to N M 1: information on M acts; i.e. line N 1 j contains ij ,
y j , and sj , separated by a space, denoting that in the j-th act elephant ij moves
to position y j , and after that act, sj is the mininal number of cameras needed, for
1 & j & M.
Expected output for sample grader input: grader.expect.1, grader.expect.2, ...
For this task, each one of these files should contain precisely the text ”Correct.”
We maintain k buckets B0 , B1 , ..., Bk1 of elephants such that buckets with lower indices store
elephants with lower positions, i.e., for any 0 & b $ k 1, for all xi " Bb and xj " Bb1 , xi & xj .
Also, elephants in each bucket are sorted according to their positions.
The goal is to make sure that to find the number of required cameras, one needs to visit each
bucket once. For simplicity, we will always place cameras so that the left-most position covered
by a camera is the position of some elephant.
Consider bucket b with p elephants. Denote the list of indices of elephants in Bb as e0 , e1 , ..., ep1
(that is, xei & xei1 ). Given an elephant ei , we would like to answer the following two questions
quickly:
Q1: If we would like to cover all elephants starting from ei (i.e., elephants in the set
rei , ei1 , ..., ep1 x), how many cameras are needed?
Q2: What is the highest position that these set of cameras cover?
For elephant e, denote the answer for Q1 for as J e and the answer to Q2 as T e.
If we have these answers for every elephant in every bucket, we can find the number of cameras
in time O k log N as follows.
We start by placing the camera at the first elephant in bucket B0 , so that the position of this
elephant is the left-most position covered by this camera.
Now consider placing a camera at elephant e in bucket Bi in the same fashion. We know that
to cover all elephants in Bi , we have to use J e cameras and these cameras cover positions up to
T e. We find the first elephant e0 not covered by these cameras in the next bucket Bi1 by binary
searching for the elephant in Bi1 whose position is minimum but greater than T e. Then, we
start placing the camera at elephant e0 in bucket Bi1 .
We repeat this step until we reach the last bucket. Since each step runs in O log N time
(from binary search), we spend O k log N time as required.
We can precompute the answers for Q1 and Q2 for elephants in Bi in O ¶Bi ¶ time by iterating
over each elephant ej from ep1 to e0 and keeping a pointer to the first elephant outside the range
xej L. For implementation details, please see the appendix.
It is crucial to note that we can process each bucket independent of all other buckets.
3.2 Updating the data structure
When an elephant e moves, we will have to update two buckets: the current bucket Bi and the
new bucket Bj . This can be done in time proportional to the current size of the bucket. To find
the current bucket of e we can store a pointer from e, but it takes O k to find the new bucket
anyway. Therefore, the running time for the update is O k ¶Bi ¶ ¶Bj ¶.
Note that the time depends heavily on the size of each bucket. Initially, we would have about
N k elephants in each bucket, but the number may grow as elephants can move. To keep the
size of each bucket bounded above by O N ©k , we will rebuild the whole data structure for every
*N k 0 updates. The rebuilding takes time O N .
3.3 Choosing the right parameter
We need to handle M updates and answer one question after each of these updates. The total
running time is
O M k log N O M k N ©k O M N © N ©k ;
where the first term denotes the total query time, the second term denotes the total updating
time, and the lastÓterm denotes the total rebuilding time.
Ó
Choosing k N gives the running time of O M N log N , which is sufficient to obtain full
marks for this problem. However, an inefficient implementation may not be able to solve subtask
5. For example, using the set data structure in the C++ Standard Template Library can introduce
an extra factor of log n to the running time of rebuilding the data structure. This can be avoided
by using simple arrays.
A Processing each bucket
To simplify the presentation, we add a dummy elephant ep at position xep1 L 1. Also, we
let yj xej be the position of the j-th left-most elephant in bucket Bi .
We consider each elephant j from the right-most elephant ep1 to the left-most one. We also
maintain an index t that points to the left-most elephant et whose position yt % yj L. Initially,
j p 1 and t p.
CAPITOLUL 9. IOI 2011 9.5. DANCING ELEPHANTS 952
For each elephant ej , we will compute J ej and last ej , the left-most elephant in the right-
most camera in the set of cameras covering rej , ej 1 , ..., ep x.
For the dummy node, we let J ep 0 and last ep ep . For elephant ej , we check if we need
to move t, i.e., if the position of et1 is greater than yj L; if that’s the case we find the smallest
t such that yt % yj L. We let J ej J et 1 and last ej last et .
Finally, for each elephant ej such that last ej points to the dummy elephant ep , we change
last ej to ej .
We can complete the process using only one pass over all elephants in the bucket Bi and note
that the pointer t moves over each elephant only once. Thus, the running time is O ¶Bi ¶ as
claimed.
To answer question Q2 for each elephant ej , we report ylast ej L.
#include "elephants.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
#include <bits/stdc++.h>
int K, Q;
int Sq=400;
int B[400][1000], sz[400];
int D[400][1000], C[400][1000];
int A[150505], T[150505];
void calc(int t)
{
if (!sz[t]) return;
int k=sz[t]-1;
for (int i=sz[t]-1; i>=0; i--)
{
while (B[t][i] + K < B[t][k]) k--;
if (k == sz[t]-1) D[t][i] = 1, C[t][i] = B[t][i] + K;
else D[t][i] = D[t][k+1] + 1, C[t][i] = C[t][k+1];
}
}
void del(int x)
{
int t, k;
for (t=0; t<M; t++)
{
if (!sz[t]) continue;
k = lower_bound(B[t], B[t]+sz[t], x) - B[t];
if (k < sz[t] && B[t][k] == x) break;
}
sz[t]--;
for (; k<sz[t]; k++)
B[t][k] = B[t][k+1];
calc(t);
}
void add(int x)
{
int t;
for (t=0; t<M-1; t++)
if (sz[t] && x <= B[t][sz[t]-1]) break;
B[t][sz[t]++] = x;
for (int i=sz[t]-1; i>0 && B[t][i-1] > B[t][i]; i--)
swap(B[t][i-1], B[t][i]);
calc(t);
}
Q++;
if (Q % Sq == 0)
{
int cnt=0;
for (int i=0; i<M; i++)
{
for (int j=0; j<sz[i]; j++) T[cnt++] = B[i][j];
sz[i] = 0;
}
init(N, K, T);
}
void read_input()
{
int i;
my_assert(3==scanf("%d %d %d",&N,&L,&M));
int main()
{
auto t1 = clock();
CAPITOLUL 9. IOI 2011 9.5. DANCING ELEPHANTS 954
int i, ans;
read_input();
init(N,L,X);
auto t3 = clock();
printf("Correct.\n");
auto t4 = clock();
return 0;
}
#include "elephants.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
#include <bits/stdc++.h>
int n, l, m;
int x[150010], v[150010];
int bnum;
int ucnt;
struct Bucket
{
int sz;
int x[2 * b_size + 1];
int num[2 * b_size + 1];
int bound[2 * b_size + 1];
void calc()
{
int t = sz;
for(int i = sz - 1; i >= 0; i--)
{
while(t > 0 && x[t - 1] > x[i] + l) t--;
if(t == sz)
num[i] = 1, bound[i] = x[i] + l;
else
num[i] = num[t] + 1, bound[i] = bound[t];
}
}
void ins(int y)
{
int p = (int)(upper_bound(x, x + sz, y) - x);
sz++;
for(int i = sz - 1; i > p; i--)
x[i] = x[i - 1];
x[p] = y;
calc();
}
void del(int y)
{
int p = (int)(lower_bound(x, x + sz, y) - x);
sz--;
for(int i = p; i < sz; i++)
x[i] = x[i + 1];
calc();
}
} b[b_size + 1];
b[bnum++].calc();
}
}
void rebucket()
{
int cnt = 0;
for(int i = 0; i < bnum; i++)
{
for(int j = 0; j < b[i].sz; j++)
{
v[cnt++] = b[i].x[j];
}
}
bnum = 0;
CAPITOLUL 9. IOI 2011 9.5. DANCING ELEPHANTS 956
int ret = 0;
int lst = -1;
for(int i = 0; i < bnum; i++)
{
if(lst >= b[i].x[b[i].sz - 1]) continue;
if(lst < b[i].x[0])
{
ret += b[i].num[0];
lst = b[i].bound[0];
}
else
{
int p = (int)(upper_bound(b[i].x, b[i].x + b[i].sz, lst) - b[i].x);
ret += b[i].num[p]; lst = b[i].bound[p];
}
}
ucnt++;
if(ucnt % (b_size - 5) == 0) rebucket();
return ret;
}
void read_input()
{
int i;
my_assert(3==scanf("%d %d %d",&N,&L,&M));
int main()
{
auto t1 = clock();
int i, ans;
CAPITOLUL 9. IOI 2011 9.5. DANCING ELEPHANTS 957
read_input();
init(N,L,X);
auto t3 = clock();
printf("Correct.\n");
auto t4 = clock();
return 0;
}
#include "elephants.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
#include <bits/stdc++.h>
struct iii
{
int x, n, y;
CAPITOLUL 9. IOI 2011 9.5. DANCING ELEPHANTS 958
};
int A[MX], Q;
vector<iii> D[C];
void calc_bucket(vector<iii>& v)
{
for(int n=v.size(), i=n, p=n; i--;)
{
while(p && v[i].x<v[p-1].x-M) p--;
if(p==n)
v[i].n=1, v[i].y=v[i].x+M;
else
v[i].n=v[p].n+1, v[i].y=v[p].y;
}
}
void init_buckets()
{
int k=0;
for(auto&v:D)
{
for(auto[x,n,y]:v) X[k++]=x;
v.clear();
}
void del(int x)
{
for(auto&v:D) if(v.size() && v.front().x<=x && x<=v.back().x)
{
v.erase(lb(v, x));
calc_bucket(v);
break;
}
}
void add(int x)
{
int p=0, n=N-1;
for(auto&v:D)
if(!(n-=v.size()) || v.size() && p<=x && x<=(p=v.back().x))
{
v.insert(lb(v, x), {x, 0, 0});
calc_bucket(v);
break;
}
}
int answer()
{
int p=0, n=0;
for(auto&v:D) if(v.size() && p<=v.back().x)
{
auto[x,m,y]=*lb(v, p);
n+=m, p=y+1;
}
return n;
}
D[i].reserve(B);
for(int i=0; i<N; i++)
D[i/B].push_back({A[i]=E[i], 0, 0});
}
void read_input()
{
int i;
my_assert(3==scanf("%d %d %d",&N,&L,&M));
int main()
{
auto t1 = clock();
int i, ans;
read_input();
init(N,L,X);
auto t3 = clock();
printf("Correct.\n");
auto t4 = clock();
return 0;
}
*/
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/subtask5/grader.in.20",
(char*)"elephants.out",
(char*)"../tests/subtask5/grader.expect.20",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
9.6 Parrots
Problema 6 - Parrots 100 de puncte
Yanee is a bird enthusiast. Since reading about IP over Avian Carriers (IPoAC), she has spent
much of her time training a flock of intelligent parrots to carry messages over long distances.
Yanee’s dream is to use her birds to send a message M to a land far far away. Her message M
is a sequence of N (not necessarily distinct) integers, each between 0 and 255, inclusive. Yanee
keeps K specially-trained parrots. All the parrots look the same; Yanee cannot tell them apart.
Each bird can remember a single integer between 0 and R, inclusive.
Early on, she tried a simple scheme: to send a message, Yanee carefully let the birds out of the
cage one by one. Before each bird soared into the air, she taught it a number from the message
sequence in order. Unfortunately, this scheme did not work. Eventually, all the birds did arrive
at the destination, but they did not necessarily arrive in the order in which they left. With this
scheme, Yanee could recover all the numbers she sent, but she was unable to put them into the
right order.
To realize her dream, Yanee will need a better scheme, and for that she needs your help.
Given a message M , she plans to let the birds out one by one like before. She needs you to write
a program that will perform two separate operations:
First, your program should be able to read a message M and transform it into a sequence
of at most K integers between 0 and R that she will teach the birds.
Second, your program should be able to read the list of integers between 0 and R received
as the birds reach their destination, and then transform it back to the original message M .
You may assume that all parrots always arrive at the destination, and that each of them
remembers the number it was assigned. Yanee reminds you once again that the parrots may
arrive in any order. Note that Yanee only has K parrots, so the sequence of integers between 0
and R thatb you produce must contain at most K integers.
CAPITOLUL 9. IOI 2011 9.6. PARROTS 961
Your task
Write two separate procedures. One of them will be used by the sender (encoder) and the
other by the receiver (decoder).
The overall process is shown in the following figure.
Note that R and K are not given as input parameters - please see the subtask descriptions
below.
In order to correctly solve a given subtask, your procedures must satisfy the following condi-
tions:
All integers sent by your procedure encode must be in the range specified in the subtask.
The number of times your procedure encode calls the procedure send must not exceed the
limit K specified in the subtask. Please note that K depends on the length of the message.
Procedure decode\verb must correctly recover the original message M and call the proce-
dure output(b) exactly N times, with b equal to M 0, M 1, ..., M N 1, respectively.
In the last subtask, your score varies according to the ratio between the lengths of the encoded
message and the original message.
Example
10
Consider the case where N 3, and M = 30
20
Procedure encode(N,M), using some strange method, may encode the message as the se-
quence of numbers (7, 3, 2, 70, 15, 20, 3). To report this sequence, it should call the procedure
send as follows:
send(7)
send(3)
send(2)
send(70)
send(15)
send(20)
send(3)
CAPITOLUL 9. IOI 2011 9.6. PARROTS 962
Once all parrots reach their destination, assume we obtain the following list of transcribed
numbers: (3, 20, 70, 15, 2, 3, 7). The procedure decode will then be called with N 3, L 7,
and
3
20
70
X = 15
2
3
7
The procedure decode must produce the original message (10, 30, 20). It reports the result
by calling the procedure output as follows.
output(10)
output(30)
output(20)
Subtasks
Subtask 1 (17 points)
N 8, and each integer in the array M is either 0 or 1.
Each encoded integer must be in the range from 0 to R 65535, inclusive.
The number of times you can call the procedure send is at most K 10 N .
Implementation details
Limits
CAPITOLUL 9. IOI 2011 9.6. PARROTS 963
Grading Environment: In the real grading environment, your submissions will be compiled
into two programs e and d to be executed separately. Both your encoder and decoder
modules will be linked to each executable, but e only calls encode and d only calls decode.
CPU time limit: Program e will make 50 calls to procedure encode and it should run in 2
seconds. Program d will make 50 calls to procedure decode and it should run in 2 seconds.
Memory limit: 256 MB
Note: There is no explicit limit for the size of stack memory. Stack memory counts towards
the total memory usage.
Interface (API)
Implementation folder: parrots/
To be implemented by contestant:
– encoder.c or encoder.cpp or encoder.pas
– decoder.c or decoder.cpp or decoder.pas
Note for C/C++ programmers: both in the sample grader and in the real grader, en-
coder.c[pp] and decoder.c[pp] are linked together with the grader. Therefore, you should
declare all global variables inside each file as static to prevent them from interfering with
variables from other files.
Contestant interface:
– encoder.h or encoder.pas
– decoder.h or decoder.pas
Grader interface:
– encoderlib.h or encoderlib.pas
– decoderlib.h or decoderlib.pas
Sample grader: grader.c or grader.cpp or grader.pas
The sample grader executes two separate rounds. In each round, it first calls encode with the
given data, and then it calls decode with the output your procedure encode produced. In the
first round the grader does not change the order of the integers in the encoded message. In
the second round the sample grader swaps the integers on odd and even positions. The real
grader will apply various kinds of permutations to the encoded messages. You can change
how the sample grader shuffles the data by modifying its procedure shuffle (in C/C++) or
Shuffle (in Pascal).
The sample grader also checks for both range and length of the encoded data. By default,
it checks that the encoded data is in the range between 0 and 65535, inclusive, and that the
length is at most 10 N . You can change this by adjusting the constants CHANNEL_RANGE
(from 65535 to 255, for example) and max_expansion (from 10 to 15 or 7, for example).
Sample grader input: grader.in.1, grader.in.2, ...
Note: The sample grader reads the input in the following format:
– Line 1: N
– Line 2: a list of N numbers: M 0, M 1, ..., M N 1
Expected output for sample grader input: grader.expect.1, grader.expect.2, ...
For this task, each one of these files should contain precisely the text ”Correct.”
For this task, contestants are given a message M of length N , which consists of a sequence
of integers between 0 and 255, inclusive, and they are asked to find an encoding and decoding
scheme such that the encoded message X are invariant up to permutations. The encoded message
should be as concise as possible. The scores will be rewarded based on the ratio of the length of
the encoded message X to the length of the original message M .
CAPITOLUL 9. IOI 2011 9.6. PARROTS 964
There are many ways to solve this task. It will be instructive to look at the first few subtasks.
1 Subtask 1
For this subtask, recall that the original message M is just a sequence of two possible numbers,
0 or 1. Assuming that the original message is indexed from 0 to N 1, one can instead choose
the send the positions in the original message where all number 1’s are located. This technique
uses at most N integers to send the message.
2 Subtask 2
For subtask 2, since the numbers in the original message M could be from 0 to 255, they can
be encoded using only 8 bits. However, this subtask allows one to use up to 16 bit per number in
the encoded message E. Hence, you can encode the position of each number using the higher 8
bits (similar to the solution to subtask 1), and use the lower 8 bits to encode the actual number
in the original message M , i.e.
Ei 256 i Mi
where Ei denotes the i-th number in the original message.
Note that the encoded numbers are also ordered, i.e. Ei $ Ei1 , for 0 & i $ N 1. Therefore,
when we would like to decode the message from the shuffled array X, we can sort it to get E.
Then, to obtain the original message from the sorted E should be pretty obvious.
This method also uses at most N parrots, which is satisfactory for this subtask.
3 Subtask 3
Thinking about the first two subtasks should get us familiar with the approach. There are
many roads to take from here. However, to formalize the settings, we shall think of a general
representation first.
Because we shall keep integers in the encoded array, a natural representation would be to use
a sorted sequence. Note that this representation is very robust against permutation; provided that
the encoded array E is sorted, by sorting a shuffled array X, we can easily recover the encoded
array E, as in subtask 2.
We shall try to extend the approach in subtask 2. However, for subtasks 3-5, we do not have
”extra” bits for keeping the position data. In these cases, we look at the original message as a
sequence of binary digits (or bits), 0 and 1, by representing each number using only 8 bits.
Thus, the original message of length N will have 8N bits.
This leads to a way to solve subtask 3. Note that the origianl message M contains at most
16 8 128 bits. For now, let Bi be the i-th bit of the original message, indexing from 0 to
8N 1. In this case, it is sufficient to take 7 bits to represent all positions of every single bit
Bi , and use one last bit to represent the actual data. Hence, the encoding scheme looks like the
following
Ei 2 i Bi
therefore, it takes 7 bits to represent posible positions and another bit to keep the data. That is,
for each bit bi , we shall encode it as 2 i bi . The length of the encoded message for each test
case of this subtask is 8N bytes.
4 Subtask 4
For this subtask, there are 32 8 256 bit positions; and it requires 8 bits just to represent the
positions. Hence, there is no way to include the information of each bit of the original message in
the encoding. If we recall the technique we use to solve subtask 1, we can improve the technique
we used in subtask 3 by choosing to encode the positions of all 1 bits. This approach again sends
at most 8N bytes.
5 Subtask 5
For this subtask, contestants are allowed to obtain some partial scores, depending on the ratio
of the encoding message to the original message. In our point of view, to obtain nearly perfect
CAPITOLUL 9. IOI 2011 9.6. PARROTS 965
scores like 98 is relatively much easier than to obtain the full points. We consider the last 2 points
to be the reward to those who choose to implement more sophisticated method of encoding that
achieve better results than our expectations.
We discuss many potential solutions that might achieve some partial scores.
5.1 A ratio=12 approach
We are going to generalize the solution to the previous subtask case since the number of bits
is more than 256. In this case, there are at most 512 bit positions.
To deal with this issue, we partition the message into 256 pairs of bits. We define the i-th bit
pair Pi to be M2i , M2i1 . Again, the bit pair P should be indexed from 0 to 4N 1.
Note that there are 4 possible values for each bit pair, which can be represented with integers
from 0 to 3. One possible method is to send the positions of the bit pair (which uses 8 bit to
encode) in the encoding data, and then the actual bit pair data will be encoded as the number of
occurrences of such positions.
Using this approach, for each pair of bits, we may have to send at most 3 bytes. Therefore,
we send at most 32 8N 12N bytes. Contestants will achieve 7 points on this subtask for
implementing this method.
5.2 A ratio=6.25 approach
With a simple observation, we can reduce the size of the encoded messages by roughly a factor
of two. Note that the best case (in terms of encoding length) for the previous encoding method is
when the original message only contains zero bits, and the worst case is when the message contains
only one bits. We shall try to get the average of these two cases.
Consider two encoding scheme, called ONE and ZERO. For a pair of bits b2i , b2i1 , the one
scheme sends 2 b2i b2i1 copies of i, but the zero scheme sends 3 2 b2i b2i1 copies. Note that
both schemes work, provided that the decoder knows which of the schemes the encoder actually
uses.
For each pair of bits, the sum of the number of encoded bytes used by both scheme is always
2 b2i b2i1 3 2 b2i b2i1 3 bytes. Considering all pairs, the sum is 3 8N 2
12N .
Now, if we choose the scheme with the lower number of encoding data, we will need at most
half of this number, i.e., at most 6N bytes.
There are many ways to signal the decoder which encoding scheme the encoder uses without
too much penalty on the ratio. For example, we can add 4 copies of 255 iff the ZERO scheme is
used. This will make the ratio goes up by N4 . However, since N ' 16, the worst ratio is at most
6.25. Contestants will achieve 17 points on this subtask for implementing this method.
5.3 Better approaches
There are many other approaches that give better compression ratio.
5.3.1 One byte to 4 numbers
Consider the number of encoded messages of length no greater than 7, only consisting of
numbers 0, 1, 2, and 3 (0, 0, 1, 1, 1, 1, 3 is one such message). To analyze this, it might be
easier to consider an equivalent scheme: encoded messages of length exactly 7, only consisting of
numbers 0, 1, 2, 3, and BLANK. There are 44 711 4
330 of them, which is enough to encode
one byte of the original message.
Since the original message is at most 64 bytes long, it is possible to allocate 4 numbers per byte
(0, 1, 2, and 3 for the first byte, for example), and therefore numbers from 0 to 255 are suffcient.
This scheme yields a compression ratio of at most 7.
5.3.2 Optimal ratio
Theoretically, one can encode 64 bytes of data to the minimum of 261 bytes of encoded message
261 517 1.47 10154 different encoded messages
without loss of information. There are 256256 256
using no more than 261 bytes. This is just more than 256 1.34 10 , the number of different
64 154
64-byte original messages. The compression ratio achieved is about 4.08. For smaller data, the
ratio is even smaller.
This method yields a perfect score for this task. However, implementation of this scheme is
comparatively difficult.
CAPITOLUL 9. IOI 2011 9.6. PARROTS 966
#include "encoder.h"
#include "decoder.h"
#include "encoderlib.h"
#include "decoderlib.h"
#include <bits/stdc++.h>
class BigNum
{
public:
BigNum A = aux;
BigNum B = *this;
int acc = 0;
return ans;
}
return true;
}
return false;
}
private:
int base;
BigNum pot[MAXB];
BigNum dp[MAXV][MAXL];
void buildPowers()
{
pot[0].insert( 1 );
void buildBinomials()
{
for(int i = 0 ; i < MAXV ; i++)
dp[i][0].insert( 1 );
hasInit = true;
}
BigNum binary;
BigNum sum;
{
int qtdParrots;
int qtdNumbers = 256 - i - 1;
sum = aux;
}
remainParrots -= qtdParrots;
if( i == -1 ) continue;
int freq[MAXL];
hasInit = true;
}
BigNum sum;
int remainParrots = L;
freq[i]--;
remainParrots--;
}
}
BigNum cur;
output( v );
}
}
void send(int x)
{
if(M == MAX_M) {
printf("Encoded message too long\n");
exit(0);
}
encoded_message[M] = x;
M++;
}
int read_data()
{
if(NN == M) {
printf("Read too many encoded message\n");
exit(0);
}
NN++;
return encoded_message[NN-1];
}
void output(int y)
{
if(O == N)
O++;
if(O > N)
return;
output_message[O] = y;
O++;
}
if(O!=N)
return 0;
for(i = 0; i < N; i++)
if(message[i] != output_message[i])
return 0;
return 1;
}
int main()
{
auto t1 = clock();
int i,tt,t,p,r;
int correct;
scanf("%d",&tt);
scanf("%d %d",&max_expansion,&channel_range);
scanf("%d",&r);
srand(r);
auto t2 = clock();
M = 0;
encode(N,message);
check_encoded_message();
CAPITOLUL 9. IOI 2011 9.6. PARROTS 971
scanf("%d",&p);
shuffle(p);
NN = 0;
O = 0;
decode(N,M,encoded_message);
if(!check_output())
{
printf("Incorrect\n");
exit(0);
}
}
auto t3 = clock();
printf("Correct.\n");
fprintf(stderr,"Ratio: %f\n",(float)M/N);
auto t4 = clock();
return 0;
}
#include "encoder.h"
#include "decoder.h"
#include "encoderlib.h"
#include "decoderlib.h"
#include <stdio.h>
#include <stdlib.h>
#include<ctime>
#include<iostream>
#include<cstring>
#include<algorithm>
{
if(a[i] < b[i])
{
return 1;
}
return 0;
}
}
return 0;
}
void send(int x)
{
if(M == MAX_M)
{
printf("Encoded message too long\n");
exit(0);
}
encoded_message[M] = x;
M++;
}
int read_data()
{
if(NN == M)
{
printf("Read too many encoded message\n");
exit(0);
}
NN++;
return encoded_message[NN-1];
}
void output(int y)
{
if(O == N)
O++;
if(O > N)
return;
output_message[O] = y;
O++;
}
}
}
if(O!=N)
return 0;
for(i = 0; i < N; i++)
if(message[i] != output_message[i])
return 0;
return 1;
}
int main()
{
auto t1 = clock();
int i,tt,t,p,r;
int correct;
scanf("%d",&tt);
scanf("%d %d",&max_expansion,&channel_range);
scanf("%d",&r);
srand(r);
auto t2 = clock();
M = 0;
encode(N,message);
check_encoded_message();
scanf("%d",&p);
shuffle(p);
NN = 0;
O = 0;
decode(N,M,encoded_message);
if(!check_output())
{
printf("Incorrect\n");
exit(0);
}
}
auto t3 = clock();
printf("Correct.\n");
fprintf(stderr,"Ratio: %f\n",(float)M/N);
auto t4 = clock();
return 0;
}
10.1 Cluedo
Problema 1 - Cluedo 100 de puncte
Dr. Black has been murdered. Detective Jill must determine the murderer, the location, and
the weapon. There are six possible murderers, numbered 1 to 6. There are ten possible locations,
numbered 1 to 10. There are six possible weapons, numbered 1 to 6.
For illustration only, we show the names of the possible murderers, locations and weapons. The
names are not required to solve the task.
Murderer Location Weapon
1. Ballroom
2. Kitchen
1. Professor Plum 3. Conservatory 1. Lead pipe
2. Miss Scarlet 4. Dining Room 2. Dagger
3. Colonel Mustard 5. Billiard Room 3. Candlestick
4. Mrs. White 6. Library 4. Revolver
5. Reverend Green 7. Lounge 5. Rope
6. Mrs. Peacock 8. Hall 6. Spanner
9. Study
10. Cellar
Jill repeatedly tries to guess the correct combination of murderer, location and weapon. Each
guess is called a theory. She asks her assistant Jack to confirm or to refute each theory in turn.
When Jack confirms a theory, Jill is done. When Jack refutes a theory, he reports to Jill that one
of the murderer, location or weapon is wrong.
You are to implement the procedure Solve that plays Jill’s role. The grader will call
Solve many times, each time with a new case to be solved. Solve must repeatedly call
Theory(M,L,W), which is implemented by the grader. M , L and W are numbers denoting
a particular combination of murderer, location and weapon. Theory(M,L,W) returns 0 if the
theory is correct. If the theory is wrong, a value of 1, 2 or 3 is returned. 1 indicates that the
murderer is wrong; 2 indicates that the location is wrong; 3 indicates that the weapon is wrong.
If more than one is wrong, Jack picks one arbitrarily between the wrong ones (not necessarily in
a deterministic way). When Theory(M,L,W) returns 0, Solve should return.
Example
As example, assume that Miss Scarlet committed the murder (Murderer 2) in the conservatory
(Location 3) using a revolver (Weapon 4). When procedure Solve makes the following calls to
function Theory, the results in the second column could be returned.
41
argint: Bogdan-Cristian Tătăroiu, ICHB (Bucureşti)
. bronz: Vlad Alexandru Gavrilă, ICHB (Bucureşti)
. bronz: Andrei-Bogdan Pârvu, Tudor Vianu (Bucureşti),
. bronz: Victor Ionescu, ICHB (Bucureşti).
977
CAPITOLUL 10. IOI 2010 10.1. CLUEDO 978
This was intended to be a very easy task. The number of features to be determined (murderer,
location, weapon), and the number of options for each feature were intentionally fixed, and not
parameterized.
Given that there are 6 candidate murderers, 10 candidate locations, and 6 candidate weapons,
there is a total of 6*10*6=360 theories.
Subtask 1 could be solved by trying each possible theory (three nested for loops).
Because the response to a refuted theory will identify one feature for which a wrong option was
guessed, the search can be expedited. All theories having that wrong option for that particular
feature are now ruled out.
Subtask 2 can be solved by a single loop, incrementing whichever feature was wrong (a mono-
tonic search). The total number of options equals 6+10+6=22, and the last option not ruled out
must be correct (it was given that there is exactly one correct theory). Therefore, at most 22-3=19
refuted calls to Theory are needed. One confirming call to Theory was required, so a total of 20
calls suffices.
Here is a Pascal solution that can readily be generalized (the constant, type, and auxiliary
function definitions could be eliminated, but they document the relevant concepts nicely):
1 const
2 NFeatures = 3; { number of features }
3 Confirmed = 0; { result when theory is confirmed }
4
5 type
6 TFeature = 1 .. NFeatures;
7 TOption = 1 .. MaxInt; { value for a feature }
8 TTheory = array [ TFeature ] of TOption;
9 TResult = Confirmed .. NFeatures;
10
11 function TestTheory(T: TTheory): TResult;
12 begin
13 TestTheory := Theory(T[1], T[2], T[3])
14 end;
15
16 procedure Solve;
17 var
18 T: TTheory = (6, 10, 6); { candidate theory }
19 i: TResult; { result of TestTheory(T) }
20
21 begin
22 repeat
23 i := TestTheory(T);
24 if i <> Confirmed then { T refuted }
25 T[i] := T[i] - 1
26 until i = Confirmed
27 { T confirmed }
28 end;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<ctime>
#include<iostream>
#include "grader.h"
#include "cluedo.h"
#include<bits/stdc++.h>
void Solve()
{
CAPITOLUL 10. IOI 2010 10.1. CLUEDO 980
int m=1,l=1,w=1;
while(1)
{
int r = Theory(m,l,w);
if(!r) return ;
if(r==1) ++m;
if(r==2) ++l;
if(r==3) ++w;
}
}
gotit = 1;
return 0;
}
int main()
{
std::freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
//std::freopen("cluedo.out", "w", stdout);
while (3 == scanf("%d%d%d",&M,&L,&W))
{
cnt = gotit = 0;
Solve();
printf("OK %d\n",maxcnt);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<ctime>
#include<iostream>
#include "grader.h"
#include "cluedo.h"
void Solve()
{
int i=1, j=1, k=1, r;
while(1)
{
r = Theory(i, j, k);
if(r==0) return;
else if(r==1) i++;
else if(r==2) j++;
else if(r==3) k++;
}
}
gotit = 1;
return 0;
}
int main()
{
std::freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
//std::freopen("cluedo.out", "w", stdout);
while (3 == scanf("%d%d%d",&M,&L,&W))
{
cnt = gotit = 0;
Solve();
printf("OK %d\n",maxcnt);
return 0;
}
// -------------- end grader ----------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<ctime>
#include<iostream>
#include "grader.h"
#include "cluedo.h"
CAPITOLUL 10. IOI 2010 10.2. HOTTER COLDER 982
#include <bits/stdc++.h>
void Solve(void)
{
int i[] = {1, 1, 1};
while(true)
{
int r = Theory(i[0], i[1], i[2]);
if(r == 0) return;
i[r - 1]++;
}
}
gotit = 1;
return 0;
}
int main()
{
std::freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
//std::freopen("cluedo.out", "w", stdout);
while (3 == scanf("%d%d%d",&M,&L,&W))
{
cnt = gotit = 0;
Solve();
printf("OK %d\n",maxcnt);
return 0;
}
Jack and Jill play a game called Hotter, Colder. Jill has a number between 1 and N , and Jack
makes repeated attempts to guess it.
Each of Jack’s guesses is a number between 1 and N . In response to each guess, Jill answers
hotter, colder or same. For Jack’s first guess, Jill answers same. For the remaining guesses Jill
answers:
hotter if this guess is closer to Jill’s number than his previous guess
colder if this guess is farther from Jill’s number than his previous guess
same if this guess is neither closer to nor further from Jill’s number than his previous guess.
You are to implement a procedure HC(N) that plays Jack’s role. This implementation may
repeatedly call Guess(G), with G a number between 1 and N . Guess(G) will return 1 to
indicate hotter, -1 to indicate colder or 0 to indicate same. HC(N) must return Jill’s number.
Example
As example, assume N 5, and Jill has chosen the number 2. When procedure HC makes the
following sequence of calls to Guess, the results in the second column will be returned.
Call Returned value Explanation
Guess(5) 0 Same (first call)
Guess(3) 1 Hotter
Guess(4) -1 Colder
Guess(1) 1 Hotter
Guess(3) 0 Same
At this point Jack knows the answer, and HC should return 2. It has taken Jack 5 guesses to
determine Jill’s number. You can do better.
Subtask 1 [25 points]
HC(N) must call Guess(G) at most 500 times. There will be at most 125 250 calls to HC(N),
with N between 1 and 500.
Subtask 2 [25 points]
HC(N) must call Guess(G) at most 18 times. There will be at most 125 250 calls to HC(N)
with N between 1 and 500.
Subtask 3 [25 points]
HC(N) must call Guess(G) at most 16 times. There will be at most 125 250 calls to HC(N)
with N between 1 and 500.
Subtask 4 [up to 25 points]
Let W be the largest integer, such that 2W 3N . For this subtask your solution will score:
0 points, if HC(N) calls Guess(G) 2W times or more,
25α points, where α is the largest real number, such that 0 $ α $ 1 and HC(N) calls
Guess(G) at most 2W αW times,
25 points, if HC(N) calls Guess(G) at most W times.
There will be at most 1 000 000 calls to HC(N) with N between 1 and 500 000 000.
Be sure to initialize any variables used by HC every time it is called.
Implementation Details
Implementation folder: /home/ioi2010-contestant/hottercolder/
To be implemented by contestant: hottercolder.c or hottercolder.cpp or
hottercolder.pas
Contestant interface: hottercolder.h or hottercolder.pas
Grader interface: grader.h or graderlib.pas
Sample grader: grader.c or grader.cpp or grader.pas and graderlib.pas
Sample grader input: grader.in.1 grader.in.2.
Note: The input file contains several lines, each containing N and Jill’s number.
Expected output for sample grader input: the grader will create files grader.out.1
grader.out.2 etc.
CAPITOLUL 10. IOI 2010 10.2. HOTTER COLDER 984
` If the implementation correctly implements Subtask 1, one line of output will contain
OK 1
` If the implementation correctly implements Subtask 2, one line of output will contain
OK 2
` If the implementation correctly implements Subtask 3, one line of output will contain
OK 3
` If the implementation correctly implements Subtask 4, one line of output will contain
OK 4 alpha α
Compile and run (command line): runc grader.c or runc grader.cpp or
runc grader.pas
Compile and run (gedit plugin): Control-R, while editing any implementation file.
Submit (command line): submit grader.c or submit grader.cpp or
submit grader.pas
Submit (gedit plugin): Control-J, while editing any implementation or grader file.
This problem is an interesting variant of the well-known guessing game Higher-Lower, also featured
in the demonstration task Guess.
Higher-Lower is efficiently solved by the, also well-known, Binary Search algorithm. Binary
Search maintains an interval of still possible numbers (candidates). Initially, this interval includes
all numbers in the range. By comparing to the middle candidate, the interval can be halved by
a single guess. Thus, the secret number can be determined in a logarithmic (to base 2) number
of guesses. Or, to put it differently, if the range of allowed numbers is doubled, than the secret
number can be determined with one additional guess.
Subtask 1
Doing a Linear Search, that is, successively calling Guess(i) for i from 1 to N , yields a
solution requiring N calls to Guess, in the worst case. This solves Subtask 1. See below for a
Pascal program.
Analysis
To get a better understanding of the Hotter-Colder problem, it helps to formalize the rules of
this game.
Let J be Jill’s number, and let P be the most recent guess, that is, Guess P was called last.
In that situation, Guess G will return
if P <= G then
HOTTER if J > M
COLDER if J < M
SAME if J = M
else
HOTTER if J < M
COLDER if J > M
SAME if J = M
Subtask 2
Ignoring the results of all odd calls to Guess, we can extract one bit of information out of every
successive pair of odd-numbered and next even-numbered call to Guess. This yields a solution
that calls Guess at most W times, where W is the largest integer such that 2
W ©2
& N . That is,
2 9
it makes at most log2 N (rounded up) calls to Guess. For N 500 (almost 2 ), this boils down
to making at most 18 calls.
Subtask 3
By exploiting the fact that we actually do a high/low/equal comparison instead of a pure
high/low (binary) comparison, we can gain almost one extra bit of information (taken over all
guesses).
k k
Explanation: a complete binary tree with 2 leaves has 2 1 internal nodes. So, the same
number of high/low/equal guesses can reach twice the number of nodes minus one (compared to
using just binary high/low guesses).
A Pascal program is given below.
Subtask 4
The preceding approaches obviously throw away (ignore) valuable information. However, using
this information requires careful tuning of the guesses. It helps to do some small cases by hand.
N 3 can obviously be done in 2 guesses, by straddling the middle, for example, Guess 1
followed by Guess 3 does a high/low/equal comparison to 2.
N 5 can be done in 3, but this already needs some care, because it does not work to set
this up so that the first two guesses compare to the middle number 3. When, after Guess 1
Guess 5, or Guess 2 Guess 4, the result of the second guess is colder, you won’t be able
to solve the remaining problem in a single guess.
You need to start with Guess 1 Guess 3 (or symmetrically Guess 5 Guess 3). If the
result of the second guess is same, Jill’s number is 2; if the result is colder, only candidate 1
remains and this must be Jill’s number. If the result is hotter, candidates 3, 4, and 5 remain.
Since 3 was the most recent guess, doing Guess 5 will compare to 4, and we are done.
In general, it turns out to be possible to determine Jill’s number in no more than log2 3 N
log2 3 log2 N calls of Guess.
We explain one such algorithm. Because of the nature of the guess (being a comparison), at
any moment you have an interval of remaining candidate numbers. You can distinghuish two cases
for the location of this interval with respect to the initial interval:
K 1
dddddddddd is of length 2 2;
CAPITOLUL 10. IOI 2010 10.2. HOTTER COLDER 986
K 2
the most recent guess was R P 2 .
Your next guess is G P 2:
aaaabbbbbbdddddddddd
1G P M R
K 2 K 1
This guess compares to M G R©2 P 2P 2 ©2 P 2 2 1, that is,
the first element of the d-labeled subinterval. Do a case distinction on the result of this guess:
Same: Jill’s number is M ; done.
Colder: the interval is reduced to M 1 through R; continue with a ”middle game” on
K 1
ddddddddd of length 2 1;
` Colder: ”wall game” on interval 1 through P (aaaa), which we assumed can be solved in
K more guesses;
K 1
` Hotter: ”middle game” on abbbbbb of length 2 1.
8
9 function HC(N: Longint): Longint;
10 { returns secret number of Jill }
11
12 var
13 r: TResult; { result of Guess }
14 a, b: Longint; { [a .. b] is interval of remaining candidates }
15
16 begin
17 if N = 1 then begin HC := N
18 ; Exit
19 end { if }
20 { N >= 2 }
21
22 ; a := 1
23 ; b := N
24
25 { invariant: 1 <= a <= b <= N }
26 ; while a <> b do begin
27 r := Guess(a) { ignored }
28 ; r := Guess(b) { compares to (a+b)/2 }
29 ; case r of
30 Colder: b := (a + b - 1) div 2; { largest integer < (a+b)/2 } Same: begin a := (a + b)
div 2 ; b :=
31 a end;
32 Hotter: a := (a + b + 1) div 2; { smallest integer > (a+b)/2 } end { case r }
33 end { while }
34 { a = b }
35 ; HC := a
36 end;
112 {
113 int g = Guess(fix(end, 3));
114 if (g > 0) return fix(end, 3);
115 if (g == 0) return fix(end, 2);
116 return fix(end, 1);
117 }
118
119 g = Guess(fix(end, 11));
120 if (g > 0) return fix(end, 7);
121 if (g == 0) return fix(end, 6);
122 if (g < 0) return fix(end, 5);
123 }
124
125 g = Guess(fix(end, t[z-2]-2));
126 if (g == 0) return fix(end, (t[z-2]-2+n)/2);
127 if (g < 0)
128 return midgame(fix(end, t[z-2]-2),
129 fix(end, (t[z-2]-2+n)/2+1),
130 fix(end, n));
131
132 // g > 0
133 g = Guess(fix(end, t[z-2]));
134 if (g < 0) return endgame(end, t[z-2]);
135 if (g == 0) return fix(end, t[z-2]-1);
136 return midgame(fix(end, t[z-2]),
137 fix(end, t[z-2]),
138 fix(end, (t[z-2]-2+n-1)/2));
139 return 0;
140 }
141
142 int HC(int N)
143 {
144 // returns Jill’s number
145 int i, mid;
146 if (!t[0])
147 {
148 t[0] = 1;
149 t[1] = 3;
150 t[2] = 7;
151 for (i=3; i<30; i++) t[i] = t[i-2] + (1l<<i);
152 }
153
154 if (N == 1) return 1;
155 if (N == 2)
156 {
157 Guess(1);
158 i = Guess(2);
159 if (i > 0) return 2;
160 else return 1;
161 }
162
163 if (N == 3)
164 {
165 Guess(1);
166 i = Guess(3);
167 if (i > 0) return 3;
168 if (i < 0) return 1;
169 return 2;
170 }
171
172 mid = (N+2)/2;
173 Guess(mid-2);
174 i = Guess(mid);
175 if (i == 0) return mid-1;
176 if (i < 0) return endgame(1, mid);
177 return endgame(N, N-mid+1);
178 }
179
180 // -------------- begin grader ---------------------
181
182 static int moves, TT, NN, prev = -1;
183 int Guess(int x)
184 {
185 int r;
186
187 if (prev == -1 || abs(x-TT) == abs(prev-TT)) r = 0;
CAPITOLUL 10. IOI 2010 10.2. HOTTER COLDER 990
188 else
189 if (abs(x-TT) > abs(prev-TT)) r = -1;
190 else r = 1;
191
192 prev = x;
193 if (x < 1 || x > NN) exit(92);
194 moves++;
195 return r;
196 }
197
198 int main()
199 {
200 freopen("../tests/Subtask4-data/grader.in.2", "r", stdin);
201 //freopen("hottercolder.out", "w", stdout);
202
203 int n=0,i,t,OK=0,sub1=0,sub2=0,sub3=0;
204 double worst = 999999;
205 while (2 == scanf("%d%d",&NN,&TT))
206 {
207 if (NN > n) n = NN;
208 prev = -1;
209 moves = 0;
210 int h = HC(NN);
211 if (h != TT)
212 {
213 exit(91);
214 }
215
216 int W = floor(0.00001+log(3*NN)/log(2));
217 double alpha = 2 - (double)moves/W;
218 if (alpha < worst) worst = alpha;
219
220 // 1 means failure
221 if ( NN <= 500 && moves > 500 ) exit(93);
222 if ( NN <= 500 && moves > 18 ) sub2=1;
223 if ( NN <= 500 && moves > 16 ) sub3=1;
224 OK++;
225 }
226
227 if (!sub1) printf("OK 1\n");
228 if (!sub2) printf("OK 2\n");
229 if (!sub3) printf("OK 3\n");
230
231 if (worst > 0) printf("OK 4 alpha %0.2lf\n",worst);
232
233 return 0;
234 }
235
236 // -------------- end grader ---------------------
237 /*
238 OK 1
239 OK 2
240 OK 3
241 OK 4 alpha 1.00
242
243 Process returned 0 (0x0) execution time : 4.323 s
244 Press any key to continue.
245 */
#include "grader.h"
#include "hottercolder.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int cal(int n)
{
return n < 5 ? 1 : (n + 1 >> 1) - cal(n >> 1);
}
CAPITOLUL 10. IOI 2010 10.2. HOTTER COLDER 991
int HC(int N)
{
int L = 1, R = N, prv, nxt, t, W = log(3 * N) / log(2);
while (L < R)
{
if (R == 2)
{
Guess(1);
return Guess(2) < 0 ? 1 : 2;
}
int cut = W & 1 ? (2 << W - 2) / 3 + 1 : (2 << W - 2) / 3 + 2;
nxt = R == N ? cut + cal(R - cut) : cut + cut - 1;
prv = cut + cut - nxt;
Guess(prv);
t = Guess(nxt);
if (t == -1) R = prv + nxt - 1 >> 1;
if (t == 0) return prv + nxt >> 1;
if (t == 1)
{
L = prv + nxt + 2 >> 1;
prv = nxt;
while (L < R)
{
nxt = (L + R >> 1 << 1) - prv;
if (nxt == prv) nxt++;
if (nxt < 1) nxt = 1;
if (nxt > N) nxt = N;
t = Guess(nxt);
if (t == -1)
{
if (prv < nxt) R = nxt + prv - 1 >> 1;
else L = nxt + prv + 2 >> 1;
}
if (t == 0) return nxt + prv >> 1;
if (t == 1)
{
if (prv < nxt) L = nxt + prv + 2 >> 1;
else R = nxt + prv - 1 >> 1;
}
prv = nxt;
}
}
W -= 2;
}
return L;
}
int main()
{
//freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
freopen("../tests/Subtask4-data/grader.in.2", "r", stdin);
int n=0,i,t,OK=0,sub1=0,sub2=0,sub3=0;
double worst = 999999;
while (2 == scanf("%d%d",&NN,&TT))
{
if (NN > n) n = NN;
prev = -1;
moves = 0;
int h = HC(NN);
CAPITOLUL 10. IOI 2010 10.2. HOTTER COLDER 992
if (h != TT)
{
exit(91);
}
int W = floor(0.00001+log(3*NN)/log(2));
double alpha = 2 - (double)moves/W;
if (alpha < worst) worst = alpha;
// 1 means failure
if ( NN <= 500 && moves > 500 ) exit(93);
if ( NN <= 500 && moves > 18 ) sub2=1;
if ( NN <= 500 && moves > 16 ) sub3=1;
OK++;
}
if (!sub1) printf("OK 1\n");
if (!sub2) printf("OK 2\n");
if (!sub3) printf("OK 3\n");
if (worst > 0) printf("OK 4 alpha %0.2lf\n",worst);
return 0;
}
// ----------------------- end grader --------------------
/*
OK 1
OK 2
OK 3
OK 4 alpha 1.00
#include "grader.h"
#include "hottercolder.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <bits/stdc++.h>
#define f first
#define s second
#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define rsz resize
#define bk back()
#define pb push_back
vi soFar, guess;
pi posi;
int N;
bool tri(int x)
{
guess.pb(Guess(x));
if (guess.bk == 0)
{
if (sz(soFar) && soFar.bk != x)
posi.f = posi.s = (soFar.bk+x)/2;
}
else
{
if (guess.bk == -1)
{
if (x < soFar.bk)
{
ckmax(posi.f,(soFar.bk+x)/2+1);
}
else
{
ckmin(posi.s,(soFar.bk+x-1)/2);
}
}
else
{
if (x < soFar.bk)
{
ckmin(posi.s,(soFar.bk+x-1)/2);
}
else
{
ckmax(posi.f,(soFar.bk+x)/2+1);
}
}
}
soFar.pb(x); assert(posi.f <= posi.s);
return posi.f == posi.s;
}
int binSearch()
{
while (1)
{
int des = posi.f+posi.s-soFar.bk;
ckmax(des,1); ckmin(des,N);
if (tri(des)) return posi.f;
}
}
}
}
int Guess(int x)
{
int r;
if (prevv == -1 || abs(x-TT) == abs(prevv-TT)) r = 0;
else
if (abs(x-TT) > abs(prevv-TT)) r = -1;
else r = 1;
prevv = x;
if (x < 1 || x > NN) exit(92);
moves++;
return r;
}
int main()
{
//freopen("../tests/Subtask1-data/grader.in.1", "r", stdin);
freopen("../tests/Subtask4-data/grader.in.2", "r", stdin);
int n=0,i,t,OK=0,sub1=0,sub2=0,sub3=0;
double worst = 999999;
while (2 == scanf("%d%d",&NN,&TT))
{
if (NN > n) n = NN;
prevv = -1;
moves = 0;
int h = HC(NN);
if (h != TT)
{
exit(91);
}
int W = floor(0.00001+log(3*NN)/log(2));
double alpha = 2 - (double)moves/W;
if (alpha < worst) worst = alpha;
// 1 means failure
if ( NN <= 500 && moves > 500 ) exit(93);
if ( NN <= 500 && moves > 18 ) sub2=1;
if ( NN <= 500 && moves > 16 ) sub3=1;
OK++;
}
if (!sub1) printf("OK 1\n");
if (!sub2) printf("OK 2\n");
if (!sub3) printf("OK 3\n");
if (worst > 0) printf("OK 4 alpha %0.2lf\n",worst);
return 0;
}
// ----------------------- end grader --------------------
/*
OK 1
OK 2
OK 3
OK 4 alpha 1.00
Cities in Alberta tend to be laid out as rectangular grids of blocks. Blocks are labeled with
coordinates 0 to R 1 from north to south and 0 to C 1 from west to east.
The quality of living in each particular block has been ranked by a distinct number, called
quality rank, between 1 and R C, where 1 is the best and R C is the worst.
The city planning department wishes to identify a rectangular set of blocks with dimensions H
from north to south and W from west to east, such that the median quality rank among all blocks
in the rectangle is the best. H and W are odd numbers not exceeding R and C respectively. The
median quality rank among an odd number of quality ranks is defined to be the quality rank m in
the set such that the number of quality ranks better than m equals the number of quality ranks
worse than m.
You are to implement a procedure rectangle(R,C,H,W,Q) where R and C represent the
total size of the city, H and W represent the dimensions of the set of blocks, and Q is an array
such that Qab is the quality rank for the block labeled a from north to south and b from west
to east.
Your implementation of rectangle must return a number: the best (numerically smallest)
possible median quality rank of an H by W rectangle of blocks.
Each test run will only call rectangle once.
Example 1
5 11 12 16 25
17 18 2 7 10
R 5, C 5, H 3, W 3, Q = 4 23 20 3 1
24 21 19 14 9
6 22 8 13 15
For this example, the best (numerically smallest) median quality rank of 9 is achieved by the
middle-right rectangle of Q shown in bold. That is, rectangle(R,C,H,W,Q)=9
Example 2
6 1 2 11 7 5
R 2, C 6, H 1, W 5, Q =
9 3 4 10 12 8
For this example the correct answer is 5.
Subtask 1 [20 points]
Assume R and C do not exceed 30.
Subtask 2 [20 points]
Assume R and C do not exceed 100.
Subtask 3 [20 points]
Assume R and C do not exceed 300.
Subtask 4 [20 points]
Assume R and C do not exceed 1 000.
Subtask 5 [20 points]
Assume R and C do not exceed 3 000.
Implementation Details
Implementation folder: /home/ioi2010-contestant/quality/
To be implemented by contestant: quality.c or quality.cpp or quality.pas
Contestant interface: quality.h or quality.pas
Grader interface: none
Sample grader: grader.c or grader.cpp or grader.pas
CAPITOLUL 10. IOI 2010 10.3. QUALITY OF LIVING 997
This problem looks like many other grid tasks. Such problems have also appeared on some
previous IOIs. Heavy range-search algorithms might seem to be useful, but actually a much
simpler 100% solution exists.
Let N R C measure the size of a problem instance.
Subtask 1
Subtask 1 can be solved by the most obvious brute force algorithm that considers each rectangle
2
(there are R H 1 C W 1 of these), quadratically sorts its contents ( H W steps),
and directly picks out the median rank, and optimizes this. The worst case situation is obtained
3
by H R©2 and W C ©2. Therefore, this algorithm’s time complexity is O N .
Subtask 2
Using any O N log N sort algorithm (these are well-known), the brute force algorithm can be
2
improved to O N log N . This solves subtask 2.
2
Also, an O N sort (bucket sort) is possible, to obtain a simple O N algorithm, but this
does not suffice to solve Subtask 3. See below for a Pascal implementation.
There are some obvious opportunities for improvement, such as exploiting the large overlap
between certain rectangles when filling/emptying the array to be sorted. But these improvements
do not affect the time complexity.
Subtask 3
1.5
O N log N algorithms are also possible and they solve Subtask 3. Here is one: say the
0.5
vertical offset of the final rectangle is known [O N possibilities]. Then scan across the row,
using some efficient data structure to keep track of the median (think of incremental/sliding
window, such as a range tree plus binary search, or a pair of heaps for values less/greater than the
median). [Each value is added/subtracted from the data structure exactly once, for an O N log N
scan length.]
This is rather involved to code; see Subtask 5 for a simpler and better solution.
Subtask 4
This subtask accommodates possibleO N log N log N algorithms, although we have not en-
countered them.
Subtask 5
Here is a O N log N solution. Observe that the program’s output can be verified by some
algorithm which answers the question ”Does any rectangle have median & X?” This query can
be answered in O n time. A rectangle has median & X if and only if it contains more values
2
& X than otherwise. Assign all cells in the grid a ’value’ according to a ’threshold’ function: -1 if
greater than X, 0 if equal to X, 1 if less than X. Using the well-known cumulative data structure
for queries on rectangular sums, try all possible rectangle locations and return ”yes” if the ’values’
inside any sum to ' 0. We simply binary search values of X to find the minimum value for which
the answer is ”yes”.
CAPITOLUL 10. IOI 2010 10.3. QUALITY OF LIVING 998
#include <stdio.h>
#include <stdlib.h>
#include "quality.h"
#include<ctime>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdint>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <vector>
#include <bitset>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#include <tuple>
#include <list>
#include <set>
#include <map>
#define add push_back
#define m_p make_pair
#define fr first
#define sc second
#define endl ’\n’
int rectangle(int nn, int mm, int hh, int ww, int a[M][M])
{
n = nn;
m = mm;
h = hh;
w = ww;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
matrix[i + 1][j + 1] = a[i][j];
}
}
BinarySearch(0, n * m);
return ans;
}
int main()
{
auto t1 = clock();
scanf("%d%d%d%d",&R,&C,&H,&W);
for (i=0;i<R;i++)
for (j=0;j<C;j++) scanf("%d",&Q[i][j]);
CAPITOLUL 10. IOI 2010 10.3. QUALITY OF LIVING 1001
auto t2 = clock();
ans = rectangle(R,C,H,W,Q);
auto t3 = clock();
printf("%d\n",ans);
auto t4 = clock();
return 0;
}
#include<bits/stdc++.h>
#include "quality.h"
{
if(target < (H*W)/2)
return false;
F0R(i, R)
F0R(j ,C)
{
pre[i][j]=(rect[i][j]==target ? 0:(rect[i][j]<target ? -1:1))+
(i==0 ? 0:pre[i-1][j]) + (j==0 ? 0:pre[i][j-1]) -
((i==0||j==0) ? 0 : pre[i-1][j-1]);
int main()
{
auto t1 = clock();
scanf("%d%d%d%d",&R,&C,&H,&W);
for (i=0;i<R;i++)
for (j=0;j<C;j++) scanf("%d",&Q[i][j]);
auto t2 = clock();
ans = rectangle(R,C,H,W,Q);
auto t3 = clock();
printf("%d\n",ans);
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/Subtask5-data/grader.in.3-5",
(char*)"../tests/Subtask5-data/grader.expect.3-5",
(char*)"quality.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
10.4 Languages
Problema 4 - Languages 100 de puncte
You are to write an interactive program that, given a sequence of Wikipedia excerpts (see
example below), guesses the language of each, in turn. After each guess, your program is given
the correct answer, so that it may learn to make better guesses the longer it plays.
Each language is represented by a number L between 0 and 55. Each excerpt has exactly 100
symbols, represented as an array E of 100 integers between 1 and 65 535. These integers between
1 and 65 535 have been assigned arbitrarily, and do not correspond to any standard encoding.
You are to implement the procedure excerpt(E) where E is an array of 100 numbers representing
a Wikipedia excerpt as described above. Your implementation must call language(L) once, where
L is its guess of the language of the Wikipedia edition from which E was extracted. The grading
server implements language(L), which scores your guess and returns the correct language. That
is, the guess was correct if language(L) = L.
CAPITOLUL 10. IOI 2010 10.4. LANGUAGES 1004
The grading server calls excerpt(E) 10 000 times, once for each excerpt in its input file. Your
implementation’s accuracy is the fraction of excerpts for which excerpt(E) guessed the correct
language.
You may use any method you wish to solve this problem. Rocchio’s method is an approach
that will yield accuracy of approximately 0.4. Rocchio’s method computes the similarity of E to
each language L seen so far, and chooses the language that is most similar. Similarity is defined
as the total number of distinct symbols in E that appear anywhere amongst the previous excerpts
from language L.
Note that the input data have been downloaded from real Wikipedia articles, and that there
may be a few malformed characters or fragments of text. This is to be expected, and forms part
of the task.
Example
For illustration only, we show the textual representation of excerpts from 56 language-specific
editions of Wikipedia.
1. Yshokkie word meestal in Kanada , die noorde van die VSA en in Europa gespeel. Dit is
bekend as ’n b
...
54. Paris By Night 84: In Atlanta - Passport to Music & Fashion (m nhc v Thi trang) l chng
tr
55. ISO 3166-2:GU ni akoole ninu ISO 3166-2 , apa opagun ISO 3166 ti International Organi-
zation for Stan
56. /Tbn Kama 2002 22
The sample input file grader.in.1 contains 10 000 such examples. The 56 languages are those
listed as ”mother tongue” in the IOI 2010 registration data. The language for each excerpt is
chosen at random from these 56 languages, and each excerpt is taken from the first paragraph
of an article chosen at random from the corresponding Wikipedia edition. Each line of the file
contains:
The two-letter ISO code for the Wikipedia language edition;
100 numbers between 1 and 65 535, representing the first 100 symbols, in sequence, of the
first paragraph of the article;
a viewable representation (in UTF-8) of the 100 symbols that you can read in your text
editor or Firefox web browser. This viewable representation is for your convenience only,
and is not intended to be used as input for your program.
The official grader uses 10 000 different excerpts, selected in the same way from the same 56
Wikipedia editions. However, the grader assigns a different number between 0 and 55 to each
language, and a different number between 1 and 65 535 to each symbol.
Subtask 1 [30 points]
Your submission must achieve accuracy of 0.3 or better on the grading server.
Subtask 2 [up to 80 points]
Your score will be 114 α 0.3, rounded to the nearest integer, where α is the accuracy of
your submission.
Implementation Details
Implementation folder: /home/ioi2010-contestant/language/
To be implemented by contestant: lang.c or lang.cpp or lang.pas
Contestant interface: lang.h or lang.pas
Grader interface: grader.h or graderlib.pas
Sample grader: grader.c or grader.cpp or grader.pas and graderlib.pas
Sample grader input: grader.in.1.
Note: Each line of input contains: a two-character language code; an excerpt represented as
100 numbers separated by spaces; the text representation of the excerpt.
Expected output for sample grader input: If the implementation calls language as specified
for each of the 10 000 examples, the sample grader will output OKalpha where alpha is the
accuracy.
Compile and run (command line): runc grader.c or runc grader.cpp or
runc grader.pas
CAPITOLUL 10. IOI 2010 10.4. LANGUAGES 1005
Compile and run (gedit plugin): Control-R, while editing any implementation file.
Submit (command line): submit grader.c or submit grader.cpp or
submit grader.pas
Submit (gedit plugin): Control-J, while editing any implementation or grader file.
The nature of this problem is innovative within the IOI. Its purpose is to bring the field
of information retrieval under the attention. This problem is discussed in detail in the book
Information Retrieval: Implementing and Evaluating Search Engines by S. Bttcher, C.L.A. Clarke,
and G.V. Cormack (MIT Press, to appear soon). Especially see Chapter 10 on Categorization
and Filtering.
One important observation is that excerpts from the same language version of Wikipedia will
share some characteristics in a statistical sense. Because many random excerpts are offered, the
variability between excerpts from the same language play a negligible role. It has been confirmed
that the statistical resemblance between the provided test input and the official grader input is
highly predictable.
Note that because of the random re-coding of the language codes and symbol codes, there is
no opportunity to hard code any specific (personal) language knowledge into a solution.
There are many approaches possible. Rocchio’s method, which was informally described in the
task description, suffices to solve Subtask 1.
For Subtask 2, one needs to do more than simply look at symbol frequencies. Collecting
statistics on bigrams (pairs of neighboring symbols), trigrams (three consecutive symbols) will
yield higher accuracies.
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include<iostream>
#include <cmath>
#include <string.h>
#include "grader.h"
#include "lang.h"
memset(now,0,sizeof(now));
p3[0]=(E[0]<<10ˆE[1]<<5ˆE[2])&mod;
c=num3[p3[0]];
if(c!=0)
{
for(j=0;j<56;j++)
{
z=cbrt(pre3[j][p3[0]]);
now[j]+=2*z*z/(c+1);
}
}
for(i=1;i<98;i++)
{
p3[i]=(p3[i-1]<<5ˆE[i+2])&mod;
c=num3[p3[i]];
if(c!=0)
{
for(j=0;j<56;++j)
{
z=cbrt(pre3[j][p3[i]]);
now[j]+=z*z/(c+2);
}
}
}
for(i=0;i<100;i++)
{
if(num1[E[i]]!=0)
{
for(j=0;j<56;++j)
{
z=cbrt(pre1[E[i]][j]);
now[j]+=z*z/num1[E[i]];
}
}
}
mx=now[0];
for(i=1;i<56;i++)
{
if(now[i]>mx)
{
mx=now[i];
mxnum=i;
}
}
r=language(mxnum);
for(i=0;i<98;i++)
{
num3[p3[i]]++;
pre3[r][p3[i]]++;
}
for(i=0;i<100;i++)
{
num1[E[i]]++;
pre1[E[i]][r]++;
}
}
#define N 100
int language(int L) {
if (L < 0 || L >= 56) exit(92);
rightt += (L == lnum);
tot++;
return lnum;
}
int main()
{
auto t1 = clock();
CAPITOLUL 10. IOI 2010 10.4. LANGUAGES 1007
auto t2 = clock();
auto t3 = clock();
printf("OK %0.2lf%%\n",100.0*rightt/tot);
auto t4 = clock();
printf("OK %0.2lf%%\n",100.0*rightt/tot);
std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
return 0;
}
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include<iostream>
#include<cstring>
#include <map>
#include <algorithm>
#include <vector>
#include "lang.h"
#include "grader.h"
struct WD
{
long long t1, t2;
void init()
{
t1 = t2 = 0;
}
void addwd(int p, int pos)
{
if(pos == 0) t1 = p;
CAPITOLUL 10. IOI 2010 10.4. LANGUAGES 1008
bool operator<(WD a, WD b)
{
return a.t1 != b.t1 ? (a.t1 > b.t1) : (a.t2 > b.t2);
}
map<WD,int> mp;
const int l = 5;
#define N 100
int language(int L)
{
if (L < 0 || L >= 56) exit(92);
rightt += (L == lnum);
tot++;
return lnum;
}
int main()
{
auto t1 = clock();
auto t2 = clock();
excerpt(uni);
}
auto t3 = clock();
printf("OK %0.2lf%%\n",100.0*rightt/tot);
auto t4 = clock();
printf("OK %0.2lf%%\n",100.0*rightt/tot);
std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
return 0;
}
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include<iostream>
#include "grader.h"
#include "lang.h"
#include <bits/stdc++.h>
using namespace std;
int cnt[57][80808];
int cnt2[57][80808];
int cnt3[57][80808];
int cnt4[57][80808];
int lann[57];
double f(int x)
{
return (double)x / (x + 1);
}
#define N 100
int language(int L)
{
if (L < 0 || L >= 56) exit(92);
rightt += (L == lnum);
tot++;
return lnum;
}
int main()
{
auto t1 = clock();
auto t2 = clock();
auto t3 = clock();
printf("OK %0.2lf%%\n",100.0*rightt/tot);
auto t4 = clock();
printf("OK %0.2lf%%\n",100.0*rightt/tot);
std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t3-t2 = " << (double)(t3 - t2) / CLOCKS_PER_SEC << ’\n’;
std::cout <<"t4-t3 = " << (double)(t4 - t3) / CLOCKS_PER_SEC << ’\n’;
return 0;
}
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include<iostream>
#include <bits/stdc++.h>
#define FOR(i, x, y) for (int i = x; i < y; i++)
typedef long long ll;
#include "grader.h"
int best = 0;
CAPITOLUL 10. IOI 2010 10.4. LANGUAGES 1012
double best_sim = 0;
FOR(i, 0, LANGS)
{
double sim = 0;
FOR(j, 0, SZ - 3)
{
sim += hyperb(freq[i][qu[j]]) * 138;
sim += hyperb(freq[i][tr[j]]) * 60;
sim += hyperb(freq[i][bi[j]]) * 97;
sim += hyperb(freq[i][si[j]]) * 1;
}
sim /= log(cnt[i] + 1);
#define N 100
int language(int L)
{
if (L < 0 || L >= 56) exit(92);
rightt += (L == lnum);
tot++;
return lnum;
}
int main()
{
auto t1 = clock();
auto t2 = clock();
auto t3 = clock();
printf("OK %0.2lf%%\n",100.0*rightt/tot);
auto t4 = clock();
printf("OK %0.2lf%%\n",100.0*rightt/tot);
std::cout <<"t2-t1 = " << (double)(t2 - t1) / CLOCKS_PER_SEC << ’\n’;
CAPITOLUL 10. IOI 2010 10.5. MEMORY 1013
return 0;
}
10.5 Memory
Problema 5 - Memory 100 de puncte
This was intended to be another very easy task, though slightly more difficult than the one on
Day 1 when aiming for a full score.
Turning each possible pair of cards face up in some sequence is guaranteed to obtain all 25
candies. There are 50-choose-2 = 50 * 49 / 2 = 1225 such pairs. Hence, doing 2450 card turns
(that is, calls to faceup) suffices. This can be programmed with two nested for-loops, and it
solves Subtask 1.
CAPITOLUL 10. IOI 2010 10.5. MEMORY 1015
But it does not solve Subtask 2, where no more than 100 card turns are allowed. Note that
the try-all-pairs solution does not look at what is on the cards that are turned face up. That is,
it does not make use of the values returned by faceup. By using these returned values, you can
gather information that can be used later to reduce the number of cards turned up.
In particular, taking this to an extreme, you can first turn all cards, in pairs, to discover and
record where all the letters are, without caring about turning up equal pairs. In this first round,
you might already obtain some candies by accident, but that is irrelevant. In the next round, you
know where equal pairs are and you can flip them, in sequence, to obtain all remaining candies.
The first round requires 50 turns (calls to faceup), and the second round another 50 turns.
Thus, altogether 100 times a card is turned, and thereby Subtask 2 is solved.
In the second round, you could skip equal pairs that were already identified in the first round.
However, that will not improve the worst-case performance and it will complicate the coding.
Here is a Pascal solution that can readily be generalized (the constant and type definitions
could be eliminated, but they document the relevant concepts nicely):
void play()
{
CAPITOLUL 10. IOI 2010 10.5. MEMORY 1016
// initialize index
for (lt = 0; lt < 25; ++lt)
{
for (k = 0; k < 2; ++k)
{
index[lt][k] = 0;
}
}
// first round
for (i = 1; i <= 50; ++i)
{
r = faceup(i);
lt = (int)(r) - (int)(’A’); // int corresponding to char r
k = (index[lt][0]) ? 1 : 0;
index[lt][k] = i;
}
// second round
for (lt = 0; lt < 25; ++lt)
{
faceup( index[lt][0] ); // result ignored
faceup( index[lt][1] ); // result ignored
}
#include<bits/stdc++.h>
void play()
{
map<char, vector<int>> mp;
for (int i = 1; i <= 50; i++)
mp[faceup(i)].push_back(i);
char faceup(int C)
{
int c0, c1;
if (C < 1 || C > 50 || is_up[C])
{
exit(92);
}
CAPITOLUL 10. IOI 2010 10.5. MEMORY 1017
is_up[C] = 1;
up[moves%2] = C;
moves++;
if (moves%2 == 0)
{
c0 = card[ up[0] ] - ’A’;
c1 = card[ up[1] ] - ’A’;
if (c0==c1 && !candy[c0])
{
candy[c0] = 1;
++candies;
}
is_up[ up[0] ] = is_up[ up[1] ] = 0;
}
return card[C];
}
void playgame()
{
int i;
for (i=1;i<=50;i++)
{
card[i] = getchar();
}
moves = candies = 0;
play();
if (candies != 25)
{
exit(91);
}
}
int main()
{
std::freopen("../tests/Subtask1-data/grader.in.99", "r", stdin);
//std::freopen("cluedo.out", "w", stdout);
playgame();
printf("OK %d\n",moves);
return 0;
}
// ------------ end grader --------------------
#include <bits/stdc++.h>
vector<int> a[26];
void play()
{
for(int i=1;i <= 50;i++){ char x=faceup(i); a[x-’A’].push_back(i); }
for(int i = 0;i < 25;i++) faceup(a[i][0]),faceup(a[i][1]);
}
char faceup(int C)
{
int c0, c1;
if (C < 1 || C > 50 || is_up[C])
{
exit(92);
}
CAPITOLUL 10. IOI 2010 10.5. MEMORY 1018
is_up[C] = 1;
up[moves%2] = C;
moves++;
if (moves%2 == 0)
{
c0 = card[ up[0] ] - ’A’;
c1 = card[ up[1] ] - ’A’;
if (c0==c1 && !candy[c0])
{
candy[c0] = 1;
++candies;
}
is_up[ up[0] ] = is_up[ up[1] ] = 0;
}
return card[C];
}
void playgame()
{
int i;
for (i=1;i<=50;i++)
{
card[i] = getchar();
}
moves = candies = 0;
play();
if (candies != 25)
{
exit(91);
}
}
int main()
{
std::freopen("../tests/Subtask1-data/grader.in.98", "r", stdin);
//std::freopen("cluedo.out", "w", stdout);
playgame();
printf("OK %d\n",moves);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include<bits/stdc++.h>
int A[51][2],B[51];
void play()
{
for (int i = 1; i <= 50; i++)
{
int x = (faceup(i) - ’A’ + 1);
A[x][B[x]++] = i;
}
for (int i = 1; i <= 25; i++)
{
faceup(A[i][0]);
faceup(A[i][1]);
}
return ;
}
char faceup(int C)
{
int c0, c1;
if (C < 1 || C > 50 || is_up[C])
{
exit(92);
}
is_up[C] = 1;
up[moves%2] = C;
moves++;
if (moves%2 == 0)
{
c0 = card[ up[0] ] - ’A’;
c1 = card[ up[1] ] - ’A’;
if (c0==c1 && !candy[c0])
{
candy[c0] = 1;
++candies;
}
is_up[ up[0] ] = is_up[ up[1] ] = 0;
}
return card[C];
}
void playgame()
{
int i;
for (i=1;i<=50;i++)
{
card[i] = getchar();
}
moves = candies = 0;
play();
if (candies != 25)
{
exit(91);
}
}
int main()
{
std::freopen("../tests/Subtask1-data/grader.in.97", "r", stdin);
//std::freopen("cluedo.out", "w", stdout);
playgame();
printf("OK %d\n",moves);
return 0;
}
Make the same assumptions as in Subtask 1, but there are at most 1 000 000 cities.
Subtask 3 [25 points]
The assumptions from Subtask 1 may no longer be true.
There are at most 1000 cities.
Subtask 4 [25 points]
The assumptions from Subtask 1 may no longer be true.
There are at most 1 000 000 cities.
Implementation Details
Implementation folder: /home/ioi2010-contestant/traffic/
To be implemented by contestant: traffic.c or traffic.cpp or traffic.pas
Contestant interface: traffic.h or traffic.pas
Grader interface: none
Sample grader: grader.c or grader.cpp or grader.pas
Sample grader input: grader.in.1 grader.in.2
Note: The first line of the input file contains N . The following N lines contain P i for i
between 0 and N 1. The following N 1 lines contain pairs S i Di for i between 0 and
N 2.
Expected output for sample grader input: grader.expect.1 grader.expect.2 etc.
Compile and run (command line): runc grader.c or runc grader.cpp or
runc grader.pas
Compile and run (gedit plugin): Control-R, while editing any implementation file.
Submit (command line): submit grader.c or submit grader.cpp or
submit grader.pas
Submit (gedit plugin): Control-J, while editing any implementation or grader file.
This was (by intention) a fairly standard task. Though, it should be mentioned that graph
problems always are a bit trickier than one might at first think because of the need to handle
specific graph encodings.
The information provided below will be expanded in the future, but for now should help in
understanding what each subtask was expecting in the form of algorithms.
Subtask 1: Quadratic works. Because of the highly regular (linear) structure of the network
graph, it is easy to try each city as location for the arena, calculate the worst congestions
and pick out the location where this worst congestion is minimal.
Subtask 2: Requires linear algorithm, but because there are only two leaves and the graph
representation is highly regular, it is easy to see that one sweep over the cities along the
roads suffices to determine the optimum location.
Subtask 3: Quadratic works, but now the general graph must be handled. Again, as in
Subtask 1, every city can be tried as arena location, the worst congestion can then be
calculated, and best location can be found.
Subtask 4: This is the full problem. A linear traversal of the graph, accumulating congestion
information appropriately, enables one to determine the optimal location of the arena in
linear time.
CAPITOLUL 10. IOI 2010 10.6. TRAFFIC CONGESTION 1022
#include<iostream>
#include<ctime>
#include<vector>
#include<algorithm>
vector<int> g[1000005];
long long num[1000005],minv=1000000000000000000;
int n,ans;
int main()
{
auto t1 = clock();
int i;
scanf("%d",&N);
for (i=0;i<N;i++) scanf("%d",&P[i]);
for (i=0;i<N-1;i++) scanf("%d%d",&S[i],&D[i]);
auto t2 = clock();
int r = LocateCentre(N,P,S,D);
auto t3 = clock();
printf("%d\n",r);
auto t4 = clock();
return 0;
}
#include<iostream>
#include<ctime>
#include<bits/stdc++.h>
return ans.second;
}
int main()
{
auto t1 = clock();
int i;
scanf("%d",&N);
for (i=0;i<N;i++) scanf("%d",&P[i]);
for (i=0;i<N-1;i++) scanf("%d%d",&S[i],&D[i]);
auto t2 = clock();
int r = LocateCentre(N,P,S,D);
auto t3 = clock();
printf("%d\n",r);
auto t4 = clock();
return 0;
}
#include<iostream>
#include<ctime>
#include <bits/stdc++.h>
dfs (1,0);
return sol - 1;
int main()
{
auto t1 = clock();
int i;
scanf("%d",&N);
CAPITOLUL 10. IOI 2010 10.7. MAZE 1026
auto t2 = clock();
int r = LocateCentre(N,P,S,D);
auto t3 = clock();
printf("%d\n",r);
auto t4 = clock();
return 0;
}
int main()
//int main(int argc, char * argv[])
{
int argc=4;
char* argv[] =
{
(char*)"checker",
(char*)"../tests/Subtask4-data/grader.in.52-4",
(char*)"../tests/Subtask4-data/grader.expect.52-4",
(char*)"traffic.out",
};
cout<<"argc = "<<argc<<"\n";
for(int kk=0;kk<argc;kk++)
cout<<argv[kk]<<"\n";
cout<<"----------------------\n";
10.7 Maze
Problema 7 - Maze 100 de puncte
Authors: Monika Steinová (CHE/SWK), Michal Foris̆ek (SWK)
CAPITOLUL 10. IOI 2010 10.7. MAZE 1027
##X#######
###X######
####X##X##
##########
##XXXX####
##########
The symbol # represents a square with standing cornstalks, and X represents a square with
an obstacle (such as a tree) that cannot be crushed to form a pathway.
The field is transformed into a maze by crushing squares occupied by corn. One crushed square
(the entrance) must be on the edge of the field. The other crushed squares must be in the interior.
The objective is to maximize the shortest path from the entrance to the core, measured by the
number of crushed squares that Jack must pass through, including the entrance and the core. It
is possible to pass from one square to another only if both are crushed and they share an edge.
In your submission, the crushed squares should be identified by periods (.). Exactly one of the
crushed squares should be on the perimeter. For example:
#.X#######
#.#X#...##
#...X#.X.#
#.#......#
#.XXXX##.#
##########
Below, for illustration purposes only, we mark the entrance E, the core C and remainder of
the path using . The path length is 12.
#EX#######
#+#X#C+.##
#+++X#+X.#
#.#++++..#
#.XXXX##.#
##########
named maze1.txt maze2.txt etc., and transform them into valid mazes by replacing some of
the # symbols by periods.
Note: the Grading Server Public Test will award 1 point per subtask for any valid solution
(regardless of the path length). The Grading Server Release Test will award the remaining points.
The total score for the task will be rounded to the nearest integer between 0 and 110.
Subtask 1 [up to 11 points]
The field described above (of size 6 10) may be found in the file field1.txt. Create a
maze for this field named maze1.txt that has a shortest path from the entrance to the core
P ©20
with length P . Your score for this subtask will be the minimum of 11 and 10 . Note that the
sample solution scores 3.98 points.
Subtask 2 [up to 11 points]
The file field2.txt represents a field of size 100 100. Create a maze for this field named
maze2.txt that has a shortest path from the entrance to the core of length P . Your score for
P ©4000
this subtask will be the minimum of 11 and 10 .
Subtask 3 [up to 11 points]
The file field3.txt represents a field of size 100 100. Create a maze for this field named
maze3.txt that has a shortest path from the entrance to the core of length P . Your score for
P ©4000
this subtask will be the minimum of 11 and 10 .
Subtask 4 [up to 11 points]
The file field4.txt represents a field of size 100 100. Create a maze for this field named
maze4.txt that has a shortest path from the entrance to the core of length P . Your score for
P ©4000
this subtask will be the minimum of 11 and 10 .
Subtask 5 [up to 11 points]
The file field5.txt represents a field of size 100 100. Create a maze for this field named
maze5.txt that has a shortest path from the entrance to the core of length P . Your score for
P ©5000
this subtask will be the minimum of 11 and 10 .
Subtask 6 [up to 11 points]
The file field6.txt represents a field of size 11 11. Create a maze for this field named
maze6.txt that has a shortest path from the entrance to the core of length P . Your score for
P ©54
this subtask will be the minimum of 11 and 10 .
Subtask 7 [up to 11 points]
The file field7.txt represents a field of size 20 20. Create a maze for this field named
maze7.txt that has a shortest path from the entrance to the core of length P . Your score for
P ©33
this subtask will be the minimum of 11 and 10 .
Subtask 8 [up to 11 points]
The file field8.txt represents a field of size 20 20. Create a maze for this field named
maze8.txt that has a shortest path from the entrance to the core of length P . Your score for
P ©95
this subtask will be the minimum of 11 and 10 .
Subtask 9 [up to 11 points]
The file field9.txt represents a field of size 11 21. Create a maze for this field named
maze9.txt that has a shortest path from the entrance to the core of length P . Your score for
P ©104
this subtask will be the minimum of 11 and 10 .
Subtask 10 [up to 11 points]
The file fieldA.txt represents a field of size 200 200. Create a maze for this field named
mazeA.txt that has a shortest path from the entrance to the core of length P . Your score for
P ©7800
this subtask will be the minimum of 11 and 10 .
Implementation Details
This is an output-only task.
Implementation folder: /home/ioi2010-contestant/maze/
To be submitted by contestant: maze1.txt maze2.txt maze3.txt maze4.txt
maze5.txt maze6.txt maze7.txt maze8.txt maze9.txt mazeA.txt.
Contestant interface: none
Grader interface: none
CAPITOLUL 10. IOI 2010 10.8. SAVEIT 1029
10.8 Saveit
Problema 8 - Saveit 100 de puncte
Author: Mihai Pătraşcu (ROM)
CAPITOLUL 10. IOI 2010 10.8. SAVEIT 1030
Contestant interface:
` encoder.h or encoder.pas
` decoder.h or decoder.pas
This task also is innovative for the IOI. In general, for most IOI tasks efficiency matters.
However, in this case it is not execution time or memory usage but rather communication efficiency:
how to represent some complex data in as few bits as possible, without losing information.
This difference in focus makes the tasks possibly somewhat harder to understand. Further-
more, it is technically more complicated, because the contestant has to program two independent
procedures that are inverses to each other. The communication format is not prescribed; all that
matters is that the decoder programmed by the contestant can decode the data from the encoder
that is also programmed by the contestant. The grading server then connects these two procedures
to verify that the decoder can indeed ”understand” what the encouder produced.
Two things are important. First, find a way to encode adjacency information about Xedef’s
package transportation network. Second, to transmit that information with communication effi-
ciency.
Briefly stated, the subtasks could be tackled as follows:
Subtask 1: You can send the entire adjacency matrix ”as is”; this information is naturally
expressed in terms of bits, other encodings are imaginable as well. All that the encoder and
decoder need to agree upon is the order of the bits. Since there are 1000 cities, this requires
CAPITOLUL 10. IOI 2010 10.8. SAVEIT 1032
no more than 1000*1000=1 000 000 bits. Other approaches using more bits also work in
this subtask.
Subtask 2: You can send the entire table with all hop counts directly. Since there are no
more than 1000 cities, the maximum hop count is less than 1000, and thus can be encoded
in 10 bits. The size of the table is at most 1000*36=36 . Hence, not more than 360 000 bits
are needed.
Subtask 3: One needs a new idea to improve the communication efficiency further. The crux
is to come up with the idea of considering a spanning tree; any spanning tree will do. The
distance from v1 to v2 is one of
Then all one has to do is encode these possibilities with 2 bits each.
Subtask 4: Using two bits to record a one-of-three choice is excessive. It is possible to map 3
ternary decisions (27 choices) to 5 bits (32 possibilities). This improves the communication
further.
#include "grader.h"
#include "encoder.h"
#include "decoder.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include<iostream>
#include <vector>
#include <cmath>
#include <cassert>
#include <queue>
int decode_bit()
{
if (curbit >= nb)
{
exit(92);
CAPITOLUL 10. IOI 2010 10.8. SAVEIT 1033
}
return bits[curbit++];
}
int to = g[i][h];
if(dist[0][to] + 1 == dist[0][i])
{
far[i] = to;
push(to, 10);
break;
}
}
}
return;
}
ll extract(int bits)
{
ll result = 0;
for(int i = 0; i < bits; i++)
result += decode_bit() * (1LL << i);
return result;
}
FOR(i,ne)
assert(2 == scanf("%i%i", v1+i, v2+i));
decode(nv, c);
if (hcnt != c*nv)
{
exit(92);
}
printf("%s 1\n",nb<=16000000?"OK":"NO");
printf("%s 2\n",nb<=360000?"OK":"NO");
printf("%s 3\n",nb<=80000?"OK":"NO");
printf("%s 4\n",nb<=70000?"OK":"NO");
}
#include "grader.h"
#include "encoder.h"
#include "decoder.h"
#include<iostream>
#include <bits/stdc++.h>
bits[nb++] = bit;
}
int decode_bit()
{
if (curbit >= nb)
{
exit(92);
}
return bits[curbit++];
}
int dst[44][1010];
vector<int> g[1010];
int par[1010];
int vis[1010];
void dfs(int v = 1)
{
vis[v] = 1;
for(auto i : g[v]) if(!vis[i])
{
par[i] = v; dfs(i);
}
}
dfs();
{
int now = dst[i][j+k] - dst[i][par[j+k]] + 1;
if(j + k > n) now = 0;
t = t * 3 + now;
}
/*
dst[i][j] - dst[i][par[j]]
1 : 0
-1 : 11
0 : 10
*/
int p[1010];
int mm[44][1010];
int chk[1010];
int ans[44][1010];
FOR(i,ne)
assert(2 == scanf("%i%i", v1+i, v2+i));
decode(nv, c);
if (hcnt != c*nv)
{
exit(92);
}
printf("%s 1\n",nb<=16000000?"OK":"NO");
printf("%s 2\n",nb<=360000?"OK":"NO");
printf("%s 3\n",nb<=80000?"OK":"NO");
printf("%s 4\n",nb<=70000?"OK":"NO");
}
”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
1040
APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 1041
A.1.1 Code::Blocks
Pentru versiuni mai noi, de Code::Blocks şi compilatoare, se poate accesa site-ul
http://www.codeblocks.org/downloads/binaries
de unde se poate descărca, de exemplu, codeblocks-20.03mingw-setup.exe.
Versiuni mai vechi, dar foarte bune, se pot descărca de la adresa
43
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
44
g++.exe este compilatorul de C++, programul care va verifica dacă instrucţiunile noastre sunt ok sau nu ...
şi care ne va supăra mereu cu erorile pe care ni le arată ... ... Este “o mică artă” să ı̂nţelegem mesajele de
eroare pe care le vedem pe ecran şi să fim ı̂n stare să “depanăm” programele noastre!
APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 1042
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 A. ”INSTALARE” C++ A.1. KIT OJI 2017 1043
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 A.9: Pregătit pentru a scrie cod de program C++ ı̂n Code::Blocks
APPENDIX A. ”INSTALARE” C++ A.1. KIT OJI 2017 1045
Dacă avem fişierele p01.cpp, ..., p05.cpp, ı̂n folderul nostru de lucru, şi facem dublu-click pe
fiecare ... vor apărea toate ...
A.2 winlibs
A.2.1 GCC şi MinGW-w64 pentru Windows
Se descarcă de la
http://winlibs.com/#download-release
unul dintre fişierele:
winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r
3.7z dimensiune fişier = 148 MB
winlibs-x86_64-posix-seh-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r
3.zip dimensiune fişier = 324 MB
winlibs-x86_64-posix-seh-gcc-10.2.0-mingw-w64-8.0.0-r3.7z dimensiune
fişier = 52.1 MB
winlibs-x86_64-posix-seh-gcc-10.2.0-mingw-w64-8.0.0-r3.zip dimensi-
une fişier = 141 MB
A.2.2 PATH
Trebuie pusă ı̂n PATH calea pentru D:\mingw64\bin\. În “Type here to search” scrieţi: path
şi apoi click pe “Edit the system environment variables”, ca ı̂n figura următoare:
APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 1051
Se selecteaza “Path” şi click pe “Edit”. Apare fereastra “Edit Environment Variables”
C:¯path
Dacă totul este OK atunci se trece la instalarea IDE-ului preferat (Integrated Development
45
Environment ), de exemplu Code::Blocks 20.03 (sau Eclipse, Visual Studio Code, Dev C++,
NetBeans, şi altele).
A.2.3 CodeBlocks
CodeBlocks se poate descărca de la http://www.codeblocks.org/downloads/26. Sunt
mai multe variante dar eu am descărcat numai codeblocks-20.03-setup.exe care are 35.7 MB.
La instalare am lăsat totul implicit, deci ... Next, Next, ..., Next până la sfârşit!
La prima lansare ı̂n execuţie este necesară setarea locaţiei compilatorului de C++ (gcc-ul pe
care tocmai l-am instalat!).
45
https://en.wikipedia.org/wiki/Integrated_development_environment
https://ro.wikipedia.org/wiki/Mediu_de_dezvoltare
APPENDIX A. ”INSTALARE” C++ A.2. WINLIBS 1054
Exponenţiere rapidă
În figura B.1 este considerat numărul nr 234 care ı̂n baza 2 se scrie sub forma 11101010 (celula
C10).
Pe R3 (rândul 3) este arătat ce se ı̂ntâmplă cu nr atunci când se fac ı̂mpărţiri succesive prin
baza 10: se ”şterge” ulima cifră (care este egală cu nr%10 adică ultima cifră este de fapt restul
ı̂mpărţirii lui nr la baza 10).
Pe R10 (rândul 10) este arătat ce se ı̂ntâmplă cu nr atunci când se fac ı̂mpărţiri succesive prin
baza 2: se ”şterge” ulima cifră (care este egală cu nr%2 adică ultima cifră este de fapt restul
ı̂mpărţirii lui nr la baza 2, la fel cum se ı̂ntâmplă ı̂n baza 10).
Observaţia 1. Cifrele se obţin ı̂n ordine inversă. Prima cifră obţinută ca rest este de fapt ultima
cifră din număr (vezi R4 şi R11).
Pe R6 şi R16 sunt precizate puterile bazei.
Valoarea numărului nr este suma produselor dintre cifre şi puterile corespunzătoare:
ı̂n baza 10: 4*1 + 3*10 + 2*100 = 234 (R3 şi R6)
ı̂n baza 2: 0*1 + 1*2 + 0*4 + 1*8 + 0*16 + 1*32 + 1*64 + 1*128 = 234 (R13 şi R16)
1063
APPENDIX B. EXPONENŢIERE RAPIDĂ B.2. NOTAŢII, RELAŢII ŞI FORMULE 1064
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;
(B.2.1)
nk nk1 ©2 k ' 1; nk1 j 0 desigur ! ... dar şi nk1 j 1
ak1 , k ' 1;
2
ak
ek nk %2 " r0, 1x, k ' 0;
pk1 ak , k ' 0, dacă ek 1; ak ak modifică produsul pk1
1
p w
k k ' 0, dacă ek 0; ak 1 nu modifică produsul pk1
0
pk1 ,
B.4 Codul
Codul pentru relaţiile (B.2.1) devine:
Observaţia 2. În acest cod actualizarea lui p se face după actualizările pentru a şi n.
Observaţia 3. În codul următor actualizarea lui p se face ı̂naintea actualizărilor pentru a şi n,
corespunzător relaţiilor (B.4.2).
APPENDIX B. EXPONENŢIERE RAPIDĂ B.4. CODUL 1066
~
iniţializări:
p1 1;
n1 n;
a1 a;
calcul pentru k ' 0:
e
k nk1 %2 " r0, 1x; k ' 0 (B.4.2)
pk1 ak1 , k ' 0, dacă ek 1; ak1
1
ak1 modifică produsul pk1
k w
p
k ' 0, dacă ek 0; ak1
0
pk1 , 1 nu modifică produsul pk1
actualizări k ' 0:
a ak1 , k ' 0;
2
k
nk nk1 ©2 k ' 0; şi nk1 j 0 desigur !
APPENDIX B. EXPONENŢIERE RAPIDĂ B.4. CODUL 1067
Observaţia 4. Instrucţiunile care sunt ”ı̂n plus” se pot elimina. Codul următor arată acest lucru:
Observaţia 5. Produsul poate deveni foarte mare şi din cauza asta se cere rezultatul modulo un
număr prim. Codul următor arată acest lucru:
14 a = (a * a)%MOD;
15 n = n / 2;
16 nropr=nropr+6; // n%2, p*a, a*a, (a * a)%MOD si n/2
17 }
18 return p;
19 }
20
21 int main()
22 {
23 int a=1234;
24 int n=1e+9; // 10ˆ9
25 int rezn; // rezultat exponentiere naiva
26
27 rezn=exponentiere_rapida(a,n);
28
29 cout<<"rezr = "<<rezn<<" nropr = "<<nropr<<"\n";
30
31 return 0;
32 }
33 /*
34 rezr = 376 nropr = 180
35
36 Process returned 0 (0x0) execution time : 0.021 s
37 Press any key to continue.
38 */
Numărul de operaţii:
cu metoda naivă acest număr este 2 000 000 000
cu metoda rapidă este 180.
Iar ca număr de operaţii ... una este să faci 2 miliarde de operaţii şi alta este să faci
numai 180 de operaţii de acelaşi tip (de fapt sunt numai 30 de paşi dar la fiecare pas se fac 5
sau 6 operaţii aritmetice)!
46
şi nu mai trebuie ”atâtea formule matematice”!
46
Este o glumă!
Index
1071
INDEX INDEX 1072
[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.
1074
BIBLIOGRAFIE BIBLIOGRAFIE 1075
[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
1077
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!